第 2 章 常见日志源:系统、应用与数据库
要做日志汇聚,第一步就是搞清楚日志从哪来。很多人觉得不就是读个文件嘛?真上手才发现,每种日志源的脾气都不一样。Windows 和 Linux 的日志根本不是一个路子,Nginx 和 Tomcat 的格式也差得远。嗯,我把常见的日志源分成三大类,咱们一个一个聊。
2.1 系统日志:Windows Event Log 与 Linux Syslog
Windows Event Log 是 Windows 系统的亲儿子。它不存成文本文件,而是二进制格式(.evt/.evtx)。你不可能像 tail -f 一样直接读它。要采集?得用 WinRM、WEC(Windows Event Collector),或者干脆装个 Filebeat 用 API 拉取。
事件日志结构其实挺清晰的:
EventID—— 事件编号,比如 4625 是登录失败Level—— 严重级别:信息、警告、错误、严重Provider—— 来源,比如 Security、Application、SystemTimeCreated—— 时间戳Message—— 事件描述文本
我在项目中遇到过最坑的事:Windows 时间同步不准,导致事件时间戳和真实时间差了 8 小时。排查半天才发现是物理机 CMOS 电池没电了。所以,采集前一定先确认 NTP 配置。
Linux Syslog 就开放多了。它走 syslog 协议(RFC 5424),原生文本格式,一根管道就能传。现代发行版基本都用 rsyslog 或 syslog-ng。你打开 /var/log/messages 就能看到:
<34>Oct 11 14:32:15 hostname sshd[1234]: Failed password for root from 10.0.0.5
前头的 <34> 是设施(Facility)和级别(Severity)的编码。里面最关键的就是 Facility + Severity + 时间戳 + 主机名 + 进程名 + 消息内容。我习惯用 rsyslog 的模板功能把日志转成 JSON 格式,这样下游解析起来舒服很多。
避坑指南:我曾经在一个项目里,rsyslog 的 $template 写错了一个引号,结果所有日志都变成了“%msg%”开头… 嗯,配置 rsyslog 一定要删掉注释再测试。
| 维度 | Windows Event Log | Linux Syslog |
|---|---|---|
| 存储格式 | 二进制 .evtx | 纯文本 / 结构化 JSON |
| 采集协议 | WinRM / WEC / WMI | syslog / TCP / UDP / RELP |
| 时间可靠性 | 依赖系统时间 | 依赖系统时间 |
| 典型工具 | Filebeat Winlogbeat | rsyslog, syslog-ng, Filebeat |
| 常见坑 | 事件截断 >32KB 的消息 | UDP 丢包、时间格式乱 |
2.2 应用日志:Nginx 与 Tomcat
应用日志是审计日志里的重头戏,因为业务行为都记录在这。先说 Nginx。
Nginx 访问日志(access.log)默认是 combined 格式:
192.168.1.1 - - [10/Oct/2024:13:55:36 +0800] "GET /api/user HTTP/1.1" 200 1234 "-" "Mozilla/5.0"
字段顺序:客户端IP、时间、请求方法、URL、状态码、响应大小、Referer、User-Agent。你想想看,如果攻击者想遍历用户ID,从这些日志里一统计就出来了。我推荐在生产环境把日志改成 JSON 格式,这样采集端不用写一堆正则。
Tomcat 的日志就分两路了:catalina.out 记操作系统层输出和 JVM 信息,localhost_access_log 记 HTTP 请求。catalina.out 里 Java 的堆栈异常信息很全,但缺点是一旦出现 OOM,日志瞬间爆炸。我踩过这个坑:线上服务器 /var/log 写满,原因是 catalina.out 没配置日志轮转。
避坑指南:Tomcat 的 access log 默认不记录 POST 请求体。你想审计用户操作内容?那得自己写 Valve 或者用 Filter 记录。否则只能看到“发了什么请求”,看不到“发了什么数据”。
2.3 数据库日志:MySQL 与 PostgreSQL
数据库日志主要看三类:错误日志、慢查询日志、二进制日志(或 WAL)。
MySQL 的错误日志记录启动、停止、连接失败等。慢查询日志是关键——DBA 调优靠它,安全审计也靠它。慢查询日志里记录 SQL 语句、执行时间、锁等待时间。但是MySQL 默认不记录未使用索引的查询,你得手动开启 log_queries_not_using_indexes=ON。我见过一个案例:黑客用 sleep(10) 拖慢数据库,让慢查询日志里全是正常查询,掩盖真正的延时注入——所以光靠慢查询日志不够,还得结合 audit log 插件。
PostgreSQL 的日志默认写到 pg_log 目录下。它的 log_statement = 'all' 可以记录所有 SQL,但性能损耗很大。一般生产环境只开 ddl 或 mod。我更推荐用 pg_stat_statements 做性能分析,用 PostgreSQL 的 audit extension 做合规审计。
| 日志类型 | MySQL | PostgreSQL |
|---|---|---|
| 错误日志 | error.log | pg_log 文本 |
| 慢查询 | slow_query.log | 设置 log_min_duration_statement |
| 二进制日志/WAL | binlog (row/statement) | WAL |
| 审计日志 | Enterprise Audit Plugin | pg_audit |
| 采集方式 | Filebeat / Logstash | Filebeat / pgWAL 插件 |
时间戳时区陷阱
Nginx 日志默认用本地时间,MySQL 慢查询日志默认用 UTC。如果你不统一转化为 UTC,汇聚到中央平台后时序就跟乱麻一样。我习惯在采集端通过 Logstash 的 date 插件统一转成 UTC 时间戳。
2.4 日志源汇聚结构
下面这张图是我常用的一种汇聚架构。你看,系统日志、应用日志、数据库日志分别通过不同协议进入采集层,然后在汇聚平台中统一格式,最后落地到存储或分析引擎。
实践经验:我一般先用 Filebeat 做本地日志收集,它原生支持 Windows Event Log、Linux 命令行 tail、MySQL 慢查询日志等。如果遇到二进制格式的日志,比如 Windows 旧版 .evt 文件,就得上 Winlogbeat。总之,统一用 Beat 家族能省不少适配工作。
好了,这一章我把最常用的六种日志源都过了一遍。每种都有各自的脾性——有的固执于二进制,有的偏爱文本,有的需要特殊采集协议。在做汇聚方案时,先摸清它们的脾气,后面才能顺利地把它们拧成一股绳。