ROS 程序编写之日志

ROS 提供了一套日志系统用于输出日志信息。

严重级别

日志消息分为五个不同的严重级别:

划分各种重要级别旨在提供一种区分和管理日志消息的全局方法,这些级别本身对系统不包含任何额外的影响。

打印日志

打印普通日志:

#include <ros/ros.h>

int main(int argc, char** argv){
    ros::init(argc, argv, "count_and_log");
    ros::NodeHandle nh;

    ros::Rate rate(10);
    for(int i = 0; ros::ok();i++){
        ROS_DEBUG_STREAM("Counted to " << i);//打印debug日志,默认日志运行级别为INFO,不会生成日志
        if( 0 == (i%3) ){
            ROS_INFO_STREAM(i << " is divisible by 3");//打印info日志
        }
        if( 0 == (i%5) ){
            ROS_WARN_STREAM(i << " is divisible by 5");//打印warn日志
        }
        if( 0 == (i%10) ){
            ROS_ERROR_STREAM(i << " is divisible by 10");//打印error日志
        }
        if( 0 == (i%20) ){
            ROS_FATAL_STREAM(i << " is divisible by 20");//打印fatal日志
        }

        rate.sleep();
    }
}

日志输出:

[ INFO] [1458218253.291133699]: 0 is divisible by 3
[ WARN] [1458218253.291355117]: 0 is divisible by 5
[ERROR] [1458218253.291454136]: 0 is divisible by 10
[FATAL] [1458218253.291551318]: 0 is divisible by 20
...

生成一次性日志,即只有第一次调用时打印日志:

#include <ros/ros.h>

int main(int argc, char** argv){
    ros::init(argc, argv, "count_and_log");
    ros::NodeHandle nh;

    while(ros::ok()){
        //日志打印宏以_ONCE结尾,表示只调用一次
        ROS_DEBUG_STREAM_ONCE("This appears only once.");
        ROS_INFO_STREAM_ONCE("This appears only once.");
        ROS_WARN_STREAM_ONCE("This appears only once.");
        ROS_ERROR_STREAM_ONCE("This appears only once.");
        ROS_FATAL_STREAM_ONCE("This appears only once.");
    }
}

日志输出:

[ INFO] [1458218569.154094082]: This appears only once.
[ WARN] [1458218569.154374214]: This appears only once.
[ERROR] [1458218569.154528681]: This appears only once.
[FATAL] [1458218569.154683830]: This appears only once.

固定频率输出日志,

#include <ros/ros.h>

int main(int argc, char** argv){
    ros::init(argc, argv, "count_and_log");
    ros::NodeHandle nh;

    while(ros::ok()){
        //日志打印宏以_THROTTLE结尾,表示按指定频率打印日志
        //第一个参数为double类型,表示隔指定时间打印一次日志,单位为秒
        ROS_DEBUG_STREAM_THROTTLE(0.1, "This appears every 0.1 seconds.");
        ROS_INFO_STREAM_THROTTLE(0.3, "This appears every 0.3 seconds.");
        ROS_WARN_STREAM_THROTTLE(0.5, "This appears every 0.5 seconds.");
        ROS_ERROR_STREAM_THROTTLE(1.0, "This appears every 1.0 seconds.");
        ROS_FATAL_STREAM_THROTTLE(2.0, "This appears every 2.0 seconds.");
    }
}

日志输出:

[ INFO] [1458218781.674232147]: This appears every 0.3 seconds.
[ WARN] [1458218781.674430793]: This appears every 0.5 seconds.
[ERROR] [1458218781.674529999]: This appears every 1.0 seconds.
[FATAL] [1458218781.674652158]: This appears every 2.0 seconds.
[ INFO] [1458218781.974213324]: This appears every 0.3 seconds.
[ WARN] [1458218782.174472579]: This appears every 0.5 seconds.
[ INFO] [1458218782.274219901]: This appears every 0.3 seconds.
[ INFO] [1458218782.574214940]: This appears every 0.3 seconds.
[ WARN] [1458218782.674468422]: This appears every 0.5 seconds.
[ERROR] [1458218782.674929831]: This appears every 1.0 seconds.
[ INFO] [1458218782.874219638]: This appears every 0.3 seconds.
[ INFO] [1458218783.174216314]: This appears every 0.3 seconds.
[ WARN] [1458218783.174689945]: This appears every 0.5 seconds.
[ INFO] [1458218783.474240344]: This appears every 0.3 seconds.
[FATAL] [1458218783.674690042]: This appears every 2.0 seconds.

查看日志

日志消息有三个不同的目的地:控制台,话题/rosout,日志文件

控制台

输出到控制台的日志,DEBUGINFO消息被打印至标准输出,而WARNERRORFATAL打印至标准错误输出

可以折折环境变量ROSCONSOLE_FORMAT调整打印格式,有如下域:

例子:

$ export ROSCONSOLE_FORMAT='[${node}]:[${severity}]:[${time}]:[${file}]:[${function}]:[${line}]:[${message}]'
$ rosrun agitr logtest 
[/count_and_log]:[ INFO]:[1458219369.406914988]:[/home/chenjunjun/ros/src/agitr/logtest.cpp]:[main]:[9]:[This appears every 0.3 seconds.]
...

rosout 上的消息

相比于控制台输出,/rosout话题输出的主要作用是它在一个流中包含了系统中所有节点的日志消息。

可以通过如下命令查看话题/rosout中的消息:

$ rostopic echo /rosout

也可以使用图形界面查看:

$ rqt_console

rqt_console订阅的是话题/rosout_agg/rosout_agg话题由节点rosout收集话题/rosout聚合之后发布

日志文件

ros日志存储在~/.ros/log/run_id/rosout.log中,run_id在节点管理器启动时生成,用于区别不同的回话,可以通过如下命令获取:

$ rosparam get /run_id
e3259970-e9df-11e5-8992-000c2935e588

可以使用如下命令查看日志文件占用磁盘:

$ rosclean check
31M ROS node logs

使用如下命令清除日志文件:

$ rosclean purge 
Purging ROS node logs.
PLEASE BE CAREFUL TO VERIFY THE COMMAND BELOW!
Okay to execute:

rm -rf /home/chenjunjun/.ros/log
(y/n)?
y

设置日志级别

默认的日志级别为INFO,所设置级别以下的日志不会被打印出来,所以上面的代码都没有答应出debug的日志。

日志级别可以修改。

通过命令行设置日志级别

$ rosservice call /count_and_log/set_logger_level ros.agitr DEBUG

日志记录:

...
[/count_and_log]:[ INFO]:[1458220670.200462414]:[/home/chenjunjun/ros/src/agitr/logtest.cpp]:[main]:[9]:[This appears every 0.3 seconds.]
[/count_and_log]:[DEBUG]:[1458220670.276369980]:[/home/chenjunjun/ros/src/agitr/logtest.cpp]:[main]:[8]:[This appears every 0.1 seconds.]
...

可以看到debug日志

通过图形界面设置

$ rqt_logger_level

在代码中设置

#include <ros/ros.h>

//引入日志库的头文件
#include <log4cxx/logger.h>

int main(int argc, char** argv){
    ros::init(argc, argv, "count_and_log");

    //设置日志的运行级别
    log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->setLevel(ros::console::g_level_lookup[ros::console::levels::Debug]);
    //刷新一下,如果在修改日志运行级别之前没有生成日志也可以不调用,例如此处可以不调用
    ros::console::notifyLoggerLevelsChanged();

    ros::NodeHandle nh;

    while(ros::ok()){
        ROS_DEBUG_STREAM_THROTTLE(0.1, "This appears every 0.1 seconds.");
        ROS_INFO_STREAM_THROTTLE(0.3, "This appears every 0.3 seconds.");
        ROS_WARN_STREAM_THROTTLE(0.5, "This appears every 0.5 seconds.");
        ROS_ERROR_STREAM_THROTTLE(1.0, "This appears every 1.0 seconds.");
        ROS_FATAL_STREAM_THROTTLE(2.0, "This appears every 2.0 seconds.");
    }
}

参考

Comments