1. 日志基础:日志是什么、为什么重要、日志级别详解

大家好,我是老张。今天咱们聊聊日志——这个看似简单,却让无数系统栽过跟头的基础话题。

先问个问题:你遇到过线上系统出问题,翻遍所有日志文件,结果发现要么啥都没记,要么记了一堆没用的信息吗?我遇到过,还不止一次。有一次凌晨三点被叫起来处理故障,打开日志一看,全是 DEBUG 级别的垃圾信息,真正有用的 ERROR 反而被淹没了。那感觉,真叫一个绝望。

所以,日志这事,真得好好说道说道。

1.1 日志到底是什么?

说白了,日志就是系统运行时的「黑匣子」。它记录着系统在什么时间、什么位置、发生了什么事件。

我习惯把日志比作「系统的体检报告」。你想想看,人每年都要体检,通过各项指标判断身体是否健康。系统也一样,通过日志来判断它是否在正常工作。

一个完整的日志条目,通常包含这些信息:

  • 时间戳:精确到毫秒甚至微秒的事件发生时间
  • 日志级别:这条日志的严重程度
  • 来源:哪个模块、哪个类、哪个方法产生的
  • 线程信息:哪个线程在执行
  • 消息内容:具体发生了什么
  • 异常堆栈:如果有异常,完整的调用链

核心观点:日志不是写给机器看的,是写给人看的。写日志的时候,要想着「如果三个月后的我看到这条日志,能立刻明白当时发生了什么」。

1.2 为什么日志如此重要?

你可能觉得,日志不就是记录点信息嘛,能有多重要?

嗯,我给你讲个真实案例。我之前负责过一个电商平台,有一次大促期间,用户下单后一直收不到确认短信。运维团队查了整整两个小时,最后发现是短信网关的超时时间设置得太短了。怎么发现的?就是靠日志里一条不起眼的 WARN 级别记录:「短信发送超时,重试第1次」。

如果没有这条日志,我们可能还在怀疑是网络问题、数据库问题、甚至用户手机问题。这就是日志的价值——它帮你把「猜测」变成「确认」。

日志的重要性,我总结为三点:

  1. 故障排查:系统出问题时,日志是第一手证据
  2. 性能分析:通过日志可以分析响应时间、吞吐量等指标
  3. 安全审计:谁在什么时间做了什么操作,日志一清二楚

我的习惯:每次上线新功能,我都会先看一遍日志输出。如果发现该记的没记,不该记的记了一大堆,我会立刻要求开发改。别等到出事了再后悔。

1.3 日志级别详解

日志级别这东西,看起来简单,但用对的人真不多。我见过不少项目,所有日志都用 INFO,或者干脆全用 ERROR。这其实是个大坑。

咱们一个一个说:

DEBUG

DEBUG 级别的日志,是给开发人员调试用的。它记录的是「程序执行到哪一步了」「这个变量的值是多少」这类细节信息。

我个人习惯,DEBUG 日志只在开发环境和测试环境开启。线上环境?除非你在排查一个特别诡异的问题,否则千万别开。我曾经见过一个系统,线上开了 DEBUG 日志,结果一天产生了 200GB 的日志文件,直接把磁盘撑爆了。

避坑指南:我曾经因为线上开了 DEBUG 日志,导致系统性能下降 30%。原因是日志输出太多,I/O 成了瓶颈。从那以后,我定了个规矩:线上环境默认只开 INFO 及以上级别。

INFO

INFO 是「信息」的意思。它记录的是系统正常运行时的关键节点。比如「用户登录成功」「订单创建完成」「定时任务开始执行」。

INFO 日志要把握好度。记太多了,日志文件会膨胀;记太少了,出了问题又找不到线索。我的经验是:每个业务操作的关键步骤记一条 INFO 就够了

WARN

WARN 是「警告」。它表示系统遇到了一个「不太正常但还能继续运行」的情况。

举个例子:用户请求的某个参数不合法,系统用了默认值代替。这种情况不需要报错,但应该记录下来,方便后续排查。

WARN 级别的日志,我建议重点关注。因为它往往是问题的「前兆」。如果你发现某个 WARN 日志出现的频率突然升高,那很可能系统正在走向崩溃。

ERROR

ERROR 是「错误」。它表示系统遇到了一个「功能无法正常完成」的问题。

比如数据库连接失败、第三方接口返回异常、业务逻辑校验不通过。这些都应该记 ERROR 日志。

注意:ERROR 日志一定要包含完整的异常堆栈信息。光记一句「操作失败」是没用的,你得知道失败的原因是什么。

重要提醒:ERROR 日志不等于系统崩溃。它只是表示某个功能点出了问题。系统可能还在运行,但功能已经受损了。

FATAL

FATAL 是「致命错误」。它表示系统已经无法继续运行了,必须立即停止。

比如配置文件加载失败、核心服务不可用、内存溢出。遇到 FATAL 级别的日志,通常意味着系统需要重启或者人工介入。

说实话,我在生产环境中很少看到 FATAL 日志。因为一旦出现,系统基本就挂了。但该记还是要记,这是最后一道防线。

1.4 日志级别的选择原则

说了这么多,到底该怎么选日志级别?我给大家一个简单的判断标准:

级别 什么时候用 举个例子
DEBUG 开发调试,排查问题 「SQL 执行耗时:15ms」
INFO 业务关键节点 「用户 12345 下单成功,订单号:20240301001」
WARN 异常但可恢复 「缓存未命中,回查数据库」
ERROR 功能失败 「数据库连接超时,重试 3 次后放弃」
FATAL 系统不可用 「配置文件加载失败,系统退出」

我的建议:写日志的时候,问自己一个问题——「如果这条日志是最后一条,我能根据它定位问题吗?」如果答案是「不能」,那就重写。

1.5 日志格式规范

最后说说日志格式。很多团队不重视这个,结果就是每个人的日志风格都不一样,查起来特别费劲。

我推荐一个通用的日志格式:

[时间] [级别] [线程名] [类名:行号] - [消息内容]
[异常堆栈]

举个例子:

[2024-03-01 14:30:22.123] [ERROR] [http-nio-8080-exec-1] [com.example.OrderService:56] - 订单创建失败,订单号:20240301001
java.sql.SQLTimeoutException: 等待数据库连接超时
    at com.example.OrderService.createOrder(OrderService.java:56)
    at com.example.OrderController.submit(OrderController.java:23)
    ...

这个格式的好处是:一眼就能看到时间、级别、位置和原因。配合日志分析工具,可以快速定位问题。

注意:不要记录敏感信息,比如密码、身份证号、银行卡号。我曾经见过一个项目,日志里直接打印了用户的明文密码,这要是泄露出去,后果不堪设想。

好了,日志基础就讲到这里。下一章咱们聊聊「日志框架的选择与配置」,到时候我会分享一些实际项目中的踩坑经验。