日志系统设计:日志级别、格式规范与切割归档策略

日志这东西,说白了就是系统的「黑匣子」。数据回放和问题复现,没有一套好的日志系统,基本就是盲人摸象。我这些年踩过的坑,有一半都能归结到日志没设计好。

今天咱们就聊聊日志系统的三个核心要素:日志级别、格式规范、切割与归档。嗯,这三件事做好了,排查问题的效率至少翻一倍。

一、日志级别:DEBUG / INFO / WARN / ERROR

日志级别不是随便定的。我见过不少团队,线上环境开着 DEBUG 级别,结果一天下来日志文件几百个 G,真正有用的信息反而被淹没了。

我个人习惯,日志级别分四档就够了:

级别 含义 使用场景 线上是否开启
DEBUG 调试信息 开发阶段、问题复现时 ❌ 关闭
INFO 关键流程记录 数据回放开始/结束、关键节点 ✅ 开启
WARN 异常但不影响流程 数据格式异常、重试操作 ✅ 开启
ERROR 严重错误 数据丢失、流程中断 ✅ 开启

核心原则:线上环境只开 INFO 及以上。DEBUG 日志只在需要复现问题时动态开启。

我在项目中遇到过一个问题:数据回放时某个步骤偶尔失败,但 ERROR 日志里啥也没有。后来发现是同事把异常信息打在了 DEBUG 级别。你想想看,线上环境 DEBUG 是关的,等于白打。

避坑指南:我曾经因为日志级别设置不当,导致线上问题排查花了整整两天。后来我定了个规矩——所有可能影响数据完整性的异常,必须用 ERROR 级别输出。

二、日志格式规范

日志格式这件事,看似简单,其实门道不少。我见过最离谱的日志,就一行字符串,连时间戳都没有。这种日志,数据回放时根本没法用。

我建议的日志格式,包含以下字段:

  • 时间戳:精确到毫秒,带时区。比如 2025-01-15 14:23:45.678 +0800
  • 日志级别:用固定宽度,比如 [INFO]、[ERROR]
  • 线程/协程 ID:方便追踪并发问题
  • 请求追踪 ID:数据回放时,同一个回放请求的日志应该能串联起来
  • 类名/方法名:快速定位代码位置
  • 消息体:具体的日志内容

举个例子,我常用的格式是这样的:

2025-01-15 14:23:45.678 +0800 [INFO] [thread-12] [trace-abc123] com.example.ReplayService.startReplay - 数据回放开始,批次ID: batch-001

小技巧:请求追踪 ID 一定要在入口处生成,然后透传到整个调用链。数据回放时,通过这个 ID 就能把一次回放的所有日志串起来。我习惯用 UUID 或者雪花算法生成。

为什么格式这么重要?说白了,日志是给人看的,也是给工具分析的。格式统一了,你才能用 grep、awk 这些工具快速过滤。我见过有人日志格式三天两头变,结果写脚本分析日志时,每次都要改正则表达式,烦得很。

三、日志切割与归档策略

日志不切割,磁盘迟早会爆。我经历过一次线上事故,就是因为日志把磁盘写满了,服务直接挂了。嗯,从那以后,切割策略就成了我设计日志系统时的第一优先级。

3.1 切割策略

常见的切割方式有两种:

  • 按时间切割:每小时、每天、每周切一次。我推荐按天切割,兼顾了文件大小和查询方便。
  • 按大小切割:比如单个日志文件超过 500MB 就切。适合日志量不稳定的场景。

我个人习惯,两种策略结合使用:

# logback 配置示例
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>logs/replay.log</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>logs/replay.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
    <maxHistory>30</maxHistory>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
      <maxFileSize>500MB</maxFileSize>
    </timeBasedFileNamingAndTriggeringPolicy>
  </rollingPolicy>
</appender>

这个配置的意思是:每天切一次,但如果某天的日志超过了 500MB,就再切一个文件。保留最近 30 天的日志。

3.2 归档策略

日志不能只切不归档。我建议的归档策略:

  • 热数据:最近 7 天的日志,保留在本地磁盘,方便快速查询
  • 温数据:7 天到 30 天的日志,压缩后归档到对象存储(比如 S3、OSS)
  • 冷数据:超过 30 天的日志,归档到低成本存储,保留 6 个月到 1 年

注意:归档时一定要保留原始格式和目录结构。我见过有人归档时把文件名改了,结果想查某天的日志,找半天找不到。

知识体系总览

下面这张图,是我对日志系统设计的整体理解。你可以把它当作一个检查清单:

日志系统设计 日志级别 DEBUG / INFO WARN / ERROR 线上只开 INFO 及以上 日志格式 时间戳 + 级别 线程ID + 追踪ID 类名 + 消息体 切割与归档 按时间 / 按大小 热 / 温 / 冷 分层 保留策略 + 压缩 目标:快速定位问题,高效数据回放

这张图把日志系统设计的三个核心模块串起来了。你设计日志系统时,可以对照着检查:级别是否合理?格式是否统一?切割归档是否到位?

我的经验:日志系统设计好了,数据回放和问题复现的效率能提升 50% 以上。别在这上面省功夫,否则后面排查问题的时间,会让你后悔当初的偷懒。

好了,日志系统设计这块就聊到这儿。记住一句话:日志不是写给机器看的,是写给未来的自己看的。设计得好,未来的你会感谢现在的你。

可可精品资料库