
面试翻车现场面试一家做服务机器人的公司面试官问你们系统的日志是怎么管理的出了问题怎么排查我说用RCLCPP_INFO打印然后看终端输出。他笑了笑只做开发确实够用。但你有没有想过产品上线以后日志怎么收集怎么分级怎么在不重启系统的情况下动态调整日志级别这几个问题把我问住了。日志系统看起来是最不起眼的东西但在实际工程中它直接决定了你能不能快速定位线上问题。rcl_logging的架构ROS2的日志系统底层叫rcl_logging它是一套抽象接口具体实现可以对接不同的后端。默认情况下ROS2使用内置的日志后端输出到终端。但你也可以配置成输出到文件、对接spdlog甚至对接系统的journald。这个设计的好处是解耦。你的业务代码只调用RCLCPP_INFO、RCLCPP_WARN这些宏底层到底输出到哪里、怎么格式化都可以通过配置来改。换日志方案不需要改业务代码。ROS2 Humble开始默认的日志后端从rcutils内置实现切换到了spdlog。spdlog是一个C日志库性能很好支持异步写入、多线程安全、多种输出格式。如果你的ROS2版本比较新其实底层已经在用spdlog了只是通过rcl_logging的接口封装了一层。切换日志后端需要在编译时指定。比如想用spdlog编译ros2时要设置-DROS_LOG_BACKENDspdlog。不同后端的性能差异还是挺明显的——内置后端在高频日志场景下可能会成为瓶颈spdlog的异步模式能好很多。日志后端可以通过环境变量ROS_LOG_DIR来指定日志文件的存放目录。如果不设置默认在~/.ros/log/下面。每次启动会生成一个带时间戳的子目录方便区分不同运行周期的日志。日志级别和使用ROS2定义了六个日志级别从低到高UNSET0、DEBUG10、INFO20、WARN30、ERROR40、FATAL50。默认级别是INFO也就是说DEBUG级别的日志不会输出。在代码中设置日志级别rclcpp::get_logger(my_node)-set_level(rclcpp::Logger::Level::Debug)。也可以通过命令行动态修改ros2 service call /your_node/set_logger_level rcl_interfaces/srv/SetLoggerLevel {logger_name: your_node, level: 10}。注意每个Node、甚至每个Logger都可以独立设置级别。一个Node内部可以创建多个Loggerauto logger rclcpp::get_logger(my_subsystem)。这样你可以对不同的子系统设置不同的日志级别。比如调试感知模块的时候把感知的Logger设成DEBUG其他模块保持INFO避免日志刷屏。日志格式和条件输出默认的日志格式包含时间戳、日志级别、节点名称和消息内容。你可以通过环境变量RCUTILS_CONSOLE_OUTPUT_FORMAT来自定义格式。比如设成[{severity}] [{name}]: {message}更简洁。还可以加上{function_name}显示函数名{file_name}显示源文件名方便定位代码位置。调试的时候加上这些信息能省不少事。条件日志在实际开发中非常有用。RCLCPP_INFO_THROTTLE(logger, Processing frame %d, frame_id)每隔一段时间才输出一次避免高频回调里日志刷屏。类似的还有RCLCPP_WARN_EXPRESSION只在条件满足时才输出。还有一个容易忽略的点日志输出本身是有性能开销的。如果你的回调频率是1kHz每次都打日志光日志输出就能吃掉不少CPU。所以高频回调里要么用THROTTLE要么干脆不打日志。日志分析实践日志收集上来以后怎么用这里有几个层次。最基础的是grep关键词。比如搜ERROR找错误搜节点名找特定节点的输出。这在日志量不大的时候够用。进一步可以用ROS2的ros2 topic echo /rosout来实时查看所有节点的日志输出。/rosout是一个特殊的topic所有Node的日志都会发布到这里。你可以写一个订阅者把日志转发到文件或者远程服务器。再高级一点可以对接ELKElasticsearch Logstash Kibana或者Grafana Loki这类日志分析平台。把日志结构化输出为JSON格式方便检索和可视化。在生产环境中这种方案比grep高效得多。实际项目中我建议在关键状态变化时打日志——比如模式切换、连接建立/断开、异常捕获。这些日志在排查问题时最有价值。普通的循环处理不需要每帧都打用THROTTLE降频就好。分享一个实际排查经验。有次机器人运行一段时间后导航会卡住查日志发现是某个TF变换偶尔超时。通过日志时间戳分析发现超时发生在点云处理回调里因为点云处理耗时太长导致TF查询时已经过了目标时间戳。解决方案是把点云处理改成异步TF查询用最新的可用变换。这种问题光看代码很难发现必须靠日志。再分享一个日志格式化的实战经验。我们项目里规定所有关键状态变化必须用统一的格式输出[模块名][状态变化] 旧状态 - 新状态, 原因: xxx。比如[导航][状态变化] PLANNING - EXECUTING, 原因: 路径规划完成。这样做的好处是可以用正则表达式快速提取所有状态变化事件生成时间线。有一次系统出了bug我用这个格式化的日志在10分钟内就还原了整个事件链——从模式切换到传感器异常到最终故障一目了然。如果日志格式乱七八糟这种排查可能要花几个小时。日志文件管理日志写到文件以后还有一个现实问题文件会越来越大。机器人系统7x24小时运行一天下来日志文件可能就好几个GB。磁盘写满了系统就崩了。解决办法是日志轮转log rotation。Linux下可以用logrotate工具配置定时切割和清理旧日志。比如每天切割一次保留最近7天的日志超过7天的自动删除压缩。ros2本身也支持通过ROS_LOG_DIR和环境变量配合外部工具来做这件事。另一个思路是限制单个日志文件的大小。spdlog后端支持设置文件大小上限超过以后自动滚动到新文件旧文件可以自动压缩或删除。这样磁盘空间可控。还有一点要注意日志写入是磁盘IO操作。如果你用机械硬盘高频写入会影响其他IO操作。建议日志目录放在SSD上或者用内存文件系统tmpfs临时缓存定期刷盘。日志自动化分析手动翻日志效率很低。成熟的团队会建立日志自动化分析流程。首先是关键词告警。写一个脚本实时监控日志流当出现ERROR或FATAL级别的日志时自动发送告警到团队的即时通讯群。ROS2的/rosout话题可以直接订阅不需要解析文件。配合简单的Python脚本就能实现实时告警。其次是日志聚合和统计。每天自动统计各节点的ERROR和WARN数量生成日报。如果某个节点的ERROR数量突然从每天几个变成几百个说明有异常需要排查。这种趋势分析比事后翻日志高效得多。再进一步可以对接AI分析。把异常日志喂给大语言模型做根因分析自动给出可能的故障原因和排查建议。虽然目前这种方案还不够成熟但方向是值得关注的。面试中怎么聊面试官问日志系统你可以说ROS2的日志系统基于rcl_logging支持多后端对接。日志分六个级别可以通过代码或服务调用动态调整。每个Logger可以独立设级别方便定向调试。高频回调要用THROTTLE避免性能问题。生产环境中建议结构化输出对接日志平台关键状态变化必须记录。日志系统虽然不性感但能体现一个人的工程素养。面试官问这个问题其实是在看你是不是做过真正的产品。能把日志级别管理、动态调整、文件轮转、结构化输出这些点都讲清楚的候选人说明你考虑过产品上线后的运维问题这在面试中是加分项。上一篇第140篇 ROS2性能优化——通信延迟、内存占用和CPU优化下一篇预告第142篇 ROS2安全机制——SROS2和通信加密