← Back to Blog

日志不是流水账:把日志写成排障利器的四个原则

19 阅读 点赞

几乎所有后端工程师都说过同一句话:”这个 bug 我先看看日志。”然后我们打开日志文件,滚动几万行,越看越迷糊,最后只能加断点、改代码、重新部署,绕一大圈才定位到问题。日志明明记录了一切,为什么关键时刻却帮不上忙?

问题往往不在”有没有日志”,而在”日志是怎么写的”。日志本身不产生价值,能被快速检索、能被结构化聚合、能在故障发生时直接给出线索的日志才产生价值。这篇文章想聊的是:把日志从”流水账”变成”排障利器”,需要坚持的四个原则。

日志与追踪链路概念封面
日志的价值不在于记录了多少,而在于关键时刻能否被检索和串联

原则一:日志是给未来的自己和同事看的,不是给当前开发者看的

写日志时最容易被忽略的一点是:读日志的人不是现在的你,而是三个月后凌晨两点被报警叫醒的另一个人——可能是你,也可能是刚入职三周的同事。他不知道当时的业务上下文,不知道这段代码的调用链路,更不知道哪个变量是”正常的”。

所以判断一条日志该不该打、该怎么写,有个很实用的检验标准:如果这条日志出现在值班人的屏幕上,他能不能只靠这条日志判断”发生了什么、影响谁、下一步查哪里”?如果答案是”看不懂”,那这条日志就是无效日志。

具体做法上,至少要做到三点。第一,日志消息本身要包含足够的上下文,而不是只写一个孤零零的状态。Processing...订单支付回调开始处理 order_id=8823 user_id=117 金额=299.00 是完全不同量级的两个东西。第二,避免在日志里使用缩写和内部黑话,比如 usv fail 这种只有原作者能懂的写法,过一阵子作者自己也想不起来。第三,敏感信息要脱敏但要保留可关联性——手机号中间四位打码,但保留订单号、用户 ID 这类非敏感标识,它们才是串联链路的关键。

一个简单的自我训练方法:每次写完日志,强迫自己只读这一行,不看代码,问自己”我能复现出这个场景吗”。坚持一段时间之后,日志的可读性会有质的变化。

日志分级与结构化采集概念图
日志级别是分诊台:ERROR 需要人介入,WARN 只需关注趋势

原则二:级别要克制,ERROR 不能是”情绪表达”

日志级别是最容易被滥用的东西。很多项目里 ERROR 满天飞,因为开发者觉得”这里可能出问题,先打 ERROR 保险”。结果是报警系统天天响,值班人逐渐麻木,真正的故障淹没在噪音里。这就是典型的”报警疲劳”。

比较健康的级别使用习惯是这样的:ERROR 代表”需要人介入,且此刻业务已经受损”WARN 代表”异常但已自动兜底,业务未受损,但值得关注趋势”INFO 用于记录关键业务节点和状态变更DEBUG 只用于本地或临时排查,默认在生产环境关闭

按这个标准,用户输入了错误的手机号、验证码校验失败,这些都不是 ERROR,而是 WARN 甚至 INFO——系统正确拒绝了非法请求,这是设计内的行为,不是故障。真正该打 ERROR 的是:下游服务不可用导致主流程中断、数据库连接耗尽、消息积压超过阈值这类必须有人处理的状况。

级别的另一个价值在于聚合。当 ERROR 数量被控制在一个很小的量级,它就能成为一条清晰的监控曲线。这时候你可以做真正有用的事:给 ERROR 设报警、给 WARN 设趋势告警(比如某类 WARN 半小时内增长十倍),而不是把所有级别混在一起看总量。级别不是装饰,它是分诊台。

原则三:结构化 + 请求 ID,让日志能被机器读懂和串联

纯文本日志的问题在于,它对人勉强可读,对机器几乎不可用。你想统计”过去一小时有多少订单超时”,用 grep 加正则去凑,既慢又容易漏。而结构化日志(JSON 是常见选择)把关键字段拆开,查询就变成了简单的字段过滤。

结构化日志至少要保证几个字段固定存在:时间戳(带时区、ISO 格式)、日志级别、服务名、请求 ID(trace_id / request_id)、以及业务关键标识。有了固定字段,日志平台就能做聚合、告警、链路追踪,也能在出问题时一键圈定范围。

其中请求 ID 是最值得投入的一件事。在网关或入口处生成一个唯一 ID,通过 HTTP Header 或上下文一路透传——跨服务调用、跨线程、进消息队列、写异步任务,都带着它。这样当用户报”我下单失败了”,你拿订单号或请求 ID 一搜,从入口到数据库的完整链路一次拉出来,不用再靠时间戳去猜哪几条日志属于同一次请求。这一个改动带来的排障效率提升,通常比引入任何新工具都大。

顺带提一个常被忽视的细节:日志的时间戳必须统一时区并且精确到毫秒。分布式系统里跨机器排查问题,秒级时间戳和本地时区足以让你多花一个小时。

深夜机房排障意境图
一份好日志,是凌晨值班时最靠得住的队友

原则四:日志要有预算意识——成本和留存都是设计问题

很多团队把日志当成免费的,直到账单来了。高并发服务打 DEBUG 日志,一天几百 GB 是常事,存储成本、传输成本、索引成本都不是小数目;更糟的是,日志量太大之后,检索变得极慢,关键时刻反而用不上。

所以日志需要”预算”。几个实用的做法:一是分级控制开关,让日志级别可以通过配置中心动态调整,出事时临时开 DEBUG,事后马上关掉,不必重新发版。二是采样,对高频重复的日志按比例采样(比如打印 1%),既能看出趋势又不至于淹没磁盘。三是明确留存策略,热数据留七天便于排查,冷数据归档压缩留更长的合规周期,不要让所有日志都用同一套昂贵的存储。四是屏蔽噪音,把健康检查、静态资源这类无信息量的访问日志过滤掉,它们通常占到总量的很大比例。

还有一点常被忽略:日志内容里不要 dump 整个大对象,比如把完整的 HTTP 响应体或整个数据表塞进日志。这既昂贵又难看,还容易把敏感数据写进去。只打印定位问题必需的那几个字段。

结语

日志是一项典型的”平时不显眼、关键时刻决定胜负”的基础设施。它不需要多高深的技术,却需要持续的自律:写的时候想着读者,分级的时候想着报警,落盘的时候想着机器,最后还要想着成本。

回头看这四个原则,其实指向同一件事——日志是在为未来的自己和你信任的同事构建一套可检索的记忆。当你下次凌晨被叫起来时,你会感谢半年前那个认真写日志的自己。

💬 发表评论