日志格式设计:通用日志格式、结构化日志、JSON格式日志、日志字段规范

日志格式这事儿,说实话,我见过太多团队栽跟头了。

刚入行那会儿,我总觉得日志嘛,能打出来就行。结果呢?线上出问题的时候,一堆乱七八糟的文本堆在一起,grep 都救不了你。后来我慢慢悟出一个道理:日志格式设计,本质上是在为未来的自己铺路

今天咱们就聊聊,怎么把日志格式这件事儿做扎实。

通用日志格式:最朴素的方案

先说说最基础的。通用日志格式,说白了就是「人眼能看懂的文本日志」。我早期做运维的时候,大部分系统都这么干。

一个典型的通用日志长这样:

2024-01-15 14:23:45 [INFO] [main] User login successful - userId=12345, ip=192.168.1.1

这里面包含了几个核心要素:

  • 时间戳:精确到毫秒,最好带时区
  • 日志级别:INFO、WARN、ERROR 这些
  • 线程/进程名:方便定位问题来源
  • 消息体:描述发生了什么
注意:通用格式最大的坑是「解析困难」。我曾经在排查问题时,对着几千行格式不统一的日志,手动用正则匹配——那感觉,别提多酸爽了。

结构化日志:机器也能读懂

为什么要搞结构化日志?

你想想看,当你的系统从几台机器扩展到几百台,日志量从每天几 MB 涨到几个 GB 甚至 TB 级别,靠肉眼去看?不现实。

结构化日志的核心思想就一句话:把日志变成键值对

举个例子,同样的用户登录事件,结构化日志是这样的:

timestamp=2024-01-15T14:23:45.123Z level=INFO logger=AuthService thread=main message="User login successful" userId=12345 ip=192.168.1.1 duration=45ms

看到了吗?每个字段都有明确的 key。这样 Elasticsearch、Splunk 这类工具就能直接索引和搜索了。

我的习惯:在项目初期就定义好结构化日志的 schema,哪怕一开始只用了几个字段。后面扩展起来会轻松很多。

JSON 格式日志:业界标准

说到结构化日志,JSON 格式几乎是事实标准。为什么?

  • 几乎所有编程语言都原生支持 JSON 解析
  • 可读性好,既适合机器也适合人
  • 支持嵌套结构,表达能力更强

一个标准的 JSON 日志示例:

{
  "timestamp": "2024-01-15T14:23:45.123Z",
  "level": "ERROR",
  "logger": "PaymentService",
  "thread": "pool-1-thread-3",
  "message": "Payment processing failed",
  "context": {
    "orderId": "ORD-20240115-001",
    "amount": 299.99,
    "currency": "CNY",
    "paymentMethod": "wechat"
  },
  "error": {
    "code": "PAYMENT_TIMEOUT",
    "stacktrace": "com.example.PaymentException: ..."
  },
  "requestId": "req-abc123",
  "duration": 3020
}

关键点:JSON 日志里,我建议把「业务上下文」和「技术上下文」分开。比如上面的 context 字段放业务数据,error 字段放异常信息。这样在排查问题时,能快速定位到关键信息。

日志字段规范:定好规矩

格式定好了,字段也得有规范。不然每个人按自己的喜好写,最后还是乱成一锅粥。

我总结了一套常用的字段规范,你可以直接拿来用:

字段名 类型 说明 示例
timestamp string ISO 8601 格式时间戳 2024-01-15T14:23:45.123Z
level string 日志级别,统一大写 INFO, WARN, ERROR
logger string 产生日志的类或模块名 UserService
message string 人类可读的描述信息 User login successful
requestId string 请求追踪 ID,用于链路串联 req-abc123
userId string 操作用户标识 u-10086
duration number 操作耗时,单位毫秒 45
ip string 客户端 IP 地址 192.168.1.1
error object 异常信息,包含 code 和 stacktrace {"code": "TIMEOUT"}
避坑指南:我曾经在一个项目里,有人把 userId 写成 user_id,有人写成 uid,还有人直接写 id。结果日志分析的时候,同一个字段三个名字,数据根本对不上。所以,字段命名一定要统一,最好用工具强制校验

知识体系结构图

下面这张图,帮你理清日志格式设计的整体脉络:

日志格式设计知识体系 日志格式设计 通用日志格式 结构化日志 JSON格式日志 日志字段规范 时间戳 日志级别 线程/进程 消息体 键值对 机器可读 嵌套结构 标准解析 命名统一 类型定义 目标:可读性 + 可解析性 + 可扩展性

嗯,这张图基本把咱们聊的内容串起来了。从通用格式到结构化,再到 JSON 和字段规范,每一步都是在解决实际问题。

最后说一句:日志格式设计没有银弹。小项目用通用格式就够了,大系统必须上结构化 JSON。关键是,你得想清楚未来谁会看这些日志,以及他们想从中得到什么。


公众号:蓝海资料掘金营,微信deep3321