日志打得不好,出问题时只能靠 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 + 克制的使用级别,这三件事做到,日志就从「出事后翻文本」变成「可查询的数据」。
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://mi-blog.cn/archives/709
共有 0 条评论