日志处理基础:格式、级别、采集与存储
日志处理这件事,说白了就是给系统装个黑匣子。我做了这么多年后端,见过太多线上事故——没有日志,你连死因都查不出来。今天咱们就把日志处理的基础打扎实。
日志格式解析:别让日志变成天书
日志格式,我习惯把它分成三类:无结构、半结构、结构化。你想想看,如果日志全是自由文本,解析起来得多痛苦?
| 类型 | 示例 | 解析难度 | 适用场景 |
|---|---|---|---|
| 无结构 | 2024-01-15 10:30:00 error timeout |
高 | 临时调试 |
| 半结构 | 2024-01-15 10:30:00 [ERROR] request_id=12345 msg="timeout" |
中 | 通用日志 |
| 结构化 | {"time":"2024-01-15T10:30:00Z","level":"ERROR","rid":"12345","msg":"timeout"} |
低 | 大数据分析 |
我个人强烈推荐结构化日志。为什么?因为 JSON 格式天然支持嵌套字段,解析起来几乎零成本。我在项目中遇到过,团队用无结构日志跑了半年,后来要做日志分析,光写正则就花了两周——血的教训。
核心原则:日志格式越规范,后续处理越省心。结构化日志是增量计算的基础,因为你可以直接按字段做聚合、过滤、关联。
日志级别:别什么都往日志里塞
日志级别这事,看似简单,但很多人用不好。我见过有人把 DEBUG 日志打到生产环境,结果一天产生 200GB 日志,磁盘直接爆了。
标准级别从低到高:TRACE → DEBUG → INFO → WARN → ERROR → FATAL。嗯,这里要注意,不是所有级别都要在生产环境开启。
- TRACE:最细粒度,一般只在开发环境用。我建议别在生产环境开,除非你在追一个极其诡异的 bug。
- DEBUG:调试信息,开发环境常用。生产环境慎用,除非你明确知道自己在干什么。
- INFO:正常业务流程记录。比如请求开始、结束、关键状态变更。
- WARN:潜在问题,但系统还能继续运行。比如重试、降级、限流触发。
- ERROR:明确错误,需要人工介入。比如数据库连接失败、第三方接口超时。
- FATAL:致命错误,系统无法继续运行。比如内存溢出、配置错误导致启动失败。
避坑指南:我曾经在生产环境把日志级别设成 DEBUG,结果日志量暴增 50 倍,直接拖垮了日志采集管道。从那以后,我定了个规矩——生产环境默认 INFO,需要调试时按服务粒度临时调整,用完立刻改回来。
日志采集工具:Filebeat vs Flume
采集工具的选择,说白了就是看你的场景。我两个都用过,各有千秋。
Filebeat:轻量级采集器
Filebeat 是 Elastic 家的产品,主打轻量、简单。它用 Go 写的,资源占用极低,适合部署在每台机器上。
# filebeat.yml 配置示例
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
fields:
app: my-service
env: production
output.elasticsearch:
hosts: ["http://elasticsearch:9200"]
index: "app-logs-%{+yyyy.MM.dd}"
我个人习惯用 Filebeat 做边缘采集。它有几个优点:自动处理日志轮转、支持多行日志合并、内置背压机制。我在项目中遇到过,日志文件被 logrotate 切分时,Filebeat 能无缝衔接,不会丢数据。
Flume:企业级数据管道
Flume 是 Apache 家的,功能更强大,但配置也更复杂。它支持 Source、Channel、Sink 三层架构,可以做复杂的路由和转换。
# flume.conf 配置示例
agent.sources = tail-source
agent.channels = memory-channel
agent.sinks = hdfs-sink
agent.sources.tail-source.type = spooldir
agent.sources.tail-source.spoolDir = /var/log/app
agent.sources.tail-source.channels = memory-channel
agent.channels.memory-channel.type = memory
agent.channels.memory-channel.capacity = 10000
agent.sinks.hdfs-sink.type = hdfs
agent.sinks.hdfs-sink.hdfs.path = /logs/app/%Y/%m/%d
agent.sinks.hdfs-sink.channel = memory-channel
Flume 的优势在于:支持事务保证、可自定义拦截器、能对接多种存储。但缺点也很明显——Java 写的,内存占用高,配置繁琐。
| 对比维度 | Filebeat | Flume |
|---|---|---|
| 语言 | Go | Java |
| 资源占用 | 低(约 10-30MB) | 高(约 200-500MB) |
| 配置复杂度 | 低 | 中高 |
| 事务保证 | 至少一次 | 精确一次(可配置) |
| 适用场景 | 边缘节点采集 | 中心化数据管道 |
我的建议:小规模场景(几十台机器)用 Filebeat 就够了。大规模场景(几百台以上)或者需要复杂 ETL 时,用 Flume 更合适。我现在的做法是 Filebeat 采集 + Kafka 中转 + Flume 消费,各取所长。
日志存储选型:存哪?怎么存?
日志存储选型,核心看三个维度:写入速度、查询能力、存储成本。你想想看,如果每天产生 TB 级日志,存 Elasticsearch 成本太高,存 HDFS 查询又慢。
我按场景把存储方案分成三类:
- 实时查询场景:Elasticsearch。适合日志分析、故障排查。写入快,查询灵活,但存储成本高。
- 离线分析场景:HDFS / 对象存储(S3、OSS)。适合批量计算、长期归档。成本低,但查询延迟高。
- 流式处理场景:Kafka。适合实时计算、数据中转。不持久化,但吞吐量极高。
我在项目中遇到过,团队把所有日志都往 ES 里塞,结果集群规模从 3 节点膨胀到 20 节点,成本翻了 6 倍。后来我们改了策略——近 7 天的日志放 ES,7 天以上的归档到 OSS,查询时按时间范围路由。成本直接降了 70%。
存储选型口诀:热数据用 ES,温数据用对象存储,冷数据用 HDFS。别把所有鸡蛋放一个篮子里。
知识体系总览
下面这张图,把日志处理的基础框架串起来了。从日志产生到最终存储,每一步都有讲究。
这张图把日志处理的四个核心环节串起来了。从日志产生开始,经过格式解析、级别控制、工具采集,最终落到存储层。每个环节的选择,都会影响后续增量计算的效率。说白了,基础打不好,后面再牛的算法也白搭。