Zephyr 提供了一个强大且灵活的日志系统,支持多种后端、过滤级别和格式化选项。日志系统对于调试、性能分析和生产环境监控都至关重要。
应用程序
↓
日志 API (LOG_* 宏)
↓
日志核心 (处理、过滤)
↓
后端 (UART、RTT、文件等)
| 级别 | 宏 | 数值 | 用途 |
|---|---|---|---|
| none | - | 0 | 禁用日志 |
| error | LOG_ERR | 1 | 错误信息 |
| warning | LOG_WRN | 2 | 警告信息 |
| info | LOG_INF | 3 | 一般信息 |
| debug | LOG_DBG | 4 | 调试信息 |
每个源文件需要注册自己的日志模块:
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(my_module, LOG_LEVEL_INF);
void my_function(void) {
LOG_INF("This is an info message");
LOG_WRN("Warning: value = %d", value);
LOG_ERR("Error occurred!");
}
# 启用日志系统
CONFIG_LOG=y
# 默认日志级别
CONFIG_LOG_DEFAULT_LEVEL=3 # 0=none, 1=error, 2=warning, 3=info, 4=debug
# 启用运行时过滤
CONFIG_LOG_RUNTIME_FILTERING=y
# 日志缓冲区大小
CONFIG_LOG_BUFFER_SIZE=2048
# UART 后端
CONFIG_LOG_BACKEND_UART=y
CONFIG_LOG_BACKEND_UART_SERIAL_NAME="UART_0"
# RTT 后端 (Segger RTT)
CONFIG_LOG_BACKEND_RTT=y
CONFIG_USE_SEGGER_RTT=y
# Native POSIX 后端
CONFIG_LOG_BACKEND_NATIVE_POSIX=y
# 包含时间戳
CONFIG_LOG_TIMESTAMP_64BIT=y
# 自定义时间戳函数
CONFIG_LOG_CUSTOM_TIMESTAMP=y
# 颜色输出
CONFIG_LOG_BACKEND_SHOW_COLOR=y
# 线程信息
CONFIG_LOG_THREAD_ID_PREFIX=y
最常用的调试后端,通过串口输出日志:
// prj.conf
CONFIG_LOG=y
CONFIG_LOG_BACKEND_UART=y
CONFIG_LOG_DEFAULT_LEVEL=3
// 代码中
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
int main(void) {
LOG_INF("System started");
return 0;
}
Segger Real-Time Transfer,高速调试输出:
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_RTT_TX_BUFFER_SIZE=1024
需要 J-Link 调试器支持。
可以创建自定义后端输出到其他目标:
static int my_backend_init(const struct log_backend *backend)
{
// 初始化代码
return 0;
}
static void my_backend_process(const struct log_backend *backend,
union log_msg_generic *msg)
{
// 处理日志消息
log_output_msg_process(msg, &log_output);
}
LOG_BACKEND_DEFINE(my_backend, my_backend_api, true);
// 设置模块日志级别
LOG_MODULE_REGISTER(my_module, LOG_LEVEL_INF);
启用 CONFIG_LOG_RUNTIME_FILTERING=y 后:
// 设置模块日志级别
log_filter_set(NULL, 0, log_source_id_get(my_module), LOG_LEVEL_DBG);
// 获取当前级别
int level = log_filter_get(NULL, 0, log_source_id_get(my_module), true);
CONFIG_SHELL=y
CONFIG_SHELL_LOG_BACKEND=y
# 查看/设置日志级别
uart:~$ log level
uart:~$ log level dbg my_module
[<timestamp>] <level>: <module>: <message>
示例:
[00:00:01.234] <inf> main: System started
[00:00:01.567] <wrn> sensor: Temperature high: 85°C
LOG_HEXDUMP_INF(data, sizeof(data), "Received data:");
输出:
[00:00:01.000] <inf> main: Received data:
00000000: 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10
用于低功耗场景,日志先存入缓冲区,稍后处理:
CONFIG_LOG_MODE_DELAYED=y
CONFIG_LOG_BUFFER_SIZE=4096
减少日志存储空间:
CONFIG_LOG_COMPRESS=y
// 生产环境禁用调试日志
LOG_MODULE_REGISTER(my_module, LOG_LEVEL_ERR);
if (IS_ENABLED(CONFIG_DEBUG_FEATURE)) {
LOG_DBG("Debug info: %d", value);
}
// 使用速率限制
static int32_t log_counter;
void process_data(void) {
if (++log_counter % 100 == 0) {
LOG_INF("Processed %d packets", log_counter);
}
}
NCS 提供额外的日志功能:
CONFIG_NRF_MODEM_LIB_LOG=y
CONFIG_NRF_MODEM_LIB_LOG_LEVEL_INF=y
CONFIG_LTE_LINK_CONTROL_LOG_LEVEL_INF=y
CONFIG_AT_CMD_LIB_LOG_LEVEL_INF=y
CONFIG_BT_LOG=y
CONFIG_BT_LOG_LEVEL_INF=y
CONFIG_BT_HCI_CORE_LOG_LEVEL_INF=y
// 使用清晰、描述性的模块名
LOG_MODULE_REGISTER(ble_manager, LOG_LEVEL_INF);
LOG_MODULE_REGISTER(sensor_driver, LOG_LEVEL_DBG);
LOG_MODULE_REGISTER(power_management, LOG_LEVEL_INF);
// 好的做法
LOG_INF("Connection established: addr=%s, interval=%d ms",
addr_str, conn_interval);
// 避免
LOG_INF("Connected"); // 信息不足
int read_sensor_data(struct sensor_data *data)
{
int ret = sensor_sample_fetch(dev);
if (ret < 0) {
LOG_ERR("Failed to fetch sensor data: %d", ret);
return ret;
}
ret = sensor_channel_get(dev, SENSOR_CHAN_TEMP, &data->temp);
if (ret < 0) {
LOG_WRN("Temperature channel unavailable: %d", ret);
data->temp = 0;
}
LOG_DBG("Sensor data: temp=%d.%d°C",
data->temp.val1, data->temp.val2);
return 0;
}
| 特性 | LOG 宏 | printk |
|---|---|---|
| 过滤级别 | ✅ 支持 | ❌ 不支持 |
| 模块标识 | ✅ 自动 | ❌ 手动 |
| 时间戳 | ✅ 自动 | ❌ 手动 |
| 后端切换 | ✅ 灵活 | ❌ 固定 |
| 性能开销 | 可配置 | 固定 |
推荐: 在正式项目中使用 LOG 宏,开发调试时可以用 printk。
检查:
CONFIG_LOG=y 是否启用解决:
CONFIG_LOG_BUFFER_SIZECONFIG_LOG_TIMESTAMP_64BIT=y
确保系统时钟正确配置。
Zephyr 日志系统提供了强大且灵活的日志功能,关键要点:
LOG_MODULE_REGISTER 注册模块*学习日期: 2026-03-20* *小白 🤖*