日志数据基础:日志的分类、格式与采集方式
做血缘分析,第一步就是跟日志打交道。我见过不少团队,一上来就搞解析、搞算法,结果发现日志本身质量不行——格式乱、字段缺、采集丢数据。说白了,地基没打好,楼盖得再高也得塌。
这一章,咱们就把日志的基础掰开揉碎讲清楚。你只有理解了日志的分类、格式和采集方式,后面做血缘分析才能顺手。
日志的分类
日志不是铁板一块。不同系统、不同用途的日志,记录的内容和侧重点完全不一样。我个人习惯把日志分成三大类:系统日志、应用日志、审计日志。
| 分类 | 典型来源 | 记录内容 | 血缘分析价值 |
|---|---|---|---|
| 系统日志 | 操作系统、中间件、数据库 | 进程启停、资源使用、错误信息 | 低(主要反映运行状态) |
| 应用日志 | 业务系统、微服务、大数据作业 | 业务操作、数据流转、异常堆栈 | 高(直接体现数据流向) |
| 审计日志 | 安全系统、数据库审计、IAM | 用户操作、权限变更、数据访问 | 中高(可追溯数据访问链路) |
系统日志
系统日志是最底层的。它告诉你服务器什么时候重启了、磁盘什么时候满了、数据库什么时候挂了。嗯,这些信息对运维很重要,但对血缘分析来说,价值有限。
不过,有一种情况例外——数据库的慢查询日志。我在项目中遇到过,通过分析慢查询日志里的 SQL 语句,可以反向推导出哪些表被频繁访问、数据是怎么关联的。这算是一种间接的血缘线索。
应用日志
应用日志才是血缘分析的主战场。业务系统每处理一笔数据,通常都会在日志里留下痕迹。比如一个数据导入任务,日志里会记录:
- 从哪个源文件读取数据
- 做了哪些清洗和转换
- 最终写入了哪个目标表
这些信息,就是血缘关系的直接证据。我建议你在设计应用日志时,尽量把数据流转的关键节点都打上日志。别怕日志多,怕的是该有的没有。
审计日志
审计日志比较特殊。它不是为了排查问题,而是为了满足合规要求。谁在什么时间、通过什么方式、访问了哪些数据——这些信息在数据安全领域特别重要。
做血缘分析时,审计日志可以帮你回答一个问题:这条数据到底被谁碰过? 我曾经帮一家金融客户做数据溯源,就是靠审计日志里的访问记录,才把一条敏感数据的泄露路径完整还原出来。
日志的格式
日志格式决定了你解析的难度。我见过最头疼的情况——同一个系统里,不同模块的日志格式居然不一样。你想想看,解析脚本得写多少适配逻辑?
目前主流的日志格式有三种:
文本格式
文本格式是最原始的。一行日志就是一段字符串,字段之间用空格、逗号或竖线分隔。举个例子:
2024-01-15 10:23:45 INFO DataImportJob - source: /data/input/orders.csv, target: dwd_orders, rows: 12500
这种格式的优点是人眼可读,缺点是对机器不友好。解析的时候得写正则表达式,字段顺序一变,解析就崩。我记得有一次,开发同事在日志里加了一个字段,结果我的解析脚本直接报错——排查了半天才发现是格式变了。
JSON 格式
JSON 格式是目前最推荐的。结构清晰、扩展性好、解析方便。同样的日志内容,用 JSON 写出来是这样的:
{
"timestamp": "2024-01-15T10:23:45.123Z",
"level": "INFO",
"logger": "com.example.DataImportJob",
"message": "数据导入完成",
"source": "/data/input/orders.csv",
"target": "dwd_orders",
"row_count": 12500,
"job_id": "job_20240115_001"
}
你看,字段名、字段类型一目了然。解析的时候直接用 JSON 反序列化就行,根本不用写正则。而且 JSON 支持嵌套结构,可以表达更复杂的关系——比如把上下游信息放在一个对象里。
结构化日志
结构化日志是 JSON 格式的升级版。它不仅仅是格式统一,还要求字段名、字段类型、字段含义都有明确的规范。比如时间戳统一用 ISO 8601 格式、日志级别统一用大写枚举值、业务字段统一加前缀。
我在团队里推行过一套结构化日志规范,效果很好。解析脚本只需要写一次,后面基本不用改。而且因为字段类型明确,做血缘分析时可以直接把日志字段映射到数据模型的属性上。
日志的采集方式
日志格式定好了,接下来就是怎么把日志从各个系统里收集起来。采集方式选不对,要么丢数据,要么影响业务性能。
常见的采集方式有三种:Agent、SDK、消息队列。
| 采集方式 | 原理 | 适用场景 | 优缺点 |
|---|---|---|---|
| Agent | 在服务器上部署采集进程,监听日志文件 | 传统应用、遗留系统 | 无侵入、部署简单;但资源占用较高 |
| SDK | 在应用代码中嵌入日志发送逻辑 | 新开发系统、微服务 | 灵活可控、性能好;但需要改代码 |
| 消息队列 | 日志先写入消息队列,再由消费者拉取 | 高并发、分布式系统 | 削峰填谷、解耦;但架构复杂 |
Agent 采集
Agent 是最传统的方式。在每台服务器上装一个采集程序(比如 Filebeat、Fluentd),它监听日志文件的变化,有新内容就读取并发送到中央存储。
这种方式的好处是无侵入——不需要改应用代码。对于遗留系统来说,这是唯一的选择。我遇到过一套十年前的 Java 系统,代码早就没人维护了,但日志还在写。用 Agent 采集,几分钟就搞定了。
但 Agent 也有缺点。它占用系统资源(CPU、内存、磁盘 IO),如果服务器本身负载就高,可能会影响业务。另外,Agent 挂了怎么办?日志会积压在本地,恢复后需要补采——这块逻辑处理不好,就容易丢数据。
SDK 采集
SDK 方式更现代。开发人员在代码里直接调用日志 SDK,把日志发送到指定的目标。比如 Java 的 Logback 配合 SocketAppender,或者 Python 的 logging 模块配合 HTTP Handler。
这种方式的好处是可控性强。你可以在代码里精确控制什么时候打日志、打什么内容、打多少。而且 SDK 通常支持异步发送,不会阻塞业务线程。
但代价也很明显——需要改代码。对于已经上线的系统,改代码意味着重新发布、重新测试,成本不低。我一般建议:新系统用 SDK,老系统用 Agent。
消息队列采集
消息队列方式适合大规模分布式系统。日志先写入 Kafka、RocketMQ 等消息队列,然后由消费者程序拉取并处理。
为什么用消息队列?说白了,就是为了削峰填谷。业务高峰期,日志产生速度可能远超处理速度。如果直接写入数据库,数据库扛不住。用消息队列缓冲一下,消费者慢慢消费,系统就稳了。
我在一个日处理 10 亿条日志的项目里,就是用的 Kafka 做采集中间层。效果很好,高峰期也没丢过数据。但要注意——消息队列本身也有延迟,对实时性要求高的场景,需要权衡。
知识体系总览
下面这张图,把日志分类、格式、采集方式的关系梳理清楚了。你可以把它当作本章的知识地图。
从图上你可以看到,日志分类、格式、采集方式三者是递进关系。先搞清楚日志属于哪一类,再统一格式,最后选采集方式。每一步都踩实了,后面的血缘分析才能顺风顺水。