一、日志分析基础:日志的作用与分类、常见日志格式、日志采集工具

做SRE这些年,我越来越觉得日志这东西就像飞机的黑匣子。平时没人搭理它,一出事所有人都在喊“快看日志”。说白了,日志就是系统运行时的“心电图”,记录着每一秒发生了什么、哪里不对劲。

我个人习惯是,接手一个新系统,第一件事不是看代码,而是先翻日志。日志里藏着的东西,比任何文档都真实。你想想看,代码可能撒谎,但日志不会。

1.1 日志的作用与分类

日志到底能干啥?我总结下来就三件事:

  • 故障排查:系统挂了,日志是第一现场。我记得有一次线上服务半夜报警,CPU飙到99%,查了一圈没头绪。最后翻nginx的access日志,发现某个接口的请求量突然暴涨了100倍——原来是爬虫在搞鬼。
  • 性能分析:响应慢、吞吐低,日志里的时间戳就是最好的“测速仪”。从请求进来、到处理、到返回,每一步的耗时都能从日志里抠出来。
  • 安全审计:谁在什么时候干了什么,日志一清二楚。合规检查的时候,日志就是你的“不在场证明”。

日志按来源分,大致有这几类:

分类 典型代表 我关注的点
应用日志 Java的log4j、Python的logging 异常堆栈、业务逻辑错误
访问日志 Nginx access log、Apache access log 请求量、响应时间、状态码分布
系统日志 /var/log/messages、dmesg OOM、磁盘I/O错误、内核panic
数据库日志 MySQL slow query log、PostgreSQL log 慢查询、死锁、连接数异常
中间件日志 Redis log、Kafka log 内存使用、队列积压、主从同步延迟
我的小建议:别把所有日志都往一个篮子里放。我习惯按“紧急程度”分三层——ERROR级别的单独收,WARN级别的按天归档,INFO级别的留一周就够了。不然磁盘爆了,你连哭的地方都没有。

1.2 常见日志格式

日志格式这东西,看着简单,但坑不少。我见过最离谱的,有人把日志写成了一行JSON,结果换行符没处理好,整条日志被截断了。嗯,这里要注意。

Apache/Nginx 的访问日志格式

先说最经典的Apache combined格式。说白了就是一行文本,用空格分隔各个字段:

192.168.1.1 - - [10/Oct/2024:13:55:36 +0800] "GET /api/users HTTP/1.1" 200 2326 "https://example.com" "Mozilla/5.0"

每个字段的含义:

  • 192.168.1.1 — 客户端IP
  • - - — 身份认证信息(通常为空)
  • [10/Oct/2024:13:55:36 +0800] — 请求时间
  • "GET /api/users HTTP/1.1" — 请求方法、路径、协议
  • 200 — 状态码
  • 2326 — 响应体大小(字节)
  • "https://example.com" — Referer来源
  • "Mozilla/5.0" — User-Agent

Nginx的格式和Apache几乎一样,只是多了几个字段。我个人习惯在Nginx日志里加上$request_time$upstream_response_time,这两个字段对性能分析太关键了:

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" $request_time $upstream_response_time';
避坑指南:我曾经在Nginx日志里忘了加引号,结果某个字段里带了空格,整行日志解析全乱套了。记住,所有可能包含空格的字段,一定要用引号包起来

JSON 格式日志

现在越来越多的应用开始用JSON格式写日志。为什么?因为好解析、好扩展。你想想看,一行文本格式的日志,想加个字段就得改解析规则,但JSON加个key就行了。

{
  "timestamp": "2024-10-10T13:55:36.123Z",
  "level": "ERROR",
  "logger": "com.example.UserService",
  "thread": "http-nio-8080-exec-3",
  "message": "数据库连接超时",
  "context": {
    "userId": "12345",
    "requestId": "abc-def-ghi",
    "duration": 5032
  },
  "stackTrace": "java.sql.SQLTimeoutException: ..."
}

JSON格式的好处很明显:

  • 结构化:每个字段都有明确的含义,不用猜
  • 可扩展:加字段不影响已有解析逻辑
  • 易查询:Elasticsearch里直接按字段搜索,效率高

但JSON也有缺点——体积大。同样的信息,JSON比文本格式大30%-50%。所以我的建议是:开发环境用JSON,生产环境用文本格式。或者折中一下,用Logstash的kv过滤器把文本转成JSON。

1.3 日志采集工具介绍

日志采集,说白了就是把分散在各台机器上的日志,统一收集到一个地方。我见过有人用scp手动拷贝的,也见过用rsync定时同步的。小规模还行,一旦上了百台机器,这些土办法就废了。

目前业界最主流的组合是 Filebeat + Logstash + Elasticsearch,也就是所谓的ELK栈。我重点说说前两个。

Filebeat:轻量级日志采集器

Filebeat是Elastic公司出的一个Go语言写的采集器。为什么选它?就一个字——。它占用的内存只有几十MB,CPU也几乎可以忽略不计。我曾在128MB内存的云服务器上跑过,稳得很。

Filebeat的核心逻辑很简单:

  1. 监听日志文件的变化(类似tail -f
  2. 读取新增的日志行
  3. 发送到指定的输出端(Logstash、Elasticsearch、Kafka等)

一个典型的Filebeat配置长这样:

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/nginx/access.log
  fields:
    service: nginx
    env: production

output.logstash:
  hosts: ["192.168.1.100:5044"]
我的经验:Filebeat有个“背压”机制——如果Logstash处理不过来,Filebeat会自动放慢采集速度,不会把日志弄丢。这个设计很聪明,我遇到过好几次Logstash挂了,Filebeat默默缓存日志,等恢复后自动续传,一条都没丢。

Logstash:日志处理管道

Logstash是ELK栈里的“数据加工厂”。它做的事情就是:收进来、洗干净、送出去

Logstash的架构是典型的管道模式:

输入(Input) → 过滤(Filter) → 输出(Output)

我画了一张图,帮你理解这个流程:

输入 Filebeat / TCP / UDP 过滤(Filter) grok 解析 mutate 转换 date 时间处理 输出 Elasticsearch / Kafka Logstash 管道处理流程

Logstash最强大的地方是它的过滤插件。我常用的几个:

  • grok:用正则表达式解析非结构化文本。比如把Nginx日志拆成IP、时间、URL等字段。说实话,grok的正则写起来挺痛苦的,但一旦写好,一劳永逸。
  • mutate:字段类型转换、重命名、删除。比如把字符串类型的数字转成整数,方便后面做聚合统计。
  • date:时间戳解析。日志里的时间格式五花八门,这个插件能把它们统一成ISO 8601格式。

一个Logstash配置示例:

input {
  beats {
    port => 5044
  }
}

filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
  }
  date {
    match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
    target => "@timestamp"
  }
  mutate {
    remove_field => ["message"]
  }
}

output {
  elasticsearch {
    hosts => ["http://localhost:9200"]
    index => "nginx-access-%{+YYYY.MM.dd}"
  }
}
注意:Logstash是Java写的,内存消耗比较大。我建议至少给Logstash分配2GB的堆内存。另外,如果日志量特别大(比如每秒几万条),可以考虑用Kafka做缓冲层,防止Logstash被冲垮。

小结

日志分析的第一步,就是把日志“管起来”。选对格式、用对工具,后面的事情才能顺起来。我个人觉得,Filebeat+Logstash这套组合拳,对于大多数场景已经够用了。如果你追求极致性能,可以试试用Vector或者Fluentd替代Logstash,但那是后话了。

记住一句话:日志不是用来存的,是用来查的。采集的时候多花点心思设计格式和字段,后面分析的时候能省十倍的时间。


专注资料整理