日志记录

有关可用功能的详细信息,请参阅“日志记录页面 <../../Concepts/Intermediate/About-Logging>”。

在代码中使用日志语句

基本日志记录

以下代码将在“DEBUG”严重性下从 ROS 2 节点输出日志消息:

// printf style
RCLCPP_DEBUG(node->get_logger(), "My log message %d", 4);

// C++ stream style
RCLCPP_DEBUG_STREAM(node->get_logger(), "My log message " << 4);

请注意,在这两种情况下,都不会添加尾随换行符,因为日志记录基础结构会自动添加一个。

仅在第一次记录

以下代码将在严重性为“INFO”的 ROS 2 节点输出日志消息,但仅在第一次命中时输出:

// printf style
RCLCPP_INFO_ONCE(node->get_logger(), "My log message %d", 4);

// C++ stream style
RCLCPP_INFO_STREAM_ONCE(node->get_logger(), "My log message " << 4);

除第一次之外的所有时间都记录

以下代码将在严重程度为“WARN”时从 ROS 2 节点输出日志消息,但不会输出第一次遇到的日志消息:

// printf style
RCLCPP_WARN_SKIPFIRST(node->get_logger(), "My log message %d", 4);

// C++ stream style
RCLCPP_WARN_STREAM_SKIPFIRST(node->get_logger(), "My log message " << 4);

日志记录已限制

以下代码将从 ROS 2 节点以“ERROR”严重性输出一条日志消息,但每秒不超过一次。

指定消息间隔毫秒数的间隔参数应具有整数数据类型,以便可以将其转换为“rcutils_duration_value_t”(“int64_t”):

// printf style
RCLCPP_ERROR_THROTTLE(node->get_logger(), *node->get_clock(), 1000, "My log message %d", 4);

// C++ stream style
RCLCPP_ERROR_STREAM_THROTTLE(node->get_logger(), *node->get_clock(), 1000, "My log message " << 4);

// For now, use the nanoseconds() method to use an existing rclcpp::Duration value, see https://github.com/ros2/rclcpp/issues/1929
RCLCPP_ERROR_STREAM_THROTTLE(node->get_logger(), *node->get_clock(), msg_interval.nanoseconds()/1000000, "My log message " << 4);

除第一次之外,日志记录均受到限制

以下代码将从 ROS 2 节点以“DEBUG”严重性输出一条日志消息,每秒不超过一次,并跳过第一次命中的情况:

// printf style
RCLCPP_DEBUG_SKIPFIRST_THROTTLE(node->get_logger(), *node->get_clock(), 1000, "My log message %d", 4);

RCLCPP_DEBUG_SKIPFIRST_THROTTLE(node->get_logger(), *node->get_clock(), 1000, "My log message " << 4);

日志记录演示

在此`演示<https://github.com/ros2/demos/tree/rolling/logging_demo>`_中,显示了不同类型的日志调用,并在本地和外部配置了不同记录器的严重性级别。

使用以下命令启动演示:

ros2 run logging_demo logging_demo_main

随着时间的推移,您将看到具有不同属性的各种日志调用的输出。 首先,您将只看到严重性为“INFO”及以上的日志调用的输出(“WARN”、“ERROR”、“FATAL”)。 请注意,第一条消息只会记录一次,尽管每次迭代都会到达该行,因为这是用于该消息的日志调用的属性。

日志目录配置

可以通过两个环境变量配置日志目录:“ROS_LOG_DIR”和“ROS_HOME”。 逻辑如下:

  • 如果“ROS_LOG_DIR”已设置且不为空,则使用“$ROS_LOG_DIR”。

  • 否则,使用“$ROS_HOME/log”,如果未设置或为空,则使用“~/.ros”作为“ROS_HOME”。

例如,将日志目录设置为“~/my_logs”:

export ROS_LOG_DIR=~/my_logs
ros2 run logging_demo logging_demo_main

然后,您将在 ~/my_logs/ 下找到日志。

或者,您可以设置 ROS_HOME,日志目录将与其相关 ($ROS_HOME/log)。 ROS_HOME 旨在供任何需要基本目录的内容使用。 请注意,ROS_LOG_DIR 必须未设置或为空。 例如,将 ROS_HOME 设置为 ~/my_ros_home

export ROS_HOME=~/my_ros_home
ros2 run logging_demo logging_demo_main

然后,您将在 ~/my_ros_home/log/ 下找到日志。

记录器级别配置:以编程方式

经过 10 次迭代后,记录器的级别将设置为 DEBUG,这将导致记录其他消息。

其中一些调试消息会导致评估其他函数/表达式,这些函数/表达式之前被跳过,因为未启用 DEBUG 日志调用。

有关使用的调用的进一步说明,请参阅演示的 源代码,并参阅 rclcpp 日志记录文档以获取受支持的日志记录调用的完整列表。

记录器级别配置:外部​​

ROS 2 节点具有可用于在运行时从外部配置日志记录级别的服务。

默认情况下,这些服务是禁用的。 以下代码显示如何在创建节点时启用记录器服务。

// Create a node with logger service enabled
auto node = std::make_shared<rclcpp::Node>("NodeWithLoggerService", rclcpp::NodeOptions().enable_logger_service(true))

如果你按照上面的配置运行其中一个节点,运行“ros2 服务列表”时你会发现 2 个服务:

$ ros2 service list
...
/NodeWithLoggerService/get_logger_levels
/NodeWithLoggerService/set_logger_levels
...
  • get_logger_levels

使用此服务获取指定记录器名称的记录器级别。

运行“ros2 service call”以获取“NodeWithLoggerService”和“rcl”的记录器级别。

$ ros2 service call /NodeWithLoggerService/get_logger_levels rcl_interfaces/srv/GetLoggerLevels '{names: ["NodeWithLoggerService", "rcl"]}'

请求者:发出请求:rcl_interfaces.srv.GetLoggerLevels_Request(names=['NodeWithLoggerService', 'rcl'])

响应: rcl_interfaces.srv.GetLoggerLevels_Response(levels=[rcl_interfaces.msg.LoggerLevel(name=’NodeWithLoggerService’, level=0), rcl_interfaces.msg.LoggerLevel(name=’rcl’, level=0)])

  • set_logger_levels

使用此服务为指定的记录器名称设置记录器级别。

运行“ros2 service call”为“NodeWithLoggerService”和“rcl”设置记录器级别。
$ ros2 service call /NodeWithLoggerService/set_logger_levels rcl_interfaces/srv/SetLoggerLevels '{levels: [{name: "NodeWithLoggerService", level: 20}, {name: "rcl", level: 10}]}'

请求者:发出请求:rcl_interfaces.srv.SetLoggerLevels_Request(levels=[rcl_interfaces.msg.LoggerLevel(name='NodeWithLoggerService', level=20), rcl_interfaces.msg.LoggerLevel(name='rcl', level=10)])

响应: rcl_interfaces.srv.SetLoggerLevels_Response(results=[rcl_interfaces.msg.SetLoggerLevelsResult(successful=True, Reason=’’), rcl_interfaces.msg.SetLoggerLevelsResult(successful=True, Reason=’’)])

还有演示代码展示如何通过记录器服务设置或获取记录器级别。

  • rclcpp: demo code

    $ ros2 run demo_nodes_cpp use_logger_service
    
  • rclpy: demo code

    $ ros2 run demo_nodes_py use_logger_service
    

Warning

目前存在一个限制,即 get_logger_levelsset_logger_levels 服务不是线程安全的。 这意味着您需要确保一次只有一个线程在调用服务。 请参阅 https://github.com/ros2/rcutils/issues/397 中的详细信息

使用记录器配置组件

响应记录器配置请求的服务器已开发为组件,因此可以将其添加到现有的基于组合的系统中。 例如,如果您使用“容器运行节点 <../Intermediate/Composition>”,则为了能够配置记录器,您只需请求它另外将“logging_demo::LoggerConfig”组件加载到容器中。

例如,如果您想调试“composition::Talker”演示,您可以正常启动 talker:

Shell 1:

ros2 run rclcpp_components component_container

Shell 2:

ros2 component load /ComponentManager composition composition::Talker

然后,当您想要启用调试日志记录时,请使用以下命令加载“LoggerConfig”组件:

Shell 2

ros2 component load /ComponentManager logging_demo logging_demo::LoggerConfig

最后,通过寻址空名记录器将所有未设置的记录器配置为调试严重性。 请注意,已专门配置为使用特定严重性的记录器不会受到此调用的影响。

Shell 2:

ros2 service call /config_logger logging_demo/srv/ConfigLogger "{logger_name: '', level: DEBUG}"

您应该会看到进程中任何先前未设置的记录器的调试输出开始出现,包括来自 ROS 2 核心的记录器。

记录器级别配置:命令行

从 Bouncy ROS 2 版本开始,可以从命令行配置未明确设置严重性的记录器的严重性级别。 重新启动演示,包括以下命令行参数:

ros2 run logging_demo logging_demo_main --ros-args --log-level debug

这会将任何未设置的记录器的默认严重性配置为调试严重性级别。 您应该会看到来自演示本身和 ROS 2 核心的记录器的调试输出。

可以从命令行配置单个记录器的严重性级别。 重新启动演示,包括以下命令行参数:

ros2 run logging_demo logging_demo_main --ros-args --log-level logger_usage_demo:=debug

控制台输出格式

如果您想要更详细或更简洁的格式,可以使用“RCUTILS_CONSOLE_OUTPUT_FORMAT”环境变量。 例如,要额外获取日志调用的时间戳和位置,请停止演示并使用环境变量设置重新启动它:

export RCUTILS_CONSOLE_OUTPUT_FORMAT="[{severity} {time}] [{name}]: {message} ({function_name}() at {file_name}:{line_number})"
ros2 run logging_demo logging_demo_main

您应该会看到时间戳(以秒为单位)以及每条消息中额外打印的函数名称、文件名和行号。

有关配置控制台记录器格式的更多信息,请参阅:ref:logger 控制台配置

控制台输出着色

默认情况下,当输出针对终端时,输出会着色。 如果您想强制启用或禁用它,可以使用``RCUTILS_COLORIZED_OUTPUT``环境变量。 例如:

export RCUTILS_COLORIZED_OUTPUT=0  # 1 for forcing it
ros2 run logging_demo logging_demo_main

您应该看到调试、警告、错误和严重日志现在没有彩色。

Note

在 Linux 和 MacOS 中,强制彩色输出意味着如果您将输出重定向到文件,则 ansi 转义颜色代码将出现在该文件上。 在 Windows 中,着色方法依赖于控制台 API。 如果强制执行,您将收到一条新警告,提示着色失败。 默认行为已经检查输出是否为控制台,因此不建议强制着色。

控制台输出的默认流

在 Foxy 及更高版本中,所有调试级别的输出默认都会转到 stderr。可以通过将“RCUTILS_LOGGING_USE_STDOUT”环境变量设置为“1”来强制所有输出转到 stdout。 例如:

export RCUTILS_LOGGING_USE_STDOUT=1

行缓冲控制台输出

默认情况下,所有日志输出均未缓冲。 您可以通过将“RCUTILS_LOGGING_BUFFERED_STREAM”环境变量设置为 1 来强制缓冲。 例如:

export RCUTILS_LOGGING_BUFFERED_STREAM=1

然后运行:

ros2 run logging_demo logging_demo_main

设置日志文件名前缀

默认情况下,日志文件名基于可执行文件名,后跟文件创建时的进程 ID 和系统时间戳。 您可以使用“–log-file-name”命令行参数将日志文件名前缀更改为您选择的前缀:

ros2 run demo_nodes_cpp talker --ros-args --log-file-name filename

这会将日志文件名前缀配置为“filename”,而不是可执行文件名(在本例中为“talker”)。