第四讲:日志格式化与标准化——ELK Stack基础、字段规范、JSON格式
做审计告警,最怕什么?我个人觉得,最怕日志不规范。
你想想看,日志格式五花八门,有的用空格分隔,有的用逗号,有的干脆是自由文本。告警规则写得再好,解析器读不懂,一切都白搭。这就像盖房子,砖头大小都不一样,你图纸画得再漂亮也砌不上去。
所以,咱们这一章聊聊怎么把日志“捋顺”。核心就三件事:搞懂ELK这三大件儿、统一字段命名、用JSON结构化。
4.1 ELK Stack:日志从产生到告警的流水线
ELK不是一门技术,是一套组合。说白了,就是做日志采集、存储、搜索和可视化的三个工具串在一起。
- Elasticsearch:存数据的仓库。全量索引,秒级检索。
- Logstash:干活的老黄牛。收日志、解析、过滤、格式化,最后吐给ES。
- Kibana:可视化界面。查日志、画报表、配置告警都在这里。
我记得刚接触ELK时,总把Logstash当作一个简单的转发器。后来踩了坑才发现,Logstash真正的价值在于解析和标准化。
4.1.1 从原始日志到可分析的JSON
原始日志长什么样?举个例子:
2025-03-21 10:15:30 ERROR user_id=1234 action=login result=failed msg="Invalid password"
这是一条典型的半结构化文本。人读着还行,计算机处理起来就头疼了。我们需要解析它,变成标准的JSON字段。
Logstash里配一个grok插件就能搞定:
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:log_level} user_id=%{NUMBER:user_id} action=%{WORD:action} result=%{WORD:result} msg=\"%{GREEDYDATA:message}\"" }
}
}
解析后变成:
{
"timestamp": "2025-03-21T10:15:30.000Z",
"log_level": "ERROR",
"user_id": 1234,
"action": "login",
"result": "failed",
"message": "Invalid password"
}
嗯,到这里,机器就能很舒服地处理了。而且所有字段都变成了结构化数据,索引效率也高。
4.2 日志字段规范——你得有个标准
光有JSON格式还不够,字段叫什么名字也很重要。我在项目中遇到过这样的情况:A系统用“userId”,B系统用“uid”,C系统用“user_id”。到了告警规则里,同一个用户查询得写三个条件,简直崩溃。
所以,团队内部必须约定一套通用字段规范。我建议直接参考Elastic Common Schema(ECS),这是Elastic官方定义的一套标准字段命名方式。
| 字段类别 | 推荐字段名 | 说明 | 示例值 |
|---|---|---|---|
| 时间戳 | @timestamp | 事件发生时间,UTC格式 | 2025-03-21T10:15:30.000Z |
| 日志级别 | log.level | 标准日志级别 | ERROR, WARN, INFO |
| 用户标识 | user.id | 用户唯一ID | user_12345 |
| 动作类型 | event.action | 具体操作名 | login, logout, delete |
| 结果状态 | event.outcome | 操作结果 | success, failure |
| 源IP | source.ip | 请求来源IP | 192.168.1.10 |
| 目标对象 | event.target | 操作对象ID | file_987, order_666 |
| 错误信息 | error.message | 详细错误描述 | Invalid password |
4.3 JSON格式——为什么非它不可?
JSON是结构化数据的事实标准。为什么?简单说,就是易于解析、层次清晰、扩展性好。
- 易于解析:Elasticsearch、Logstash、Kibana原生支持JSON,不需要额外写解析器。
- 层次清晰:JSON支持嵌套。比如一个告警事件可以包含“用户信息”、“操作详情”、“错误信息”三个子对象,结构一目了然。
- 扩展性好:新增字段不影响已有解析。你今天加一个“source.region”,解析器不会报错。
举个例子,一个标准的审计日志JSON应该长这样:
{
"@timestamp": "2025-03-21T10:15:30.000Z",
"log.level": "ERROR",
"user": {
"id": "user_12345",
"role": "admin"
},
"event": {
"action": "delete",
"category": "database",
“outcome”: “failure”
},
"source": {
"ip": "10.0.0.1",
"geo": {
"country": "CN",
"city": "Beijing"
}
},
"error": {
"message": "Insufficient permissions to delete table 'orders'",
"code": 403
}
}
这样一份日志,Elasticsearch会自动映射字段类型。写告警规则时,你直接查 event.outcome:failure 和 log.level:ERROR 就完事了,非常顺滑。
4.4 一张图看懂日志标准化流程
为了让你更直观地理解从原始日志到告警的可视化流程,我画了下面这张流程图。
一句话总结这个流程:原始日志就像一堆散乱的砖头,定义好字段规范(砖头的尺寸),用JSON格式化(把砖头砌成标准块儿),Logstash就是你的泥瓦匠,Elasticsearch是仓库,Kibana是监控室。
4.5 我的几点实操建议
- 前期花时间在设计字段上:别嫌麻烦。你定义得越清晰,后面写告警规则就越轻松。
- 统一时区很重要:所有时间戳都转成UTC。Kibana展示时再转本地时间。我曾经因为时区不一致,告警触发早了8个小时,排查了好久才发现是时间戳没归一。
- 字段类型要提前规划:比如
user.id到底是字符串还是数字?如果是user_12345这种,就必须是字符串。否则Elasticsearch自动映射成数字,查询就会出错。
好了,日志格式化这部分的核心就这些。把砖头烧好了,后面的楼才好盖。