日志系统基础:日志级别、格式与存储策略

日志这东西,说简单也简单,说复杂也复杂。我见过太多项目,日志打得满天飞,真到出问题的时候,翻半天找不到一句有用的。说白了,日志系统设计得好不好,直接决定了你排查问题的效率。

密钥烧录这种场景尤其敏感——烧录失败、密钥泄露、设备异常,哪一样都离不开日志。今天我们就从最基础的三个维度聊起:日志级别、日志格式、日志存储策略。

日志级别定义:从 DEBUG 到 FATAL

日志级别不是拍脑袋定的。每个级别都有明确的语义和使用场景。我习惯把它们分成两类:调试类(DEBUG、INFO)和告警类(WARN、ERROR、FATAL)。

级别 数值 含义 典型场景
DEBUG 0 调试信息 变量值、函数入口/出口、中间计算结果
INFO 1 普通信息 烧录开始/完成、设备连接/断开、配置加载
WARN 2 警告 参数异常、重试次数超限、时序偏差
ERROR 3 错误 烧录失败、通信超时、校验不通过
FATAL 4 致命错误 系统崩溃、密钥泄露、硬件损坏
我的习惯:生产环境只开 INFO 及以上级别。DEBUG 日志量太大,会拖慢烧录速度。但调试阶段必须全开,否则问题根本定位不了。

你可能会问:WARN 和 ERROR 到底怎么区分?我举个例子。烧录过程中,某一步重试了 3 次才成功——这是 WARN。重试了 10 次还是失败——这是 ERROR。前者说明系统在努力,后者说明系统已经扛不住了。

日志格式规范:让每一条日志都可追溯

日志格式这件事,我踩过不少坑。早期做项目时,日志格式五花八门,有的带时间戳有的不带,有的用逗号分隔有的用竖线。后来出过一次事故——烧录异常,日志里找不到设备 ID,排查了整整两天。从那以后,我强制团队统一格式。

一个标准的日志条目,至少包含以下字段:

  • 时间戳:精确到毫秒,格式 YYYY-MM-DD HH:mm:ss.SSS
  • 日志级别:用 5 位大写字母左对齐,如 [INFO ]、[ERROR]
  • 线程/任务名:多线程环境下必须带,否则不知道谁打的
  • 模块名:如 KeyBurner、CommManager
  • 消息体:描述性文字,尽量包含关键参数

我推荐这种格式:

[2025-03-21 14:32:17.456] [INFO ] [burner-thread-1] [KeyBurner] 烧录开始 | device_id=SN20250321001, key_type=ECC256
[2025-03-21 14:32:17.789] [WARN ] [burner-thread-1] [CommManager] 通信重试 | retry_count=2, max_retry=3
[2025-03-21 14:32:18.012] [ERROR] [burner-thread-1] [KeyBurner] 烧录失败 | error_code=0xE003, reason=校验和错误
关键原则:每条日志必须能回答三个问题——谁(模块)、什么时候(时间戳)、发生了什么(消息体+参数)。少一个,排查效率就降一截。

日志存储策略:写到哪里、写多少、写多久

日志存储看起来简单,其实坑很多。我见过有人把日志全写进 RAM,结果烧录到一半内存爆了。也有人把所有日志都存到同一个文件,几个月下来文件几十 GB,打开都费劲。

存储策略要回答三个问题:

1. 写到哪里?

嵌入式设备上,常见的选择有:

  • RAM 缓冲区:速度快,但掉电丢失。适合 DEBUG 级别,调试时用
  • Flash/EEPROM:持久化,但有写入寿命限制。适合 ERROR/FATAL 级别
  • SD 卡/外部存储:容量大,适合完整日志。但要注意文件系统可靠性
  • 串口/网络输出:实时查看,不占本地空间。适合开发阶段
注意:Flash 写入次数有限,千万别把 DEBUG 日志往 Flash 里写。我曾经见过一个产品,因为日志写太频繁,Flash 三个月就报废了。

2. 写多少?

日志量要控制。我一般遵循「三级过滤」策略:

  1. 级别过滤:生产环境只存 WARN 及以上
  2. 频率过滤:同一错误 1 秒内最多记录 1 次,防止日志风暴
  3. 内容过滤:敏感信息(如密钥明文)绝对不能写日志

3. 写多久?

存储空间有限,日志必须轮转。我常用的方案是「环形缓冲区 + 文件轮转」:

  • RAM 中维护一个环形缓冲区,存最近 1000 条日志
  • Flash 中存最近 10 个日志文件,每个文件 1MB
  • 超过 10 个文件,自动覆盖最旧的

这样既保证了近期日志可查,又不会撑爆存储。

知识体系总览

下面这张图,把日志系统的三个核心维度串起来了。你可以把它当作设计日志模块时的检查清单。

日志系统核心架构 日志级别定义 日志格式规范 日志存储策略 DEBUG INFO WARN ERROR FATAL 时间戳 | 级别 | 线程 | 模块 | 消息 关键参数:device_id, error_code 禁止记录:密钥明文、PIN码 存储介质:RAM / Flash / SD卡 轮转策略:环形缓冲区 + 文件覆盖 过滤规则:级别 / 频率 / 内容 设计原则 可追溯 · 可控制 · 可持久 · 可安全

实战中的几个坑

最后分享几个我踩过的坑,希望能帮你少走弯路。

坑一:日志阻塞主流程
我曾经在一个项目里,日志写入 Flash 时用了同步方式。结果烧录过程中,每次写日志都要等几十毫秒,整个烧录流程被拖慢了好几倍。后来改成异步写入,日志先写 RAM 缓冲区,后台线程再刷到 Flash,问题就解决了。
坑二:日志泄露敏感信息
有一次调试时,我顺手把密钥的中间计算结果打到了日志里。上线前忘了删,结果客户反馈日志文件里能看到部分密钥数据。从那以后,我强制在日志模块里加了一个「敏感词过滤」功能,所有匹配正则的字段自动替换成 ***。
我的建议:日志系统不是写完就完事了。上线后要定期检查日志量、写入延迟、存储占用。我一般会在监控面板上加一个「日志健康度」指标,一旦日志写入延迟超过 100ms 就告警。

嗯,日志级别、格式、存储,这三个基础打好了,后面的日志分析、链路追踪才能玩得转。别小看这些基础工作,它们决定了你在出问题时,是花 10 分钟定位还是花 10 小时定位。