第 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、System
  • TimeCreated —— 时间戳
  • 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 LogLinux Syslog
存储格式二进制 .evtx纯文本 / 结构化 JSON
采集协议WinRM / WEC / WMIsyslog / TCP / UDP / RELP
时间可靠性依赖系统时间依赖系统时间
典型工具Filebeat Winlogbeatrsyslog, 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 做合规审计。

数据库日志对比
日志类型MySQLPostgreSQL
错误日志error.logpg_log 文本
慢查询slow_query.log设置 log_min_duration_statement
二进制日志/WALbinlog (row/statement)WAL
审计日志Enterprise Audit Pluginpg_audit
采集方式Filebeat / LogstashFilebeat / pgWAL 插件

时间戳时区陷阱

Nginx 日志默认用本地时间,MySQL 慢查询日志默认用 UTC。如果你不统一转化为 UTC,汇聚到中央平台后时序就跟乱麻一样。我习惯在采集端通过 Logstash 的 date 插件统一转成 UTC 时间戳。

2.4 日志源汇聚结构

下面这张图是我常用的一种汇聚架构。你看,系统日志、应用日志、数据库日志分别通过不同协议进入采集层,然后在汇聚平台中统一格式,最后落地到存储或分析引擎。

常见日志源汇聚关系图 Windows Event Log Linux Syslog Nginx 日志 Tomcat 日志 MySQL 日志 PostgreSQL 日志 日志汇聚平台 (Filebeat / Logstash / RSyslog) 存储 / 分析(Elasticsearch / ClickHouse) 虚线:需要协议转换(WinRM / syslog) 实线:直接文件 tail 或 JSON 传输

实践经验:我一般先用 Filebeat 做本地日志收集,它原生支持 Windows Event Log、Linux 命令行 tail、MySQL 慢查询日志等。如果遇到二进制格式的日志,比如 Windows 旧版 .evt 文件,就得上 Winlogbeat。总之,统一用 Beat 家族能省不少适配工作。

好了,这一章我把最常用的六种日志源都过了一遍。每种都有各自的脾性——有的固执于二进制,有的偏爱文本,有的需要特殊采集协议。在做汇聚方案时,先摸清它们的脾气,后面才能顺利地把它们拧成一股绳。