日志的艺术:日志级别与最佳实践
日志这东西,说白了就是程序的「黑匣子」。
我刚入行那会儿,觉得日志就是随便打印点东西,方便自己调试。直到有一次线上事故,日志全是一堆无意义的 DEBUG 信息,关键错误被淹没了。嗯,那次我被老板叫去喝茶了。
从那以后,我养成了一个习惯:把日志当成代码的一部分来设计。
日志级别:你的程序该说什么话
日志级别不是摆设。它决定了你的程序在什么情况下,该说什么话。
| 级别 | 含义 | 我什么时候用 |
|---|---|---|
| DEBUG | 调试信息 | 开发环境、定位问题时才打开。线上环境默认关闭。 |
| INFO | 关键流程 | 用户登录、订单创建、服务启动。这些信息要让人看得懂。 |
| WARN | 潜在风险 | 配置缺失但用了默认值、接口响应慢但没超时。别忽视它。 |
| ERROR | 明确故障 | 数据库连不上、空指针、业务校验失败。必须立刻处理。 |
我个人习惯,线上环境只开 INFO 及以上。DEBUG 日志太吵了,你想想看,每秒几万条日志,谁看得过来?
我曾经犯过的错: 把敏感信息(比如用户密码、身份证号)直接打到了 ERROR 日志里。结果日志文件被运维同事看到了……嗯,从那以后我加了个日志脱敏过滤器。
结构化日志:别让日志变成「天书」
传统的日志长这样:
2024-01-15 10:23:45 ERROR 用户下单失败:订单号12345,原因:库存不足
看着还行?但如果你要写脚本分析它,你就得写正则表达式去匹配「订单号」和「原因」。麻烦不说,还容易出错。
结构化日志就不一样了。它把信息拆成键值对:
{
"timestamp": "2024-01-15T10:23:45.123Z",
"level": "ERROR",
"service": "order-service",
"traceId": "abc-123-def",
"userId": 10086,
"orderId": "ORD20240115001",
"errorCode": "STOCK_INSUFFICIENT",
"message": "用户下单失败"
}
你看,这样多清晰。用 Elasticsearch 或者 Loki 一搜,直接就能定位到问题。
我推荐用 JSON 格式。大部分日志框架都支持,比如 Logback 的 JsonLayout,或者直接集成 logstash-logback-encoder。
小技巧: 每个请求都带上一个 traceId。这样你就能把一次请求的所有日志串起来。微服务架构下,这个尤其重要。
日志最佳实践:我踩过的坑,你别再踩了
这些年我总结了几条铁律,分享给你:
- 别打无意义的日志。 比如
logger.debug("进入方法")。这种日志除了占磁盘空间,一点用没有。 - 错误日志要带上上下文。 别只打「操作失败」。你得告诉我:哪个用户?哪个订单?什么原因?
- 日志别打得太频繁。 循环里打日志?小心你的磁盘 IO 被打满。我见过一个同事在 for 循环里打 DEBUG 日志,结果线上服务直接卡死。
- 日志文件要轮转。 按天、按大小切分。别让一个日志文件撑爆磁盘。
- 敏感信息必须脱敏。 手机号、身份证、密码,一律用
***替代。
核心原则: 日志是给人看的,也是给机器分析的。所以它既要可读,又要可解析。
知识体系:一张图看懂日志
下面这张图,是我自己画的。它把日志的核心逻辑串起来了:
你看,日志这件事,说简单也简单,说复杂也复杂。但只要你把上面这些点都做到位了,线上出问题的时候,你就能比别人快 10 倍定位到根因。
嗯,这就是日志的艺术。