日志系统基础:ROS2日志系统架构、日志级别、输出格式与存储位置

各位同学好,我是老张。今天咱们聊聊ROS2的日志系统。说实话,我刚开始接触Autoware那会儿,最头疼的就是出了问题不知道从哪查起。后来慢慢摸透了日志系统,才发现——嗯,这东西其实就是你的“行车记录仪”,把车跑过的每一步都记下来了。

日志系统,说白了就是ROS2框架里内置的一套消息记录机制。它不像你写代码时自己加的print,而是有级别、有格式、有存储的一套完整体系。我个人习惯,一上车先看日志,比看什么可视化工具都管用。

ROS2日志系统架构

ROS2的日志系统,底层用的是spdlog这个高性能C++日志库。上层呢,ROS2封装了一套rclcpp/rclpy的接口,让你在节点里直接调用。整个架构分三层:

  • 日志前端:就是你代码里写的 RCLCPP_INFO 或者 rclpy.logging.get_logger().info()。这部分负责接收你的日志消息。
  • 日志核心:rcl层,负责日志级别过滤、格式化、分发。这里决定了你的日志能不能被输出。
  • 日志后端:默认输出到控制台,也可以配置输出到文件、网络等。Autoware里我们通常同时输出到控制台和文件。

我在项目中遇到过一个问题:明明代码里写了日志,但控制台就是看不到。后来发现是日志级别没配对,核心层直接给过滤掉了。你想想看,排查了半天,结果是自己把日志关掉了,多冤。

核心要点:ROS2日志系统是分层架构,前端只管发,核心管过滤,后端管输出。理解这个,你才知道日志“消失”了该查哪一层。

日志前端(rclcpp/rclpy 接口) RCLCPP_INFO / get_logger().info() 日志核心(rcl 层) 级别过滤 → 格式化 → 分发 日志后端(spdlog) 控制台输出 / 文件存储 / 远程日志

日志级别:从DEBUG到FATAL

ROS2定义了5个日志级别,从低到高分别是:

级别 数值 含义 典型场景
DEBUG 10 调试信息 变量值、循环次数、临时中间结果
INFO 20 普通信息 节点启动、参数加载、正常状态切换
WARN 30 警告 参数异常、降级运行、非致命错误
ERROR 40 错误 传感器断连、算法失败、超时
FATAL 50 致命错误 内存耗尽、核心组件崩溃、系统不可恢复

这里有个关键点:日志级别是“向上包含”的。什么意思?如果你把日志级别设为WARN,那WARN、ERROR、FATAL都会输出,但DEBUG和INFO就被过滤掉了。我建议你在开发阶段用DEBUG,跑仿真用INFO,真车上路用WARN。为什么呢?因为真车上日志太多会影响实时性,你想想看,每毫秒刷几百条日志,CPU都去干这个了,还怎么算路径规划?

我的小技巧:在Autoware的launch文件里,我习惯加一个参数 log_level:=debug,调试完再改回 warn。这样不用改代码,启动时指定就行。

日志输出格式解析

ROS2默认的日志输出格式长这样:

[INFO] [1712345678.123456789] [my_node]: Hello, this is an info message

拆开来看,一共四个部分:

  • [INFO]:日志级别,告诉你这条消息有多严重。
  • [1712345678.123456789]:时间戳,单位是秒,精确到纳秒。这个在排查时序问题时特别有用。我记得有一次定位模块和规划模块时间对不上,就是靠这个时间戳发现差了0.5秒。
  • [my_node]:节点名称,告诉你这条日志是哪个节点发的。Autoware里节点很多,没有这个你根本不知道是谁在说话。
  • Hello, this is an info message:消息正文,就是你想说的内容。

你也可以自定义格式。比如我个人喜欢加上文件名和行号:

export RCUTILS_CONSOLE_OUTPUT_FORMAT="[{severity}] [{time}] [{name}]: {function_name}() at {file_name}:{line_number} - {message}"

这样输出就变成了:

[INFO] [1712345678.123456789] [my_node]: main() at /home/user/my_node.cpp:42 - Hello, this is an info message

嗯,这个在追代码的时候特别爽,看到日志就知道是哪一行出的问题,不用再去grep了。

注意:自定义格式会增加日志输出的开销。在性能敏感的场景下,建议保持默认格式,或者只在DEBUG级别下启用详细格式。

日志文件存储位置

ROS2默认只把日志输出到控制台,不写文件。但Autoware里我们肯定要落盘,不然重启后日志就没了,你拿什么复盘?

ROS2提供了日志文件存储机制,默认路径是:

~/.ros/log/

里面会按启动时间生成文件夹,比如:

~/.ros/log/2025-01-15-14-30-22-123456/
  ├── my_node-1.log
  ├── another_node-2.log
  └── ...

每个节点一个日志文件。文件名格式是 节点名-进程ID.log。

你也可以自己指定路径,通过环境变量:

export ROS_LOG_DIR=/data/autoware_logs

我在项目中遇到过一个问题:跑了一整天,日志文件把磁盘塞满了,导致系统卡死。后来我加了个日志轮转策略,每天只保留最近7天的日志。具体做法是在启动脚本里加一句:

export RCUTILS_LOG_FILE_MAX_SIZE=10485760  # 单个文件最大10MB
export RCUTILS_LOG_FILE_ROTATION=5          # 最多保留5个轮转文件

这样每个节点的日志最多占50MB,整个系统跑一天也就几百MB,完全可控。

避坑指南:我曾经因为没配日志轮转,在实车测试时磁盘写满,导致规划模块异常退出。从那以后,我每次部署前都会检查日志存储配置。你也不希望因为日志把车搞停了吧?

好了,日志系统的基础就这些。记住一句话:日志是你的第一道防线,出了问题先看日志,别急着改代码。下一节咱们聊聊怎么用这些日志去排查Autoware里的常见故障。

可可精品资料库