日志格式设计原则:可读性、解析效率、压缩率

日志格式怎么定?别小看这个问题。我见过太多团队,上来就用 JSON 一把梭,结果一个节点一天写几个 TB,存不起也查不动。反过来,也有人为了省空间写自创二进制格式,出问题的时候谁都看不懂——包括写代码的那个人自己。

说白了,日志格式设计就是三件事:让人能看懂,让机器能快解析,让磁盘少占空间。这三件事有时候互相打架,你得清楚什么时候该让谁让步。

核心认知: 不存在“最好的格式”,只有“当前业务下最合适的折中”。你必须在可读性、解析效率和压缩率之间找到平衡点,而且这个点会随着日志量级变化。

3.1 可读性:别让运维同事骂你

我个人习惯,任何线上日志的第一条标准就是:一个不了解系统的人在紧急排障时,能一眼看懂这条日志在说什么。

可读性不是叫人写长篇大论,而是做到三个“清晰”:

  • 结构清晰: 一眼能区分时间、级别、模块、消息体
  • 字段清晰: 每个字段有明确的键名或位置约定
  • 内容清晰: 错误消息里带上关键上下文,别只写个错误码

我在项目中遇到过一件特别无奈的事。某次线上故障,运维 grep 出来的日志全是 {"code":-1,"msg":"internal error"}。一问开发,错误码 -1 代表“所有未知错误”。你说这日志跟没写有什么区别?

设计可读性的几个落地做法:

  1. 时间戳使用 ISO 8601 格式(2025-06-15T14:30:22.123+08:00),别用 Unix 毫秒数
  2. 日志级别用 INFO、WARN、ERROR 这样的全大写单词,别用数字 0/1/2
  3. 每个日志条目独占一行(方便 grep 和 tail)
小技巧: 如果必须用结构化格式,建议 LTSV(Labeled Tab-Separated Values)。它比 JSON 可读性好,而且 grep 不费劲。
例如:time:2025-06-15T14:30:22\tlevel:ERROR\tmodule:user_svc\tmsg:db timeout

3.2 解析效率:别让采集器拖慢业务

可读性再好,如果解析一行日志要花 5 微秒,每天 10 亿行,光是解析就要吃掉 5000 秒 CPU 时间。你想想看,这还没算传输和索引。

解析效率要关注两个阶段:

  • 采集阶段: Agent 或 Logstash 这类组件需要逐行解析
  • 写入阶段: 存储引擎需要从原始行中提取字段建索引

提升解析效率的常规做法:

我曾经踩过的坑: 某次用 JSON 做日志格式,字段名平均 8 个字符,日志里 80% 是键名。采集端为了防止字段乱序,还启用了严格校验——结果一个 8 核机器居然被日志解析打满了。后来改成固定顺序的管道符分隔格式,CPU 降了 70%。

推荐的格式选择优先级(按解析速度)

格式 解析速度 适用场景 说明
固定宽度 极快 高性能采集 截取子串即可,无需分隔符处理
管道符/空格分隔 快 日常业务日志 按分隔符切分,字段顺序固定
LTSV 中 需要结构化可读 按 \t 分割后按标签定位
JSON 慢 系统间传递 需 JSON 解析器,字段冗余高

我个人的一个习惯:如果日志量超过每天 100 GB,就别用 JSON。实在需要结构化,改 LTSV 或者自己设计紧凑的管道符格式。

3.3 压缩率:存得下才能查得到

可读性再好,解析再快,存储成本扛不住也是白搭。压缩率决定了你日志的保留周期——说白了就是你能看多远的“历史”。

// 一个典型对比
// 相同内容的不同格式大小(示例值)
JSON:      256 bytes  → 压缩后 72 bytes  (压缩比 3.6:1)
LTSV:       192 bytes → 压缩后 58 bytes  (压缩比 3.3:1)
管道符分隔: 140 bytes → 压缩后 42 bytes  (压缩比 3.3:1)
自研二进制:  88 bytes  → 压缩后 38 bytes  (压缩比 2.3:1)

看出来了吧?文本内容越冗余,压缩率越高。 但这里有个关键点——压缩率看的是压缩后的大小,不是原始大小。有些二进制格式原始体积小,但已经是压缩过的状态,再压也压不下去多少。

影响压缩率的几个设计要点:

  • 字段冗余: 日志里有很多重复字段(时间戳前缀、instance_id 等),这些是压缩器最喜欢的“规律”
  • 字符串长度: 过长的错误消息会拉低压缩比,建议截断或摘要
  • 换行符: 每条日志独占一行,gzip 等流式压缩器可以跨行找模式
实践经验: 如果你的日志需要长期存储(超过 30 天),建议在采集端先做一次 gzip -1(最快级别)再传输。我做过测试,Go 的 gzip.DefaultCompression 压缩文本日志,速度大约 80 MB/s,压缩比能到 4~6:1。

3.4 三个原则的权衡:用一张图说清楚

这三个原则不能同时取最优。你想想看,要可读性就得保留文本信息,要解析效率就得固定分隔,要压缩率就得允许重复字段——它们天然有冲突。

下面这张图展示了它们的关系和常见方案的定位:

日志格式设计三原则权衡图 可读性 解析效率 压缩率 JSON(高可读,低效率) LTSV(较均衡) 管道符分隔(高解析效率) 固定宽度(极高解析效率) 自研二进制(高压缩) 方案在三角形中的位置越靠近某个顶点,说明该项能力越强;理想方案应尽量靠近中心区域

从图上能直观看到:没有哪个方案能同时占据三个顶端。选格式时你得先回答一个问题——业务最受不了哪个短板?

  • 如果排障最重要,可读性不能妥协 → 选 JSON 或 LTSV
  • 如果采集端 CPU 吃紧,解析效率优先 → 选固定宽度或管道符
  • 如果存储成本快炸了,压缩率必须高 → 选自研二进制或预压缩
特别提醒: 格式选定了就别轻易改。换了格式等于让线上所有采集管道、解析插件、索引映射全部跟着变——我见过某团队年中改了一次日志格式,三个月后才发现之前的归档数据全没法用新解析器读。

好了,总结一下这一节的核心:可读性给运维兄弟一条活路,解析效率不给采集端添乱,压缩率让财务别找你要预算。 定格式之前,先拿实际日志样本跑跑——解压速度和压缩比这两个数,心里要有底。