小服务的日志不该只靠人眼翻

服务规模不大的时候,日志就是一个文件,出了问题就上去 grep。这个办法在一天几十兆的时候还能用。等一天超过几个 GB,或者同一种错误一分钟出现上百次,人眼翻日志就只剩下碰运气。

先让一行日志能被机器读

我把应用日志改成每行一个 JSON。固定字段包括时间、级别、服务名、环境、请求编号、消息。业务字段按需加,不要把一整段对象直接塞进去。

请求编号在网关生成,通过请求头传给应用,再写进每一条相关日志。这样从一条 502 可以找回这一次请求在应用里的全部记录,而不用拿时间戳去对。

1
2
3
4
5
6
7
8
{
"time": "2026-07-30T12:04:11Z",
"level": "error",
"msg": "query failed",
"request_id": "8f3c1a",
"duration_ms": 42,
"error": "connection reset"
}

文本日志不是不能用,而是字段一旦靠空格分隔,消息里多一个空格,后面的切割就会错位。JSON 多占一点体积,换来的是后面可以按字段统计。

级别要有含义

info 记录请求完成和状态变化,一条请求一条,不记录循环里的每一步。warn 表示这次处理退化了,但请求还是完成了,比如缓存未命中后回源。error 表示这次请求失败,需要人看。

最常见的问题是把预期内的失败打成 error。用户输错密码是业务结果,不是系统故障。打成 error 之后,告警会被淹没,真正的数据库错误反而不显眼。

告警看比率,也看新增

错误日志可以按消息模板聚合,把变量留在字段里,消息本身保持稳定。告警设在错误率,而不是错误条数。流量涨一倍时,条数涨一倍不一定表示故障。

另外留一个很简单的检查:过去一小时出现、过去七天没出现过的错误模板。新错误往往比总错误率更早说明这次发布带进了问题。

不要记不该记的东西

密码、会话令牌、身份证号、完整的请求体,默认不进日志。调试某个字段时,只打印长度或者是否为空。临时把级别调到 debug 可以,但不要在生产长期打开,体积和敏感信息都会上来。

日志文件按天切分,保留十四天。超过这个时间还需要追查的,应该已经在指标或链路里,而不是在某一台机器的旧文件里。