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 日志
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 日志
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,信息量越来越少,但重要性越来越高。
2.5 避坑指南
这些年我踩过不少日志级别的坑。挑几个典型的说说。
- 把所有日志都打成 ERROR——结果没人看 ERROR 了
- DEBUG 日志里打印了敏感信息(密码、密钥)——上线前忘了关
- FATAL 日志没存盘——系统重启后啥也没留下
- 日志级别用字符串比较——性能开销大,在中断里用会出问题
- 用整数枚举代替字符串比较,效率高
- 生产环境默认只开 WARN 及以上
- FATAL 日志一定要有持久化机制
- 日志输出加时间戳,方便定位问题
嗯,日志级别这东西,看似简单,但用好了能省不少事。说白了就是——该细的时候细,该粗的时候粗。别让日志成为你的负担,而是成为你的帮手。