日志系统设计原则
日志系统这东西,说白了就是飞控系统的「黑匣子」。我做了这么多年飞控中间件,最怕的就是系统在空中出了故障,结果日志一塌糊涂,根本查不出原因。嗯,今天我们就聊聊日志系统该怎么设计。
日志级别:从DEBUG到ERROR
日志级别不是随便定的。我个人习惯用四个级别,刚好够用,多了反而乱。
| 级别 | 含义 | 我什么时候用 |
|---|---|---|
| DEBUG | 调试信息 | 开发阶段、排查问题时才开启 |
| INFO | 常规信息 | 系统启动、参数变更、任务切换 |
| WARN | 警告 | 异常但不影响运行的情况 |
| ERROR | 错误 | 必须人工介入的故障 |
核心原则:生产环境只开INFO及以上级别。DEBUG日志量太大,会拖慢系统。
我在项目中遇到过一件事:有个同事把DEBUG日志开到了线上,结果每秒刷出几万条日志,直接把存储写爆了。飞机还在天上飞,日志先挂了。你说冤不冤?
日志格式规范
日志格式这事,看着简单,其实坑很多。我见过最乱的日志,连时间戳都没有,根本没法分析。
我个人推荐的标准格式:
[时间戳] [级别] [模块] [线程ID] - 消息内容
举个例子:
[2024-01-15 14:32:18.456] [INFO] [IMU] [0x3A2F] - 陀螺仪数据校准完成,偏置: 0.02°/s
为什么要这么设计?你想想看:
- 时间戳:精确到毫秒,方便定位问题发生的时间点
- 级别:一眼看出严重程度
- 模块:快速定位是哪个子系统出了问题
- 线程ID:多线程环境下,知道是谁在干活
我的小技巧:时间戳统一用UTC+8,别用本地时间。有一次我调试跨时区的系统,日志时间乱成一锅粥,后来统一用UTC+8就再没出过问题。
日志轮转策略
日志不能无限增长,否则磁盘迟早会满。轮转策略就是解决这个问题的。
我常用的策略有两种:
- 按大小轮转:每个日志文件固定大小,比如100MB。满了就新建一个。
- 按时间轮转:每天或每小时生成一个新文件。
实际项目中,我一般两种结合用:
# 日志轮转配置示例
max_file_size: 100MB # 单个文件最大100MB
max_file_count: 10 # 保留最近10个文件
rotation_policy: size # 按大小轮转
compress_old: true # 压缩旧日志
注意:轮转时一定要保证原子操作。我曾经遇到过日志写到一半被轮转,结果文件损坏的情况。解决方案是:先写到一个临时文件,轮转完成后再重命名。
日志存储架构
存储架构这块,我踩过不少坑。飞控系统的日志,既要保证实时写入,又要方便事后分析。
我推荐的分层架构:
应用层 → 日志缓冲区 → 本地存储 → 远程归档
具体来说:
- 应用层:各个模块产生日志,通过统一的API写入
- 日志缓冲区:内存中的环形缓冲区,防止写入抖动
- 本地存储:SSD或eMMC,保存最近7天的日志
- 远程归档:通过MQTT或FTP上传到服务器,长期保存
关键点:缓冲区大小要合理。太小了容易丢日志,太大了浪费内存。我一般设为1MB,够用。
这里我画了一张架构图,帮你理解整个流程:
这张图你看懂了吗?数据从应用层产生,先进入缓冲区,再写入本地存储,最后异步上传到远程。每一层都有缓冲和容错机制,保证日志不丢。
避坑指南:我曾经在远程归档上吃过亏。网络不好时,日志上传失败,结果本地存储被撑爆了。后来我加了限速和重试机制,才彻底解决。
好了,日志系统的设计原则就这些。记住一句话:日志是飞控系统的最后一道防线。设计得好,出问题能快速定位;设计得差,出了事连原因都找不到。你自己掂量掂量。
公众号:蓝海资料掘金营,微信deep3321