系统日志结构详解:三大日志体系全掌握

日志这东西,说白了就是系统的黑匣子。密钥同步出问题的时候,你先翻的肯定是日志。但日志格式五花八门,不搞清楚结构,你连从哪儿查起都不知道。

我干了这么多年运维,见过太多人一上来就 tail -f,然后被一堆乱码似的字符串吓退。其实啊,现代 Linux 系统主要就三种日志体系:传统的 syslog、增强版的 rsyslog、还有新时代的 journald。搞懂它们,你就握住了排障的钥匙。

核心观点: 密钥同步故障排查路径 = 知道日志在哪 → 看懂日志格式 → 用对工具筛选 → 定位根因。而这一切都从理解日志结构开始。
Linux 日志体系核心结构 应用程序 / 服务 系统内核 / 驱动 网络设备 / 其他 Syslog 协议层(RFC 3164 / 5424) rsyslog 服务 /var/log/*.log systemd-journald /run/log/journal 远程日志服务器 TCP/UDP 514 日志文件 / 二进制日志 / 远程归档 文本文件 | journal 数据库 | ELK / Graylog 密钥同步日志一般从应用程序打到 syslog,再经 rsyslog 或 journald 存储

1. Syslog 标准:两个 RFC 的故事

syslog 标准主要分两代:老牌的 RFC 3164 和后来的 RFC 5424。你平常看到的日志格式,基本跑不出这两个框架。

对比项 RFC 3164(传统格式) RFC 5424(结构化格式)
时间格式 Mmm dd hh:mm:ss(无年份) ISO 8601 完整时间戳
主机名 可选,纯文本 FQDN 格式,规范化
应用名 通常用 TAG 表示 APP-NAME 字段明确
结构化数据 无,靠人肉解析 支持 key=value 对
信息体 自由文本 UTF-8 编码标准
典型示例 Apr 12 10:15:30 hostname sshd[1234]: Failed password 2019-04-12T10:15:30.123Z hostname sshd 1234 - - Failed password

说实话,现在大部分传统服务还在用 RFC 3164。但新的系统,尤其是那些需要自动解析的,已经在往 RFC 5424 搬了。

我的小习惯: 排查密钥同步问题时,我会优先看时间戳有没有时区信息。RFC 3164 的日志跨时区排障时特别容易搞混。我建议你养成习惯,直接用 journald 或者配置 rsyslog 输出 RFC 5424 格式,省很多事。

2. Rsyslog 配置实战:从文本到规则

rsyslog 是目前大多数 Linux 发行版的默认 syslog 服务。它比老 syslogd 强太多了——支持 TCP、SSL、各种输出模块、还有灵活的过滤规则。

配置文件的典型路径是 /etc/rsyslog.conf 和 /etc/rsyslog.d/*.conf。核心规则格式长这样:

# 选择器字段 = 设施.级别    动作字段 = 文件路径 / 目标
authpriv.*                  /var/log/secure
*.info;mail.none;authpriv.none;cron.none   /var/log/messages
local0.*                    @192.168.1.100:514   # 远程发送

每个字段的含义你得记住:

  • 设施(Facility): 标识日志来源。常见的有 auth(认证)、authpriv(私有认证)、daemon(守护进程)、local0~local7(自定义)。做密钥同步的服务,我一般建议用 local0 或 authpriv。
  • 级别(Level): 严重程度。从高到低:emerg、alert、crit、error、warning、notice、info、debug。排同步故障时,我经常先把级别降到 debug 抓详细过程。
  • 动作(Action): 文件路径、用户(:)、远程服务器(@ 或 @@)、管道等。
曾经踩过的坑: 我遇到过 rsyslog 版本升级后,@(UDP)和 @@(TCP)混用导致远程日志丢包。你现在配置远程传输时,一定看清楚用哪个协议。密钥同步的日志丢失了,排查起来就成无头苍蝇了。

Rsyslog 高级配置:模板与过滤

rsyslog 支持自定义输出模板,这是它强大的地方。比如你想让密钥同步的日志包含完整的程序名和进程 ID:

# 定义模板
template(name="KeySyncFormat" type="string"
         string="%TIMESTAMP:::date-rfc5424% %HOSTNAME% %syslogtag%%msg%\n")

# 应用到规则
local0.*    action(type="omfile" file="/var/log/keysync.log"
                  template="KeySyncFormat")

filter 功能也很有用。我只想记录密钥同步的 ERROR 及以上级别:

if $syslogfacility-text == 'local0' and $syslogseverity <= 3 then {
    action(type="omfile" file="/var/log/keysync_error.log")
}

你想想看,这样做之后,排查问题时直接看 keysync_error.log,比在所有日志里大海捞针快多了。

3. Journald 日志:二进制的结构化宝藏

systemd 出来以后,journald 逐渐成了系统日志的新主流。它跟传统 syslog 最大的区别就是:日志不再是纯文本,而是二进制数据库,每条日志都是一组结构化的 key=value。

journald 的日志默认存在 /run/log/journal/(内存)或 /var/log/journal/(持久化)下面。直接 cat 肯定看不懂,得用 journalctl 来看。

一个典型的 journald 日志条目包含的元数据:

字段名 含义 排查密钥同步时的价值
_SYSTEMD_UNIT 产生日志的 systemd 单元名 快速定位是哪个服务在报错
MESSAGE 实际的日志正文 最重要的排障信息
PRIORITY 日志级别(0=emerg 到 7=debug) 过滤出错误和警告
SYSLOG_FACILITY 设施的编码 确认日志来源的子系统
_PID 进程 ID 追踪特定密钥同步进程
_COMM 命令名 比如 sshd、sssd、或者你的自定义同步脚本
__REALTIME_TIMESTAMP 实时时间戳(微秒精度) 精确分析同步时间线

journald 最棒的一点是,它把很多之前需要 grep 的活直接集成到 journalctl 命令里了。

# 查看所有错误级别日志
journalctl -p err

# 只看某个服务单元的日志
journalctl -u keysync

# 结合时间段和关键词
journalctl -u sshd --since "1 hour ago" --until "now" | grep -i "key"

# 输出 JSON 格式,方便程序解析
journalctl -u keysync -o json-pretty

# 查看某个日志条目的完整元数据
journalctl -u keysync -o verbose --no-pager | head -30
个人经验: 我排查密钥同步问题时,最常用的就是 journalctl -u keysync -f 实时跟踪,然后开另一个终端用 journalctl -u keysync -p err --since "5 min ago" 抓错误。两边配合,效率翻倍。

Journald 与传统 syslog 的协同

很多人以为用了 journald 就抛弃 syslog 了,其实不对。默认情况下,systemd-journald 会把日志转发给 rsyslog,再由 rsyslog 写入文本文件。这样做的好处是:

  1. journald 负责结构化和元数据保存
  2. rsyslog 负责按规则分发和远程传输
  3. 传统运维脚本仍然可以 cat 文本日志

这个转发机制通过 /etc/systemd/journald.conf 中的 ForwardToSyslog=yes 控制。我建议你别关掉这个选项,除非你只信任 journald。

一个小技巧: 如果你发现 journald 的日志文件占用磁盘空间过大,可以设置 SystemMaxUse=500M 限制大小,或者 MaxRetentionSec=7day 只保留 7 天。生产环境的日志一定要配置轮转策略。

最后说一句,真正的高手排障时,syslog 和 journald 都会看。syslog 给你一个清晰的时间线文本,journald 给你结构化的元数据炮弹。两者互补,别偏废。