2. 日志级别与分类:DEBUG、INFO、WARN、ERROR、FATAL

日志级别这东西,说白了就是给日志信息贴个标签。告诉看日志的人——这条消息有多严重,该不该立刻处理。

我刚开始做嵌入式那会儿,觉得日志嘛,能打印出来就行。结果有一次产品在现场出了问题,日志里全是乱七八糟的调试信息,真正有用的错误被淹没了。嗯,从那以后,我再也不敢乱用日志级别了。

2.1 为什么需要日志级别?

你想想看,一个嵌入式设备跑起来,每秒可能产生几十上百条日志。如果全打印出来,不光浪费存储空间,关键信息也找不着。

日志级别的作用就是——分级管理,按需输出

  • 开发阶段:打开所有级别,方便调试
  • 测试阶段:保留 INFO 及以上,过滤掉 DEBUG
  • 生产环境:只保留 WARN 及以上,减少日志量

我个人习惯是在代码里用一个宏来控制全局日志级别。这样切换环境时,改一行代码就行。

核心原则: 日志级别越低,信息越详细;级别越高,信息越紧急。

2.2 五个标准级别详解

嵌入式领域最常用的就是这五个级别。我按严重程度从低到高给你捋一遍。

DEBUG(调试)

这是最细粒度的日志。用来记录程序运行时的内部状态,比如变量值、函数调用顺序、循环次数等。

使用场景:

  • 开发阶段定位 bug
  • 验证某个分支逻辑是否被执行
  • 打印传感器原始数据

注意: 生产环境一定要关掉 DEBUG。我在一个项目中见过有人把 DEBUG 日志开到了线上,结果一天就写满了 128MB 的 Flash。

// 示例:DEBUG 日志
#define LOG_DEBUG(fmt, ...) \
    do { if (g_log_level <= LOG_LEVEL_DEBUG) \
        printf("[DEBUG] " fmt "\r\n", ##__VA_ARGS__); \
    } while(0)

// 使用
LOG_DEBUG("ADC 采样值: %d, 温度: %.2f°C", adc_val, temp);

INFO(信息)

INFO 用来记录系统正常运行的关键节点。比如设备启动、连接成功、任务切换等。

使用场景:

  • 系统初始化完成
  • 网络连接建立
  • 固件版本号打印
  • 定时任务执行周期

我个人习惯把 INFO 当作「健康检查」来用。看日志就能知道设备是不是在正常工作。

// 示例:INFO 日志
LOG_INFO("系统初始化完成,固件版本: v%s", FIRMWARE_VERSION);
LOG_INFO("WiFi 连接成功,IP 地址: %s", ip_str);

WARN(警告)

警告意味着——有问题,但系统还能继续跑。说白了就是「你最好看看,但不用立刻停机」。

使用场景:

  • 传感器读数超出正常范围但未到阈值
  • 重试操作(比如网络重连)
  • 资源使用率接近上限
  • 配置参数使用了默认值
我的经验: WARN 级别的日志一定要有「可恢复」的特征。如果某个警告持续出现,说明它应该升级为 ERROR。
// 示例:WARN 日志
LOG_WARN("电池电压偏低: %.2fV,建议充电", battery_voltage);
LOG_WARN("MQTT 重连第 %d 次", retry_count);

ERROR(错误)

错误意味着功能受损了。某个模块挂了,但系统整体还在运行。这时候需要人工介入排查。

使用场景:

  • 文件读写失败
  • 外设通信超时
  • 内存分配失败
  • 关键任务崩溃

我曾经在一个项目中,ERROR 日志里只打印了「Error occurred」,连错误码都没有。排查起来简直要命。所以 ERROR 日志一定要带上上下文信息。

// 示例:ERROR 日志
LOG_ERROR("SPI 通信超时,设备地址: 0x%02X, 错误码: %d", dev_addr, err_code);
LOG_ERROR("内存分配失败,请求大小: %d 字节", req_size);

FATAL(致命)

这是最高级别。系统已经无法继续运行了,必须重启或停机。

使用场景:

  • 看门狗超时
  • 硬件异常(HardFault)
  • 关键数据校验失败
  • 堆栈溢出
重要提醒: FATAL 日志一定要持久化存储。因为系统马上要挂了,不存下来就再也看不到了。我一般会在 FATAL 之前先写一次 Flash,再执行复位。
// 示例:FATAL 日志
LOG_FATAL("硬件异常,PC=0x%08X, LR=0x%08X", pc_val, lr_val);
// 保存日志到 Flash
save_fatal_log_to_flash();
// 系统复位
NVIC_SystemReset();

2.3 日志级别对照表

级别 数值 颜色(常用) 是否生产环境 典型行为
DEBUG 0 灰色/白色 关闭 打印内部状态
INFO 1 绿色 可选 记录关键节点
WARN 2 黄色 开启 提示潜在风险
ERROR 3 红色 开启 功能受损
FATAL 4 深红/闪烁 开启 系统崩溃

2.4 知识体系结构图

下面这张图展示了日志级别的核心逻辑。从 DEBUG 到 FATAL,信息量越来越少,但重要性越来越高。

日志级别金字塔结构 FATAL ERROR WARN INFO DEBUG 信息量多 重要性高

2.5 避坑指南

这些年我踩过不少日志级别的坑。挑几个典型的说说。

我曾经犯过的错:
  • 把所有日志都打成 ERROR——结果没人看 ERROR 了
  • DEBUG 日志里打印了敏感信息(密码、密钥)——上线前忘了关
  • FATAL 日志没存盘——系统重启后啥也没留下
  • 日志级别用字符串比较——性能开销大,在中断里用会出问题
我的建议:
  • 用整数枚举代替字符串比较,效率高
  • 生产环境默认只开 WARN 及以上
  • FATAL 日志一定要有持久化机制
  • 日志输出加时间戳,方便定位问题

嗯,日志级别这东西,看似简单,但用好了能省不少事。说白了就是——该细的时候细,该粗的时候粗。别让日志成为你的负担,而是成为你的帮手。


专注资料整理