没有日志,本身也是情报
一句话总结
没有日志并不意味着调查结束。工作还包括用其他痕迹缩小时间范围,并确保下次事故发生时能够留下日志。
为什么需要它
收到“昨天下午有几条请求失败”的报告后,我们开始寻找日志。但日志保留期只有 24 小时,可能已经被删除;日志级别可能是 WARN,所需信息从未记录;或者该路径本来就没有任何日志语句。
如果此时以“没有日志,无法确认”结束调查,同样的事情还会重复发生。
日志之外的痕迹
| 痕迹 | 能告诉我们什么 | 检查方法 |
|---|---|---|
| 文件 mtime | 何时修改了什么 | find /etc -mmin -1440 -type f |
| 数据库时间戳 | 数据创建或修改的时间 | created_at, updated_at 的分布 |
| 进程启动时间 | 何时发生重启 | ps -eo pid,lstart,cmd |
| 系统启动时间 | 服务器何时启动 | uptime -s |
| 文件大小变化 | 何时突然增长 | 比较多个备份快照 |
| 软件包安装时间 | 何时安装了什么 | /var/log/dpkg.log, rpm -qa --last |
| Shell 历史 | 人员执行了什么 | ~/.bash_history(启用时间记录时) |
| 证书有效期 | 因过期引发故障的时间 | openssl x509 -noout -dates |
**数据本身就是日志。**按分钟聚合失败订单的 created_at 分布,即使没有日志,也能定位事故开始的具体分钟。
SELECT date_trunc('minute', created_at) AS m, count(*)
FROM orders WHERE status='FAILED' AND created_at >= now() - interval '2 days'
GROUP BY 1 ORDER BY 1;
结果中数值突然升高的位置就是事故时间。再把该时间与部署记录、配置变更和启动时间对照,候选原因就会缩小到一两个。
“不存在”本身也是证据
日志中的空白区间本身就是信息。
- 平时每分钟 200 行,14:03~14:07 却为 0 行 → 进程可能停止,或磁盘已满而无法写入。
- 只有错误日志缺失,访问日志正常 → 请求根本没有到达应用,而是在前端 LB 或代理处中断。
- 只有一台服务器没有日志 → 该服务器可能日志轮换失败,或磁盘已满。
不要把“没有记录”翻译成“不知道”。询问“究竟什么没有被记录”,范围就会缩小。
为下一次留下证据
调查结束并找到原因后,最后一项工作是确保同样的问题再次发生时,比这次更早知道。
- 增加日志语句——在失败路径中记录什么失败、为什么失败,同时记录事后调查所需的值,例如请求 ID、目标和耗时。
- 调整保留期限——24 小时不足以支持大多数调查,至少应让错误日志保留更久。
- 关联 ID——为每个请求附加 ID,使其能够跨系统追踪。缺少它时,只能通过时间勉强对齐多个服务的日志。
- 增加一个指标——把本次问题转化为计数器或仪表,下次就能直接在图表中看到。
把这四项写进报告的“防止复发”部分,就不再是一句形式化描述,而会真正为下一次调查节省数小时。
事后加装观测——问题正在发生时
如果问题当前仍在持续却没有日志,就在能够复现期间附加观测。
- 周期快照:
while true; do date; ss -s; ps aux --sort=-%cpu | head -5; sleep 10; done >> /tmp/watch.log - 响应时间采样:重复执行
curl -w并写入文件。 - 数据库活动会话快照:定期按等待事件聚合。
这些方法虽然粗糙,却远胜于什么都没有,而且该文件可能成为下次会议中唯一的依据。
第一次为他人的系统添加观测时
FDE 进入客户现场时,系统通常没有日志,或者即使存在也无法查看。在既没有权限、也不能随意部署的状态下,存在一套以最少变更获得最多信息的顺序。
**第一,寻找已有信息。**增加新观测前,先清点系统已经留下的内容:Web 服务器访问日志、数据库慢查询日志、负载均衡器统计、云流量日志。它们往往已经启用,只是无人查看。
第二,从外部测量。即使无法修改代码,也可以从外部发起请求。每隔几分钟调用一次核心路径,并记录响应时间和状态码,仅凭这些信息就能知道事故从何时开始。即使不了解原因,知道时间也已经完成了调查的一半。
**第三,在边界添加观测。**即使无法修改应用,通常仍有机会调整前方的代理或 Sidecar。让它按请求记录时间和状态,就能在不修改一行代码的情况下获得请求级观测。
第四,最后才修改代码。进行到这一步时,已经知道应该在哪里加装观测。如果一开始就动代码,可能会监控错误的位置,还要额外承担回滚修改的成本。
**一开始就确定哪些内容应该记录、哪些不应该记录。**面对他人的系统时,很容易在不了解个人信息内容的情况下开启日志。启用完整请求正文记录前,必须先确认正文中包含什么。
**报告时应同时写出数字及其来源。**不要只写“很慢”,而应写“该路径 p95 为 4.2 秒,过去 7 天按负载均衡器统计的中位数为 0.4 秒”。这样下一步行动可以当场确定。缺少来源时,人们会先重新争论数字本身。
生产现场中的表现
- 保留期为 7 天,报告却在 10 天后到达 → 使用数据时间戳定位时间。
- 日志没有请求 ID,无法连接多个服务 → 勉强按时间对齐,最终误判。
- “无法复现就看不到” → 预先加装事后观测,下次即可捕获。
后续实验要做什么
你将接手一个事故区间错误日志已经消失的现场,仅凭数据的 created_at、访问日志中的空白区间和配置文件修改时间,把事故时间缩小到分钟级,并将候选原因缩小为一个。
最后还会亲自制作事后观测器。评分程序会实际运行它,确认时间与观测值是否按周期留下记录。