结构化日志与链路 ID:让线上问题可追溯

米阳 2023-10-23 5 10/23

日志打得不好,出问题时只能靠 grep 在一堆文本里拼时间线。花半天时间把日志格式统一一次,之后每次排障都能省下几倍时间。

一、别再打纯文本

这样的日志机器读不了:

用户 1024 下单失败,余额不够,订单 o8891

改成结构化(JSON 或 key=value):

{"ts":"2023-10-23T15:02:11+08:00","level":"WARN","event":"order_failed",
 "user_id":1024,"order_id":"o8891","reason":"INSUFFICIENT_BALANCE","cost_ms":38}

字段固定下来之后,就能按 user_id 聚合、按 reason 做告警、按 cost_ms 画分位数。

二、链路 ID 要贯穿全链路

入口(网关或中间件)生成一个 trace_id,放进日志上下文和响应头,调用下游时通过 HTTP 头传递:

X-Trace-Id: 4f1a9c2e7b8d

在同一次请求的所有日志里都带上它,排障时一次检索就能拉出完整调用链。异步任务、消息队列消费也要把 trace_id 序列化进消息体,否则链路会在异步边界断掉。

实现上用线程本地存储(或上下文变量)保存,避免每个方法都手动传参。注意线程池场景要显式传递上下文,线程复用还会导致 ID 串到别的请求上。

三、日志级别别乱用

级别 用途 是否告警
ERROR 需要人介入的失败 是
WARN 异常但已兜底(降级、重试成功) 汇总观察
INFO 关键业务节点、状态变化 否
DEBUG 详细参数,默认关闭 否

一个常见错误是把「用户输入不合法」打成 ERROR。那是预期内的校验失败,INFO 或 DEBUG 就够,否则告警会被噪声淹没。

四、敏感信息必须脱敏

手机号、身份证、token、密码、完整银行卡号一律不能直接进日志。统一在序列化层做脱敏:

phone  138****8000
token  sk-7f****3d

另外别把整个请求体无脑打出来,尤其是包含表单和文件上传的接口。

五、控制成本

高频接口按采样率打 DEBUG/INFO,错误日志全量保留;给日志设置保留周期(比如热数据 7 天、归档 30 天);单条日志长度设上限,防止把几 MB 的响应体写进文件把磁盘打满。

小结

结构化字段 + 全链路 trace_id + 克制的使用级别,这三件事做到,日志就从「出事后翻文本」变成「可查询的数据」。

- THE END -

米阳

10月23日15:05

最后修改:2023年10月23日
0

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论