4. 日志收集核心概念:日志格式、级别与策略
聊到日志收集,很多人第一反应就是「把日志存起来」。但说实话,如果一开始没把格式和级别规划好,后面排查问题会非常痛苦。我在好几个项目里都见过这种场景——日志倒是全量采集了,但一查问题,全是 INFO 级别的废话,真正的 ERROR 被淹没了。
这一节,我们就把日志的四个核心概念掰开揉碎讲清楚。嗯,都是基本功,但也是决定你日志系统好不好用的关键。
4.1 日志格式:JSON vs 文本
日志格式说白了就两种:纯文本和结构化(比如 JSON)。
纯文本日志长这样:
2025-06-15 10:23:45.678 ERROR [http-nio-8080-exec-3] com.example.OrderService - 订单 12345 处理失败:库存不足
这种格式人类可读性很好,用 grep 一把梭也能查。但一旦接入 ELK 或 Loki 这类系统,解析起来就费劲了——你得写正则表达式去提取时间、级别、类名、消息。
JSON 日志长这样:
{
"timestamp": "2025-06-15T10:23:45.678Z",
"level": "ERROR",
"logger": "com.example.OrderService",
"thread": "http-nio-8080-exec-3",
"message": "订单 12345 处理失败:库存不足",
"orderId": "12345",
"durationMs": 234
}
我个人习惯在生产环境强制使用 JSON 格式。为什么?因为字段是自描述的,采集端不需要写解析规则,直接就能把 orderId、durationMs 这些字段提取出来做聚合分析。
4.2 日志级别:DEBUG、INFO、WARN、ERROR
日志级别是个老生常谈的话题,但我在项目中见过太多「级别滥用」的情况。说白了,级别就是用来控制日志输出量的开关。
| 级别 | 含义 | 生产环境建议 |
|---|---|---|
| DEBUG | 调试信息,开发用 | 关闭,除非排查特定问题 |
| INFO | 正常流程信息 | 开启,但别滥用 |
| WARN | 潜在问题,不影响运行 | 开启,用于预警 |
| ERROR | 错误,需要人工介入 | 必须开启,触发告警 |
我曾经接手过一个项目,代码里到处都是 logger.info("进入方法") 和 logger.info("退出方法")。结果一天产生了几十 GB 的日志,真正有用的 ERROR 信息反而找不到了。这就是典型的级别滥用。
我的原则很简单:
- DEBUG:只在你开发调试时用,上线前检查一遍,该删的删,该降级的降级。
- INFO:记录关键业务流程的起止,比如「订单创建成功」「支付回调到达」。别把循环里的每次迭代都打 INFO。
- WARN:记录那些「虽然没报错,但不太对劲」的情况。比如重试了 3 次才成功,或者配置项使用了默认值。
- ERROR:必须记录异常堆栈和上下文信息。我习惯在 ERROR 日志里带上请求 ID 和关键参数,方便复现。
4.3 结构化日志 vs 非结构化日志
结构化日志,说白了就是「机器能直接解析的日志」。JSON 是典型代表,但也不限于 JSON——比如 Logstash 格式、GELF 格式也算。
非结构化日志就是纯文本,靠正则或者人工去看。
我为什么强调结构化?给你看个对比:
非结构化日志(文本):
2025-06-15 10:23:45 ERROR 订单 12345 处理失败,耗时 234ms
结构化日志(JSON):
{
"level": "ERROR",
"message": "订单处理失败",
"orderId": "12345",
"durationMs": 234,
"service": "order-service",
"traceId": "abc123"
}
你看,结构化日志里每个字段都是独立的。在 Kibana 里,你可以直接按 orderId 搜索,按 durationMs 排序,甚至做聚合统计——「今天所有耗时超过 1 秒的订单有哪些?」。非结构化日志要做到这些,你得先写正则把字段抠出来。
我在项目中遇到过一个典型案例:某次线上故障,需要查某个用户的所有操作记录。因为日志里带了 userId 字段,我在 Elasticsearch 里一秒就过滤出来了。如果是纯文本,你得 grep 半天,还容易漏。
4.4 日志轮转与保留策略
日志如果不轮转,磁盘迟早会被写满。这可不是危言耸听——我见过不止一次因为日志把根目录写满,导致服务直接挂掉的惨案。
日志轮转就是按大小或时间切分日志文件。比如:
- 按大小:每个日志文件 100MB,满了就新建一个
- 按时间:每小时或每天生成一个新文件
- 按数量:只保留最近 7 个文件,旧的自动删除
常见的轮转配置(以 Logback 为例):
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/var/log/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
这个配置的意思是:每天生成一个日志文件,保留最近 30 天。
保留策略要考虑几个因素:
- 合规要求:金融行业可能要求保留 180 天甚至更久
- 存储成本:日志量大的话,保留 30 天可能就要几 TB
- 查询需求:最近 7 天的日志最常查,可以放热存储;更早的放冷存储或归档
嗯,到这里日志的核心概念就讲完了。说白了,格式决定了解析成本,级别控制了日志量,结构化让查询变得简单,轮转和保留策略则保证了系统的稳定性。下一节我们开始实战——怎么用 Filebeat 把日志采集到 Elasticsearch。