阅读提要
日志不是「打印出来就行」。没有时间戳、没有请求 ID、没有轮转策略的日志,出故障时基本用不上,还会把磁盘写满。
日志的三个用途
写日志之前先想清楚它给谁看:
- 排查故障:某个请求失败了,为什么?
- 审计:谁在什么时候做了什么?
- 统计:接口耗时分布、错误率趋势。
三种用途对格式的要求不同。混在一起写,往往哪一种都做不好。

结构化优先于「好看」
一行自然语言日志:
用户 admin 上传文件失败,文件太大
机器没法可靠解析。结构化日志:
{"ts":"2026-11-01T10:12:33.482Z","level":"warn","event":"upload.reject","userId":1,"size":31457280,"limit":20971520,"requestId":"a3f9c1"}
后者可以直接按 event 聚合、按 requestId 串联、按 size 排序。代价是人眼看着累,所以需要一个格式化查看工具(jq、pino-pretty)。
判断标准:这条日志将来会不会被搜索? 会,就写结构化。
三个必带字段
不管用什么库,这三样不能少:
时间戳(ISO 8601,带毫秒和时区)。2026-11-01T10:12:33.482Z 而不是 11-01 10:12。跨时区排查时,缺时区的日志等于废纸。
请求 ID。每个进入系统的请求生成一个,透传到所有下游调用和日志里。一个用户报障,拿这个 ID 一搜,从网关到数据库的完整链路就出来了。没有它,你只能靠时间戳猜。
级别。至少区分 error / warn / info。全用 console.log 的代码,出问题时无法过滤。
轮转:三种策略
按大小:单文件到 100MB 就切,保留最近 10 个。适合流量不可预测的服务。
按时间:每天零点切一个文件。适合按天归档和清理。
两者结合:每天切,但单文件超过 500MB 也提前切。这是最稳的。
Linux 上现成的工具是 logrotate:
/opt/blog/logs/*.log {
daily
rotate 14
size 100M
compress
delaycompress
missingok
notifempty
copytruncate
}
copytruncate 这个选项值得说:它先复制文件再清空原文件,适用于「进程一直持有文件句柄、不响应信号」的场景。缺点是复制瞬间可能丢几行日志。如果应用支持 SIGHUP 重开文件(大多数日志库都支持),用 create 更严谨。
用 systemd 时其实不用自己轮转
如果服务由 systemd 管理,标准输出会被 journald 收走,轮转由 journald 负责:
# /etc/systemd/journald.conf
Storage=persistent
SystemMaxUse=1G
SystemMaxFileSize=100M
MaxRetentionSec=30day
这样就够了,不需要再配 logrotate。前提是应用往 stdout 写,而不是自己写文件。
推荐做法:应用只写 stdout,交给 journald 或容器运行时收集。应用自己管文件轮转,几乎总会出现「多进程抢同一个文件」「轮转后句柄没重开」的问题。
保留多久
由两个因素决定:磁盘容量和追溯需求。
- 排查故障:7 天足够;
- 安全审计:法规可能要求 6 个月;
- 成本敏感:热日志 7 天,冷归档压缩后存对象存储。
不要「全都留着」。日志无限增长的结果,往往是某天磁盘满了,服务挂了,而你还不知道为什么。
几个实操建议
别在循环里打日志。 一个循环一万次每次都 console.log,I/O 会把接口拖慢十倍。要么聚合后打一条,要么用采样。
错误日志要带上下文。 console.error(err) 只给了堆栈,没给「哪个用户、哪个订单」。用 logger.error({ err, orderId }, 'payment failed') 这种形式。
敏感信息必须脱敏。 密码、token、身份证、手机号,写进日志就是数据泄露。在日志库层面做统一的 redact 规则,比在每个调用点小心更可靠。
日志级别要能动态调整。 生产默认 info,排查时临时开到 debug。写死级别的服务,出事时只能重新发版。
收尾
一份能用的日志,满足四条:结构化、带请求 ID、有轮转、能按级别过滤。
这四条做到,故障排查的时间通常能从小时级降到分钟级。做不到,日志就只是磁盘占用的来源。
日志与隐私
日志里最常见的敏感信息不是密码,是手机号、邮箱、身份证号和地址。这些字段在业务日志里出现得极其自然:「用户 138**** 下单失败」。
合规要求通常是「最小必要」:排查需要知道「哪个用户」,不需要知道「他的手机号」。用内部 ID 代替,既够用又安全。
如果确实需要保留,就在写入前做脱敏。放在日志库层面统一处理,比在每个调用点记得脱敏可靠得多——人总会忘。
你认为这篇文章怎么样?
还没有表情反馈

一起聊聊
一个想法、一点补充,或一句简单的问候。
评论与回复
友善交流,彼此尊重第一句话,留给你。
读完有什么感受?欢迎成为第一个分享的人。