第3章 日志采集与解析
日志异常检测的第一步,不是算法,也不是模型——而是把日志「搞进来」并且「搞干净」。说白了,你连日志都收不齐、解析不对,后面再牛的算法也是白搭。这一章我们就把日志的源头、采集工具和常见格式彻底捋一遍。
3.1 日志来源
日志从哪来?我在生产环境里主要见过三种方式:Agent 主动采集、Syslog 协议接收、API 拉取。每种都有自己的脾气,选错了后面全是坑。
| 来源方式 | 原理 | 典型场景 | 我踩过的坑 |
|---|---|---|---|
| Agent 采集 | 在被监控机器上部署轻量进程,主动读取日志文件 | 应用日志、业务日志、容器日志 | 高并发下 Agent 缓冲区溢出导致丢日志 |
| Syslog 协议 | 网络设备或系统通过 UDP/TCP 514 端口发送日志 | 路由器、交换机、防火墙、Linux 系统日志 | UDP 丢包不重传,关键告警悄无声息就没了 |
| API 拉取 | 调用第三方平台或云服务的 REST API 获取日志 | 云服务(AWS CloudTrail、阿里云 SLS)、SaaS 平台 | API 限频 + 网络超时,数据出现小时级延迟 |
我的经验:Agent 采集是最稳定的方式,但一定要配好背压机制。我曾经在线上用 Filebeat 采集业务日志,流量峰值时没控速,直接把 ES 集群打挂了——因为 Agent 不会主动降速,你上层扛不住它就硬塞。
选 Syslog 时,我建议尽量用 TCP 而非 UDP。虽然 Syslog 协议默认用 UDP,但生产环境里 UDP 丢包你是感知不到的。我记得有次排查一个半夜的告警丢失问题,最后发现是 Syslog 的 UDP 包在核心交换机上被丢了,连个日志都没留下。
API 拉取最灵活,但也最不可控。我曾经因为第三方 API 的限流策略没搞清楚,导致采集程序跑一会儿就被封 IP,日志缺口好几个小时。后来老老实实加了指数退避重试,再也不敢硬闯了。
3.2 采集框架
日志来源搞定了,接下来要解决「怎么把散落在各地的日志统一收上来」。市面上工具不少,但真正在生产里经得住考验的,我个人首推 Filebeat 和 Logstash。它俩都属于 Elastic Stack,但定位完全不同。
| 特性 | Filebeat | Logstash |
|---|---|---|
| 语言 | Go(轻量、高性能) | JRuby(功能强但吃内存) |
| 资源占用 | 极小,5MB 内存起步 | 较大,默认 1GB 堆内存 |
| 数据处理能力 | 简单过滤、字段提取 | 复杂解析、过滤、转换、富化 |
| 输出能力 | 直接输出到 ES、Kafka、Logstash | 50+ 输出插件 |
| 适用场景 | 轻量采集 + 快速投递 | 复杂 ETL + 多下游分发 |
我个人的习惯是:采集层只用 Filebeat,把解析和处理的活留给 Logstash 或者 Kafka Streams。为什么?因为 Filebeat 真的太轻了,丢到几百台机器上几乎感觉不到它的存在。而 Logstash 如果直接跑在业务服务器上,一个不小心就把 CPU 吃满,运维同学会来找你聊天的。
曾经踩过的坑:有一次我把 Logstash 直接部署在应用服务器上,配置里写了十几个过滤规则,还加载了 GeoIP 数据库。结果业务高峰期 Logstash 内存飙到 4GB,直接把应用进程挤 OOM 了。从那以后,Logstash 我只放到独立的数据节点上,采集端一律用 Filebeat。
Filebeat 的配置很简洁,核心就三步:定义输入路径 → 加个简单处理 → 指定输出。下面是一个我常用的配置模板:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
fields:
app_name: my-service
env: production
output.logstash:
hosts: ["logstash01:5044", "logstash02:5044"]
loadbalance: true
Logstash 那边则负责「重活」——解析多行异常栈、拆字段、做数值转换、甚至调用外部 API 做富化。它的 pipeline 由 input → filter → output 三段组成,清晰但吃资源。
架构要点:从上图可以看出一条清晰的链路——三种日志来源经过 Filebeat 或 Logstash 采集处理后,最终以特定格式落地。你设计的检测系统必须覆盖整条链路,任何一个环节出错都会导致数据质量问题。
3.3 常见日志格式
日志采集上来之后,你得能「读懂」它。我见过最多的三种格式就是 JSON、CSV 和原始文本。选哪种格式,直接决定了你后面写解析规则的复杂度。
JSON 格式是我个人最喜欢的。结构清晰、自带字段名、解析器遍地都是。你想想看,一行 JSON 日志拿来就能直接塞进 ES 或数仓,多省事。
{
"timestamp": "2025-06-12T14:23:11.123Z",
"level": "ERROR",
"service": "user-service",
"trace_id": "abc-123-def-456",
"message": "数据库连接超时",
"duration_ms": 30500
}
CSV 格式在传统系统和网络设备里很常见。按列对齐,行结构固定,解析起来也简单。但有个问题——一旦某一列里出现了逗号或者换行符,整个解析就乱套了。我记得有次对接一个老系统的日志,CSV 的 message 字段里居然嵌了换行,结果每一条日志被拆成了三四行,排查了好久才发现是转义没处理好。
2025-06-12 14:23:11,ERROR,user-service,abc-123-def-456,数据库连接超时,30500
原始文本就是纯字符串,没有任何结构化约定。常见于遗留系统、嵌入式设备、或者开发人员随手打的日志。解析这种日志,说白了就是在跟正则表达式搏斗。我曾经为了解析一个老系统的日志,写了一个 80 多行的正则,跑了半年后业务方说格式改了——那一刻我真的想转行。
[2025-06-12 14:23:11] [ERROR] [user-service] 数据库连接超时 | trace=abc-123-def-456 | cost=30500ms
| 格式 | 可读性 | 解析难度 | 灵活性 | 我推荐的使用场景 |
|---|---|---|---|---|
| JSON | ⭐⭐⭐⭐⭐ | 低(自带结构) | 高(字段可扩展) | 微服务、云原生、新系统 |
| CSV | ⭐⭐⭐⭐ | 中(需处理转义) | 低(列固定) | 网络设备、监控指标、传统系统 |
| 原始文本 | ⭐⭐ | 高(全靠正则) | 中(格式一变就崩) | 遗留系统、嵌入式、临时采集 |
我的建议:如果你有权限决定日志输出格式,无脑选 JSON。它不仅是机器解析最友好的格式,而且对后续的异常检测算法也最友好——字段名即特征名,直接省掉一层特征工程。我曾经帮一个团队把原始文本改成 JSON 输出,解析代码从 200 行缩到了 10 行,检测准确率还升了 12%。
嗯,这里要注意一点:原始文本也不是完全不能用。如果日志量极大(每天几十 TB),JSON 的冗余字符会让存储和带宽成本飙升。这时候用原始文本 + 列式存储反而更经济。但代价就是解析复杂度全压在了消费端——你得自己写正则、自己维护 schema。
总结一下这章的核心:日志采集不是简单地把文件搬走,而是要把「对的数据」用「对的方式」送到「对的地方」。来源选错会丢数据,框架选错会压垮业务,格式选错会让你后面写算法时痛不欲生。把这章的内容吃透,后面讲异常检测特征提取的时候,你会回来感谢我的。
最后提醒一句:不管你用哪种方式采集、哪种格式存储,一定要保留原始日志的完整副本。我见过太多团队做了清洗和转换后就扔掉原始日志,结果发现清洗逻辑有 bug,数据已经无法回溯了。原始日志是你在黑暗中的最后一道保险绳。