第2章 Syslog协议基础

说到日志收集,Syslog 是绕不开的老大哥。它从 80 年代诞生到现在,几乎成了日志领域的通用语言。你想想看,无论是路由器、交换机,还是 Linux 服务器、各类中间件,提到日志输出,第一反应就是 Syslog。这一章我们就把它彻底讲透。

本章核心: 搞懂 Syslog 的消息结构、级别体系和传输方式。这些是后续搭建 Filebeat 收集链路的基础,千万别跳过。

2.1 从 RFC 3164 到 RFC 5424

Syslog 最早是 BSD 系统里的一个打印服务,那时候没什么标准可言。2001 年有了 RFC 3164,但严格来说它只是个"观察记录",不是真正的标准。为什么这么说?因为它对消息格式的描述太模糊了——时间戳没有年份,主机名可以随便写,连消息长度都没定义。

我在项目里就吃过这个亏。当时对接一台老交换机,它发出的 Syslog 时间戳只有月和日,跨年日志根本没法排序。后来升级到 RFC 5424,这些问题才彻底解决。

两个版本的核心区别,我列了个表:

对比项 RFC 3164(传统) RFC 5424(结构化)
时间戳格式 无年份,如 Oct 11 22:14:15 ISO 8601,含时区
主机名字段 可选,格式随意 非空,FQDN 或 IP
消息长度 无限制(实际依赖传输) 明确限制 2048 字节
结构化数据 不支持 支持 key=value
字符编码 ASCII UTF-8
应用场景 网络设备、老旧系统 现代 IT 系统、云环境
我的建议: 新项目直接上 RFC 5424。老设备兼容问题可以通过 rsyslog 或 syslog-ng 做协议转换,不要为了向下兼容降低整个链路的可观测性。

2.2 Syslog 消息格式解析

一条完整的 Syslog 消息长什么样?来看我随手从服务器上抓的一条:

<34>1 2024-10-11T22:14:15.123Z myhost.example.com su - - - 'su root' failed for user on /dev/pts/8

这串东西看着乱,拆开就清楚了。我习惯把它分成三块:PRI + HEADER + MSG。

PRI 部分: 尖括号里的数字 34。这个数字由两个值计算得来:设施编号 × 8 + 严重级别。34 反过来推算,就是设施 4(auth 安全认证)乘以 8 等于 32,再加级别 2(critical),正好对上。具体设施和级别的对应关系,下一节会细说。

HEADER 部分: 从版本号开始到主机名结束。RFC 5424 要求必须有版本号(这里是 1),然后是 ISO 8601 时间戳、FQDN 主机名。注意中间那个空的字段——应用名、进程 ID、消息 ID 在 RFC 5424 里是可选字段,没有就用 - 占位。

MSG 部分: 两个 - 之后,全部是消息体。这里记录了一条 sudo 认证失败的详情。

踩坑提醒: 我在生产环境见过不少日志处理器因为解析不了"空字段占位符"而丢数据。如果你自己写解析器,- 占位一定要处理,不能简单按空格分割。

下面这张图把 Syslog 的核心结构串起来了,从日志产生到服务器落地,每个环节都在做什么,一目了然:

Syslog 协议核心架构 日志源 系统 / 应用 / 网络设备 消息格式化 PRI + HEADER + MSG 传输层 UDP 514 / TCP 6514 日志服务器 rsyslog / syslog-ng PRI 优先级 设施 × 8 + 级别 HEADER 头部 时间戳 + 主机名 MSG 消息体 应用层具体内容 一条 RFC 5424 示例消息 <34>1 2024-10-11T22:14:15.123Z myhost.example.com su - - - 'su root' failed 消息先由日志源产生,经格式化封装后通过传输层送达服务器

2.3 设施级别与严重级别

Syslog 用两个维度给消息分类:谁产生的(设施)和 有多严重(级别)。这两者编码在 PRI 字段里,我习惯把它们背下来,因为排错时经常要用到。

设施(Facility) 标识日志来源。常见的就这几个:

代码 设施名称 典型用途
0 kern 内核日志
1 user 用户态应用
3 auth 安全认证
4 syslog Syslog 自身
7 news 网络新闻组
16-23 local0 - local7 自定义设施(常用)

严重级别(Severity) 定义了 0 到 7 的递进关系:

代码 级别名称 说明
0 Emergency 系统不可用
1 Alert 需要立即处理
2 Critical 严重错误
3 Error 一般错误
4 Warning 警告
5 Notice 正常但重要
6 Informational 信息
7 Debug 调试
快速计算: 看到 PRI 值 86,86 ÷ 8 = 10 余 6,设施 10 是 authpriv(安全认证私有),级别 6 是 Informational。几秒钟就能定位消息来源和重要程度。

2.4 Syslog 传输机制

消息格式化好了,怎么把它送到服务器?主要有三种方式。

UDP 514: 最传统的做法。无连接、不确认,发完就算。优点是不占资源,缺点是丢包不重传。我一般在内网、丢几条日志不影响大局的场合用这个。网络设备默认全走 UDP 514,改都改不了。

TCP 6514: 面向连接,保证可达。Syslog 标准里分配的端口是 6514(不是 514)。用 TCP 的好处是消息不会丢,适合对完整性要求高的业务日志。缺点是需要维护连接状态,并发量大了会消耗系统资源。

TLS 加密传输: 在 TCP 基础上加一层 SSL/TLS。我建议所有经过公网的 Syslog 都走 TLS。曾经有个客户把内部日志通过公网传到总部,明文 UDP 跑了两年,直到安全审计才发现问题——中间人随便抓包就能看到所有认证记录。

传输方式 端口 是否可靠 是否加密 适用场景
UDP 514 否 否 内网、容忍少量丢失
TCP 6514 是 否 需可靠送达
TLS 6514(可配置) 是 是 公网、安全合规要求
注意: 很多人在配置 rsyslog 时把 TCP 端口写成 514,这是错的。UDP 514 和 TCP 514 不是同一个东西,尽量遵守标准端口分配,别给自己挖坑。

2.5 避坑指南——我的实战经验

讲几个我在工程里实际踩过的坑,你遇到了可以直接绕开。

坑一:消息长度超限被截断。 传统 Syslog 单条消息最大 1024 字节,RFC 5424 放宽到 2048。但很多网络设备出厂配置还是 1024。我遇到过几次,应用报错日志被截断,关键堆栈信息没了。解决办法是在日志源端把消息长度限制调大,或者在收集端设置 MESSAGE_LENGTH 参数。

坑二:时间戳没有时区。 RFC 3164 不要求时区,导致跨机房排错时日志时间对不上。我记得有一次查一个跨国的调用链问题,A 机房和 B 机房的日志差了 8 小时,排查了半天才发现是时区问题。从那以后我强制所有日志源都走 NTP 同步,并且统一使用 UTC 时间。

坑三:设施编号冲突。 local0 到 local7 是留给用户自定义的,但不同应用可能抢同一个编号。比如 Java 应用和 Nginx 插件都用了 local1,日志就混了。我建议你做一个设施编号分配表,写进运维文档,别靠脑子记。

一个小技巧: 调试 Syslog 时,用 logger 命令手动发一条消息测试链路。比如 logger -p auth.info -n 192.168.1.100 -P 514 "test message",几秒钟就能验证配置是否生效,比看日志文件快多了。

好了,Syslog 协议的基础就这些。消息结构、级别体系、传输机制,这三块搞明白,后面配置 Filebeat 的时候你就能理解为什么有些字段要这样映射、为什么有些传输参数要这样设。这都是环环相扣的东西。