日志怎么记才有用:从 printf 到结构化日志
线上出问题,登上去翻日志,看到满屏的:
start
processing...
done
error
哪个请求?哪台机器?什么时候开始的?错误码是多少? 一概没有。
这不是日志太少,是日志没有信息量。
一条有用的日志该带什么
最小可用集合是这五样:
字段 | 作用 | 反例
时间(带时区/毫秒) | 对齐多个服务的时序 | 10:23:01 不知道哪个时区
级别 | 快速过滤 | 所有东西都打成 INFO
来源 | 哪个服务/模块 | 只写 "error occurred"
上下文 ID | 串起一次请求的全链路 | 无
具体数据 | 到底发生了什么 | "操作失败" 不说为什么
其中上下文 ID(trace id / request id) 是最容易被忽略、也最值钱的一个。
有了它,一次用户请求经过五个服务,你可以把五段日志拼成一条时间线。没有它,你只能靠时间戳猜,而时间戳在并发场景下根本对不上。
日志级别怎么分才不乱
很多人把级别用成了三种:INFO、ERROR、还有"我也不知道该用哪个"。
一个可操作的划分:
级别 | 什么情况用 | 生产环境开不开
ERROR | 需要人介入的事(请求失败、数据不一致、外部依赖挂了) | 一直开
WARN | 异常但能自愈(重试成功、降级生效、接近阈值) | 一直开
INFO | 关键业务节点(请求进来、订单创建、任务完成) | 一直开,但要克制
DEBUG | 排查细节(参数、中间结果) | 默认关,按需开
判断标准:这条日志会让人半夜被叫起来吗? 会 → ERROR;不会但值得看一眼 → WARN;只是想知道流程走到哪 → INFO。
最常见的错误是把所有异常都打成 ERROR。结果 ERROR 一天几万条,没人看了,真正的故障被淹没。
能自愈的错误不该是 ERROR。 重试第二次成功了,那就是 WARN。
什么时候该上结构化日志
纯文本日志的问题:想按字段筛选就得写正则,而正则一改就可能漏。
结构化日志是把一条日志输出成一行 JSON:
{"ts":"2026-10-26T10:23:01.482+08:00","level":"ERROR","svc":"order","trace":"a3f9c2","msg":"payment timeout","orderId":"20261026001","elapsedMs":30012}
好处很直接:
- 日志系统能直接按
orderId查,不用正则 - 能算指标(比如按
elapsedMs统计 P99) - 不会因为日志文案改了就断掉监控规则
代价:人眼看不如纯文本舒服。
所以实践中的折中方案是:开发环境用可读格式,生产环境输出 JSON。大多数日志库都支持按环境切换格式。
如果只是个小脚本、日志量一天几十行,那就别上结构化,纯文本加好字段就够了。别为了架构感给自己加活。
三个常见反模式
反模式一:在循环里打日志
for (const item of items) { log.info("processing " + item.id) }
一万条数据就是一万行日志。磁盘写满、日志系统限流,真出问题时反而查不到。
做法:循环里只统计,循环外打一条汇总。
反模式二:日志里带敏感信息
这是最危险的一类。密码、token、完整手机号、身份证、银行卡,只要进了日志,就等于进了所有能看日志的人手里。
做法:输出前统一脱敏,只留前后各 4 位。而且要在打日志的那一层做,不要指望日志系统来过滤——它不知道你的业务字段是什么意思。
反模式三:异常吞掉只留一句 "failed"
try { doSomething() } catch (e) { log.error("failed") }
堆栈呢?错误码呢?
正确做法是把异常对象本身打出来,或者至少打 e.message 和 e.stack。丢掉堆栈的那一行日志,等于把排查线索扔了。
日志要不要轮转
要。而且这是最常见的"磁盘被日志撑满"的元凶。
一条最小的轮转配置:
/path/to/*.log {
daily
rotate 14
compress
missingok
notifempty
copytruncate
}
copytruncate 适用于不支持重新打开日志文件的程序(它先复制再清空,写入方不受影响)。
如果程序支持信号重开(很多守护进程支持 SIGUSR1),用 create 模式更干净。
注意权限:如果日志目录所属用户不是 root,logrotate 会以"目录权限不安全"为由跳过。这时需要在配置里加一行:
su 用户名 用户组
这个报错信息很不显眼,容易以为轮转生效了其实没有。
小结
三条能立刻用上的:
1. 每条日志带 trace id —— 这是排查效率提升最大的一步
2. 能自愈的错误别打 ERROR —— 保住 ERROR 的信噪比
3. 日志里绝不出现敏感明文 —— 在产生日志的那一层脱敏
日志不是写给自己看的,是写给三个月后半夜被叫起来的自己看的。按这个标准写,就不会写出满屏的 "start / done"。
- 点赞
- 收藏
- 关注作者
评论(0)