第3章:Syslog消息格式详解 —— PRI、HEADER、MSG
搞懂Syslog的消息格式,是审计日志路上的第一道坎。我自己刚接触那会儿,对着一条日志看了半天,愣是不知道哪部分是优先级,哪部分是时间戳。后来才明白,整个消息就是三块拼起来的。
说白了,Syslog消息的格式长这样:
<PRI>HEADER MSG
嗯,就这么简单。但每块里面藏着不少细节。我带你一个一个拆开看。
3.1 PRI —— 优先级,藏在尖括号里的两个关键参数
PRI 字段用尖括号包裹,比如 <134>。它不是一个数,而是两个值的组合:设备(Facility)和严重级别(Severity)。计算公式是:
PRI = Facility × 8 + Severity
举个例子。我之前排查一台 Cisco 路由器,日志里出现 <134>,算一下:134 ÷ 8 = 16 余 6。Facility = 16(Local0),Severity = 6(Informational)。嗯,这就是 Local0 设备发来的信息日志。
Facility 和 Severity 都有标准定义,我整理了一个常用表格:
| 代码 | Facility 名称 | 说明 |
|---|---|---|
| 0 | kern | 内核消息 |
| 1 | user | 用户级消息 |
| 2 | 邮件系统 | |
| 3 | daemon | 系统守护进程 |
| 4 | auth | 安全/认证消息 |
| 5 | syslog | syslogd 内部消息 |
| 6 | lpr | 行打印机子系统 |
| 7 | news | 网络新闻子系统 |
| 8 | uucp | UUCP 子系统 |
| 9 | cron | 时钟守护进程 |
| 10 | authpriv | 安全/认证消息(私有) |
| 11 | ftp | FTP 守护进程 |
| 16–23 | local0–local7 | 本地自定义 |
| 代码 | Severity 名称 | 说明 |
|---|---|---|
| 0 | Emergency | 系统不可用 |
| 1 | Alert | 必须立即处理 |
| 2 | Critical | 严重条件 |
| 3 | Error | 错误条件 |
| 4 | Warning | 警告条件 |
| 5 | Notice | 正常但重要条件 |
| 6 | Informational | 信息消息 |
| 7 | Debug | 调试级消息 |
3.2 HEADER —— 时间戳和主机名
HEADER 部分紧跟在 PRI 后面,包含两个信息:时间戳和主机名,中间用空格隔开。啊对了,典型格式是:
Oct 1 12:34:56 myhost
时间戳:RFC 3164 规定是 Mmm dd hh:mm:ss,不带年份。月份缩写为英文前三个字母(Jan, Feb, ... Dec)。日期如果是个位数,前面补一个空格(不是补0)。
你可能会觉得奇怪,为什么没有年份?嗯,这是历史遗留问题。我在项目里对接过一些老设备,传过来的时间戳全是本地时间,也不带时区。这导致跨时区审计时特别痛苦。所以我建议:日志传输链路里尽量统一成 UTC,接收端再转成当地时间。
主机名:一般是源设备的主机名或 IP 地址。有些设备会直接用 FQDN,有些只用短名。注意:主机名里不能有空格,如果有空格会被解析成后续字段。
3.3 MSG —— 消息体,包含 TAG 和 Content
MSG 字段从 HEADER 之后开始,直到行尾。它分为两部分:TAG 和 Content。TAG 通常是进程名或应用标识,后面紧跟一个冒号或方括号,然后是消息内容。
举个例子:
<134>Oct 1 12:34:56 myhost sshd[12345]: Failed password for root from 10.0.0.1 port 22
这里面 sshd[12345] 就是 TAG,冒号后面的全是 Content。TAG 的格式灵活,常见的包括:
- 进程名[PID]:如
sshd[12345],PID 可选 - 应用名称:如
sudo:、kernel: - 设备标识:有些网络设备直接用模块名
Content 部分没有严格限制,可以是任意文本。但实际中很多厂商遵守 IETF RFC 5424 的结构化数据格式,比如用 [data] 包裹键值对。不过这是后话了,我们后面章节会讲 RFC 5424。
3.4 整条消息的视觉拆解
上面这些概念,我们用一张图串起来。下面是我画的 Syslog 消息结构图,把 PRI、HEADER、MSG 以及它们内部的子字段都标出来了。
3.5 实战中容易忽略的细节
- PRI 必须紧接消息开头,前面不能有空格。我见过一些脚本生成的日志,开头加了个换行符,导致 syslogd 直接丢弃整条消息。
- 时间戳的月份缩写大小写敏感?其实大小写都可以,但标准中第一个字母大写(Oct),其余小写。如果发来全大写的 OCT,有些接收器会解析失败。
- 主机名后面的空格:HEADER 结束后的第一个空格就是 MSG 的开始。如果你用程序拼接消息,务必注意空格数量。多个空格会导致 MSG 开头多出空白。
- MSG 的 TAG 里冒号:有些应用没有冒号,直接用空格分隔。这时候解析器会把整个 MSG 当成 Content,TAG 为空。你在写接收端时要做兼容。
3.6 你动手试一下
拿一条真实的日志,比如:
<13>Jan 15 08:30:00 webserver nginx: 10.0.0.2 - - [15/Jan/2025:08:30:00 +0000] "GET /index.html" 200 1234
自己拆一下:PRI 是多少?Facility 和 Severity 分别是多少?HEADER 里时间戳和主机名是什么?TAG 和 Content 分别对应哪段?
嗯,拆完后你会发现,其实这条消息的 nginx: 就是 TAG,后面那一长串 Access Log 格式就是 Content。虽然 Content 里还嵌了一个方括号时间戳,但那已经是应用层的事了,Syslog 本身不关心。
这一章的内容就是这些。格式弄清楚了,后面讲传输和接收的时候,你就能快速定位问题。记住三要素:PRI 决定路由,HEADER 提供上下文,MSG 承载事件。