你没法修一个找不到的错误。
一、用户说「就是不行」
周四下午,一个用户来信:「导出功能就是不行,试了好几次。」没有截图,没有时间,没有订单号。
简宁打开日志,一千多行里混着访问记录、定时任务输出和第三方回调。她按「导出」搜,跳出两百多条;按用户的邮箱搜,因为脱敏规则,只剩一串星号。
两个小时后,她在一个没有请求 ID 的错误堆栈里找到了原因:导出任务在读取一个空字段时崩了。修复只用了八分钟。
以下情境为教学假设,人物、引语和数字不代表经核实的真实案例。
排障时间里,找占大头。 修复是确定的工作,找是不确定的工作;日志的作用就是把不确定压成确定。
日志不是越多越好。 记录得多但串不起来,等于把一千行噪音换了个地方存放。
先能串起来,再谈分析。 请求 ID 是把日志变成证据的那根线;没有它,再多字段也只是散落的碎片。
二、日志只记四件事
一条日志要能独立回答:什么时候、哪个请求、做了什么、结果如何。
| 字段 | 例子 | 为什么需要 | 成本 |
|---|---|---|---|
| 时间 | 2026-10-25T14:03:21.418+08:00 | 和其他系统对齐时间线 | 24 字节 |
| 请求 ID | req_7f3a91c2 | 把一个请求的十几行串成一条链 | 12 字节 |
| 事件 | export.start / export.fail | 让人按动作搜索,而不是按文字猜 | 16 字节 |
| 结果 | ok / error.code=EMPTY_FIELD | 区分成功、业务失败与系统失败 | 20 字节 |
请求 ID 要在入口生成。 从反向代理或应用入口生成一次,往下传;中途再生成一个,链条就断了。
后台任务也要带 ID。 定时任务没有入口请求,就用任务批次号;否则它出错时同样查不到。
事件名用固定的词表。 export.start、export.finish、export.fail 三个词就够;写成自然语言句子,半年后没人搜得到。
用户标识要可逆地脱敏。 存哈希而不是邮箱;排查时让用户提供订单号,用订单号反查哈希。
不要把异常堆栈当消息。 堆栈进单独字段,消息保持一行;否则一行日志会被撑成五十行,采样时最先被丢。
成功也要记一条。 只记失败的日志,无法回答「这个用户到底有没有成功过」。
时间用带时区的 ISO 格式。 本地时间加偏移,跨时区排查时不用再猜。
三、错误聚合:1200 条怎么变成 4 组
错误一旦按堆栈指纹聚合,数量会塌下来。
| 组 | 条数 | 占比 | 典型原因 | 处置 |
|---|---|---|---|---|
| 数据库超时 | 640 | 53.3% | 连接池耗尽、慢查询 | 扩池、加索引 |
| 第三方失败 | 310 | 25.8% | 供应商 5xx、超时 | 重试与降级 |
| 输入错误 | 180 | 15.0% | 空字段、超长文本 | 前置校验、改提示 |
| 未知 | 70 | 5.8% | 未捕获异常 | 逐条看,补分类 |
指纹要包含错误类型与关键堆栈行。 只按消息聚合,timeout 会把所有超时混成一组;只按堆栈聚合,同一种错误会因为行号变化分裂成几十组。
输入错误不算故障。 180 条输入错误应该被前置校验挡掉,而不是变成 180 条告警。
未知组要每周清零。 70 条未知里通常藏着真正的缺陷;放着不管,下个月它会变成第 5 组、第 6 组。
每组只挂一个动作。 640 条数据库超时对应「扩池到 50 并加一个索引」,不写「优化数据库」。
聚合后看趋势,不只看数量。 某组从每天 2 条涨到 20 条,比总数从 40 涨到 45 更值得处理。
四、保留期、采样与脱敏
日志成本由三件事决定:写入量、保留期、是否采样。
写入量 = 1.2 GB/月
采样 10% → 索引量 = 0.12 GB/月
保留 30 天 → 常驻约 0.12 GB(按月轮转)
查询目标:从用户报障到定位 ≤ 5 分钟
无请求 ID 时(本例):平均 2 小时 7 分钟才定位
1200 条错误 → 4 组 → 4 个动作,而不是 1200 次判断
采样只采成功日志。 错误日志全量保留;把失败也采样掉,等于在最需要证据的时候丢证据。
保留期按用途分。 访问日志 30 天够回溯一次报障;错误日志 90 天够覆盖一个季度;审计类另算,走合规口径。
轮转要自动化。 靠手动清理的日志,最后一定会在磁盘满的那天被想起。
脱敏在写入前做。 先落盘再脱敏,敏感字段已经进了备份;写入前替换,才谈得上「没存过」。
日志里不要放密钥与令牌。 请求头整体打印是最常见的泄露方式;白名单打印字段,比黑名单删除可靠。
查询要有一键入口。 从错误详情点进「同一请求的全部日志」,比让人手输请求 ID 快得多。
每月看一次体积。 1.2 GB/月若涨到 4 GB,先查是不是某个循环在刷日志,而不是直接买更大套餐。
五、行动清单与复算验收
先把四个字段补齐,再谈日志平台。
- 在入口生成请求 ID,并透传到所有下游调用。
- 固定事件名词表,覆盖主路径的开始、完成与失败。
- 把异常堆栈放进独立字段,消息保持单行。
- 用户标识改为哈希,并保留订单号反查路径。
- 按「类型 + 关键堆栈行」配置错误指纹。
- 成功日志采样 10%,错误日志全量保留。
- 设定保留期:访问 30 天、错误 90 天。
- 在错误详情页加「查看同一请求」的跳转。
验收标准:给你一个用户报障时间,你能在五分钟内找到那一次请求的全部日志并说出失败原因;做不到,说明日志还只是记录,不是工具。
使用边界与实操验收
本文处理的是排障所需的日志与错误聚合,不涉及审计合规与数据仓库。
审计日志不归本文。 谁在什么时候改了什么,属于合规要求,保留期与不可篡改性另有一套标准。
日志不是指标。 用日志算错误率会又慢又贵;指标走监控,日志走排查。
别追求全量长存。 一人产品存一年全量日志,成本会超过服务器本身,收益却很低。
采样比例要写进文档。 否则下次排查时,你会怀疑「是不是日志被采样掉了」。
脱敏规则要能被测试。 写一条测试用例,断言邮箱、令牌、卡号不会出现在日志里。
日志格式要稳定。 字段名一年改三次,历史日志就无法与新日志一起查询。
定位时间要记录。 每次报障记下从收到到定位的分钟数;这个数字才是日志质量的验收指标。
关键参考与核验范围
核验日期:2026-10-25。以下链接用于核对结构化日志与错误聚合的一般做法,本文未逐条引用其内容。
- Google SRE:日志与错误处理 :用于核对过载时的日志与降级取舍。
- OpenTelemetry:日志数据模型 :用于核对结构化日志的字段组织方式。
引用口径。 本文只借用「结构化字段 + 请求串联 + 指纹聚合」这一一般结构;1.2 GB、1200 条、640 与 5 分钟全部是教学假设,与上述材料无关。
核验范围。 核验的是「四个字段能否支撑五分钟定位」,不是比对某家日志服务的功能与计价。
如何自行复核。 取最近一次报障,从收到邮件的时间算到定位根因的时间;若超过五分钟,先检查请求 ID 是否断了。
系列导航
- 上一篇:告警降噪:从 40 条到 3 条
- 下一篇:状态页与故障沟通:故障时说什么、多久说一次
- 回到目录:一个人的运维:可用性、告警、事故与值班
- 相关阅读:故障排查树:症状、检查与出口
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。