Zephyr日志使用指南-运行时日志过滤

Creative Commons
本作品采用知识共享署名

本文说明如何进行运行时日志消息过滤。

在Zephyr通过编译时过滤可以限制模块最小的过滤等级,但在最小等级之上的模块日志还是会输出。我们在调试时希望控制相关模块日志进行输出分析,不希望其它无关的日志都输出,这种情况下需要在运行时可以设置模块的日志过滤等级。需要注意的是运行时过滤的等级只能大于或者等于编译时指定的过滤等级。

代码控制过滤等级

运行时过滤提供了过滤日志更多的灵活性,让我们在代码里面可以根据触发条件对日志过滤等级进行修改,更方便调试。

控制运行时日志使用的接口都在头文件include/logging/log_ctrl.h中声明,设置过滤等级的函数为log_filter_set。示例代码logging_sample.clogging_filter_test函数演示了如何使用log_filter_set进行过滤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* 获取source id的函数需要自己实现 */
static int16_t log_source_id_get(const char *name)
{
/* 使用log_source_name_get取出每个source的名称做对比,确认source的id */
for (int16_t i = 0; i < log_src_cnt_get(CONFIG_LOG_DOMAIN_ID); i++) {
if (strcmp(log_source_name_get(CONFIG_LOG_DOMAIN_ID, i), name)
== 0) {
return i;
}
}

return -1;
}

static int logging_filter_test(const struct shell *shell, size_t argc, char **argv)
{
uint32_t level = strtol(argv[1], NULL, 0);
uint32_t act_level = 0;

shell_print(shell, "Set filter level %d", level);
act_level = log_filter_set(NULL, /* 第一个参数为backend,如果为NULL表示对所有的backend都进行设置 */
0, /* 第二个参数为domain_id,目前不支持多dimain,直接给0 */
log_source_id_get(STRINGIFY(logging_sample)), /* 第三个参数为source_id,代表的是要设置那个模块的等级,这里我们要设置logging_sample */
level); /* 第四个参数为level,表示要设置的过滤等级 */

/* 返回的act_level为实际生效的level */
shell_print(shell, "Set filter level %d act is %d", level, act_level);
return 0;
}

log_filter_setlevel参数可选如下,返回值为实际实际生效

1
2
3
4
5
#define LOG_LEVEL_NONE 0U
#define LOG_LEVEL_ERR 1U
#define LOG_LEVEL_WRN 2U
#define LOG_LEVEL_INF 3U
#define LOG_LEVEL_DBG 4U

log_filter_set的返回值为实际生效的等级,当level设置的等级低于编译时等级时,将按照编译时默认等级进行设置生效。

通过Shell命令控制日志系统

当启用zephyr shell命令时,可以通过shell的log命令进行日志过滤等级设置,后端设置,状态查看等。log支持的命令如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
uart:~$ log help
log - Commands for controlling logger
Subcommands:
backend :Logger backends commands.
disable :'log disable <module_0> .. <module_n>' disables logs in
specified modules (all if no modules specified).
enable :'log enable <level> <module_0> ... <module_n>' enables logs
up to given level in specified modules (all if no modules
specified).
go :Resume logging
halt :Halt logging
list_backends :Lists logger backends.
status :Logger status
mem :Logger memory usage

举例演示如下:

  • 将simple模块的日志过滤等级设置为INFO:

    log enable inf simple

  • 将simple模块的日志过滤等级设置为DEBUG:

    log enable dbg simple

  • 关闭simple模块的日志:

    log disable simple

  • 查看日志系统内存使用情况:

    log mem

  • 查看日志各模块的过滤状态:

    log status

    显示如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    uart:~$ log status
    module_name | current | built-in
    ----------------------------------------------------------
    esp_timer | inf | inf
    flash_esp32 | inf | dbg
    fs_nvs | inf | dbg
    gpio_esp32 | inf | inf
    i2c | inf | inf
    i2c_esp32 | inf | inf
    i2c_shell | inf | inf
    intc_esp32c3 | inf | inf
    log | inf | inf
    logging_sample | wrn | inf
    module_inst | inf | dbg
    module_inst.inst0 | inf | inf
    module_inst.inst1 | inf | inf
    module_inst.inst2 | inf | inf
    os | inf | inf
    shell.shell_uart | inf | inf
    shell_uart | inf | inf
    simple | inf | inf

这里current表示为当前设置的过滤等级,build-in为编译时设置的过滤等级。过滤等级上current不能低于build-in。

  • 中断所有后端日志输出:

    log halt

  • 恢复所有后端日志输出:

    log resume

参考

https://docs.zephyrproject.org/latest/services/logging/index.html