系统日志结构详解:三大日志体系全掌握
日志这东西,说白了就是系统的黑匣子。密钥同步出问题的时候,你先翻的肯定是日志。但日志格式五花八门,不搞清楚结构,你连从哪儿查起都不知道。
我干了这么多年运维,见过太多人一上来就 tail -f,然后被一堆乱码似的字符串吓退。其实啊,现代 Linux 系统主要就三种日志体系:传统的 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 搬了。
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): 文件路径、用户(
:)、远程服务器(@或@@)、管道等。
@(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 写入文本文件。这样做的好处是:
- journald 负责结构化和元数据保存
- rsyslog 负责按规则分发和远程传输
- 传统运维脚本仍然可以 cat 文本日志
这个转发机制通过 /etc/systemd/journald.conf 中的 ForwardToSyslog=yes 控制。我建议你别关掉这个选项,除非你只信任 journald。
SystemMaxUse=500M 限制大小,或者 MaxRetentionSec=7day 只保留 7 天。生产环境的日志一定要配置轮转策略。
最后说一句,真正的高手排障时,syslog 和 journald 都会看。syslog 给你一个清晰的时间线文本,journald 给你结构化的元数据炮弹。两者互补,别偏废。