日志级别与分类:DEBUG、INFO、WARN、ERROR、FATAL 的定义与使用场景

日志级别这东西,说白了就是给日志信息贴个标签。告诉看日志的人——这条消息有多严重,该不该立刻处理。

我刚入行那会儿,觉得日志嘛,能打出来就行。结果有一次排查线上问题,满屏都是 INFO,真正关键的 ERROR 被淹没了。从那以后,我才意识到级别划分有多重要。

协议栈里,日志级别通常分五档。从低到高依次是:DEBUG、INFO、WARN、ERROR、FATAL。咱们一个一个说。

DEBUG:开发者的放大镜

DEBUG 级别的日志,只在开发和调试阶段打开。它记录的是最细碎的信息——变量值、函数入口出口、循环次数、状态机跳转细节。

举个例子,你在调试 RRC 连接建立流程:

// 伪代码示例
log_debug("RRCConnectionRequest received, cause=%d, ue_id=%s", cause, ue_id);
log_debug("Entering state: RRC_CONN_SETUP_PENDING");
log_debug("T300 timer started, expiry=%d ms", t300_value);

这些信息在生产环境绝对不能开。为什么?

  • 量太大——一秒能刷几千条,磁盘瞬间写满
  • 影响性能——频繁 I/O 操作会拖慢协议栈处理速度
  • 暴露细节——内部变量、内存地址可能被恶意利用
我的习惯:DEBUG 日志只在本地开发环境或实验室开启。线上出问题时,我会单独给某个模块开 DEBUG,定位完立刻关掉。

INFO:正常流程的标记桩

INFO 级别记录的是协议栈正常运行时的关键节点。比如连接建立成功、切换完成、定时器超时后正常处理。

它不表示任何异常,只是告诉你——系统走到这一步了。

log_info("UE context setup complete, RNTI=0x%04x", rnti);
log_info("Handover successful, target cell_id=%d", cell_id);

INFO 日志在生产环境是默认开启的。它用来回答一个最基本的问题:系统现在在干什么?

我记得有一次排查一个小区接入失败的问题。看 INFO 日志发现,UE 的 Attach Request 到了 MME,但 MME 没有回 Attach Accept。这就把问题范围缩小到了核心网侧,而不是空口。

WARN:值得警惕的异常

WARN 表示系统遇到了异常情况,但还能继续运行。它不影响当前功能,但可能埋下隐患。

协议栈里常见的 WARN 场景:

  • 重传次数超过阈值但还没到最大限制
  • 收到格式异常的协议报文,但还能解析
  • 资源池使用率超过 80%
  • 定时器超时后重试成功
log_warn("RLC retransmission count=%d, threshold=%d", retx_count, max_retx);
log_warn("SIB1 decoding failed, retrying... attempt=%d", attempt);
我曾经踩过的坑:有个同事把所有 WARN 都当 INFO 处理,觉得"反正还能跑"。结果某天资源池耗尽,整站瘫痪。复盘时发现 WARN 日志已经连续刷了三天,没人关注。WARN 就是警报器,响了就该去看。

ERROR:功能受损,必须介入

ERROR 表示某个功能已经无法正常执行。协议栈会尝试恢复,但用户可能已经感知到服务中断。

典型的 ERROR 场景:

  • RRC 连接建立失败
  • 安全模式命令失败
  • SCTP 链路中断
  • 内存分配失败
log_error("RRC connection setup failed, cause=%s", failure_cause);
log_error("SCTP association lost, stream_id=%d", stream_id);

ERROR 日志必须包含足够的信息用于定位。我个人要求团队在 ERROR 日志里至少带上:

  1. 错误码或失败原因
  2. 相关的 UE ID 或连接标识
  3. 当前状态或上下文

光写一句 "RRC setup failed" 等于没写。谁 failed?为什么 failed?在哪个小区?这些信息缺一不可。

FATAL:系统崩溃前的最后遗言

FATAL 是最严重的级别。系统遇到了不可恢复的错误,协议栈即将终止或重启。

什么情况会触发 FATAL?

  • 断言失败
  • 关键数据结构损坏
  • 看门狗超时
  • 底层硬件报错
log_fatal("Assertion failed: pdu != NULL, file=%s, line=%d", file, line);
log_fatal("Watchdog timeout, stack will restart");
关键原则:FATAL 日志必须包含完整的调用栈和上下文快照。这是系统崩溃前最后一次说话的机会,一定要把话说清楚。

你想想看,系统都挂了,你只留一句 "FATAL error occurred"。那跟没留有什么区别?

级别对比速查

级别 含义 生产环境 典型场景
DEBUG 调试信息 关闭 变量值、函数调用、状态跳转
INFO 正常流程 开启 连接建立、切换完成、定时器处理
WARN 异常但可恢复 开启 重传超阈值、资源紧张、重试成功
ERROR 功能失败 开启 连接失败、链路中断、内存分配失败
FATAL 系统崩溃 开启 断言失败、数据结构损坏、看门狗超时

日志级别的选择原则

我总结了一个简单的判断方法:

  • 这条日志对排查问题有帮助吗?——没有就别打
  • 这条日志正常运行时也会出现吗?——是就 INFO,否则 DEBUG
  • 出现这条日志需要人关注吗?——需要就 WARN 或 ERROR
  • 系统还能继续跑吗?——能就 ERROR,不能就 FATAL

嗯,这里要注意一点。同一个事件在不同阶段可能用不同级别。比如重传:第一次重传可以打 DEBUG,超过阈值打 WARN,达到最大次数后打 ERROR。这叫级别递进,很实用。

日志级别与排查效率

日志级别选对了,排查效率能翻倍。选错了,就是灾难。

我见过一个项目,所有日志都用 INFO。结果线上出问题,日志文件 2GB,根本没法看。后来改成按级别分类,排查时间从小时级降到了分钟级。

还有一个项目,FATAL 日志里只写了 "FATAL"。系统崩溃了,连原因都不知道。这跟没打日志有什么区别?

我的建议:团队内部定一个日志规范。什么场景用什么级别,写清楚。新人也照着做,避免出现"全 INFO"或"全 ERROR"的极端情况。

下面这张图,帮你快速理解五个级别的关系和流向:

日志级别分类与处理流向 DEBUG INFO WARN ERROR FATAL 生产环境 DEBUG:关闭 INFO/WARN/ERROR:开启 FATAL:必须开启 处理方式 DEBUG/INFO:记录即可 WARN:需关注并排查 ERROR/FATAL:立即处理

从 DEBUG 到 FATAL,严重程度递增,日志量递减。DEBUG 最多,FATAL 最少。这个金字塔结构,你心里要有数。

好了,日志级别就讲到这里。记住一句话:选对级别,比打日志本身更重要。