rsyslog 8.2112.0 配置参数详解
rsyslog v8 配置体系七大构件拆解:global/module/input/template/RainerScript/ruleset/action 与 queue 参数逐项实测,含双实例自环转发、模板转发的 tcpdump 排障实录、下游故障队列零丢失续传演练,全部回显实机采集。
rsyslog 8.2112.0 配置参数详解
目标:系统拆解 rsyslog v8 配置体系的七大构件——global 全局指令、module 模块装载、input 输入对象、template 模板、RainerScript 过滤与 ruleset、action 动作与 queue 队列参数,每个参数配「可独立执行的实验 + 真实回显」。全部实验在 Ubuntu 22.04.4 的 rsyslog 8.2112.0 上完成:为不动系统主配置(避免影响系统日志),一律用独立配置文件拉第二实例,实验完毕即销毁。
一、环境信息
- 操作系统:Ubuntu 22.04.4 LTS(x86_64),主机名
ops - rsyslog 版本:8.2112.0(jammy 仓库版,
rsyslogd -v实测横幅见安装篇) - 实测时间:2026-10-20
- 实验方法:独立第二实例。系统主 rsyslog(pid 884,systemd 托管)全程不动;所有实验用
rsyslogd -f <独立配置> -i <独立pid>拉起,端口用 10515 高位避让系统端口,实验结束 kill 掉实例 - 实验文件布局(实验工作区):
/opt/data/quzuo/tmp/rsyslog/
├── test-a.conf # A 实例配置:imfile 采集 + 模板 + 条件路由 + omfwd 双协议转发 + action queue
├── test-b.conf # B 实例配置:10515 UDP/TCP 接收,按协议分文件落盘
├── bad.conf # 反例配置:故意写错,演示 -N1 的三类报错
├── spool-a/ # A 实例 WorkDirectory(队列缓冲与 imfile 状态文件)
├── app.log # 被 imfile 监听的模拟应用日志
├── collected.log # A 实例 imfile 采集落盘
├── error.log # A 实例条件路由命中 ERROR 的落盘
├── local.log # A 实例默认规则集(本地 socket)落盘
├── forwarded-udp.log # B 实例 UDP 10515 接收落盘
├── forwarded-tcp.log # B 实例 TCP 10515 接收落盘
└── stats-a.log # A 实例 impstats 周期统计输出
- 站位说明:本文的配置对象在系统主配置中的位置(哪些是 Ubuntu 自带的、改哪里)见《Ubuntu 22.04 安装 rsyslog 8.2112.0 指南》第八章;体系概览见《rsyslog 8.2608.0 介绍与选型指南》第三章。
二、前置条件
- 系统已安装 rsyslog 8.2112.0(安装步骤见安装篇,
rsyslogd -N1可用即可); - 实验用目录已创建:
mkdir -p /opt/data/quzuo/tmp/rsyslog/{spool-a,spool-b}; - 有 root 权限(第二实例需要绑定网络端口、读写实验目录);
- 理解一个安全约定:改系统配置前先
rsyslogd -N1校验,主配置(/etc/rsyslog.conf)不动,自定义规则全放/etc/rsyslog.d/*.conf。本文所有实验连 drop-in 都不碰,用完全独立的配置文件,实验失败的最坏结果是实例起不来,系统日志零影响。
三、参数查看与修改方式
3.1 配置体系的加载模型
rsyslog v8 配置是一个对象模型,加载顺序(同文件内从上到下,跨文件按 $IncludeConfig 字典序合并)决定作用:
global(...)全局参数(工作目录、内部日志等);module(load="...")模块装载——没装载的模块,其 input/action 参数写上去直接报错;template(...)模板定义(必须先于引用它的 action?不一定——rsyslog 允许任意顺序,但引用不存在名字会在校验期报Could not find template);input(...)输入对象(决定日志从哪进);ruleset(name="...") { ... }规则集与 action(决定日志怎么路由出去);- 不在任何 ruleset 里的裸 action 属于默认规则集(本地 socket 等未绑定 ruleset 的输入走这里)。
3.2 修改方式与校验闭环
标准改动流程:改文件 → rsyslogd -N1 校验 → 通过才重启/重载。实测校验通过形态:
rsyslogd -N1 -f test-b.conf
实测回显:
rsyslogd: version 8.2112.0, config validation run (level 1), master config test-b.conf
rsyslogd: End of config validation run. Bye.
返回码 0 且出现 End of config validation run. Bye. 才能放行。-N1 的三种典型报错形态在 3.3 与反例实验里实机演示。
3.3 -N1 实战:三类报错形态(反例实测)
准备一份故意写错的配置(bad.conf,三个坑:模块名拼写错、template type 非法值、引用未定义模板):
global(workDirectory="/opt/data/quzuo/tmp/rsyslog/spool-a")
modul(load="imuxsock") # 错误1:modul 拼写错误
template(name="bad" type="sting" string="%msg%\n") # 错误2:type 取值非法
if $msg contains "x" then action(type="omfile" file="/tmp/x.log" template="notexist") # 错误3:模板未定义
实测校验:
rsyslogd -N1 -f bad.conf
echo $?
实测回显:
rsyslogd: version 8.2112.0, config validation run (level 1), master config bad.conf
rsyslogd: error during parsing file bad.conf, on or before line 3: warnings occured in file 'bad.conf' around line 3 [v8.2112.0 try https://www.rsyslog.com/e/2207 ]
rsyslogd: error during parsing file bad.conf, on or before line 3: invalid character '(' - is there an invalid escape sequence somewhere? [v8.2112.0 try https://www.rsyslog.com/e/2207 ]
rsyslogd: error during parsing file bad.conf, on or before line 3: warnings occured in file 'bad.conf' around line 3 [v8.2112.0 try https://www.rsyslog.com/e/2207 ]
rsyslogd: error during parsing file bad.conf, on or before line 3: invalid character '=' - is there an invalid escape sequence somewhere? [v8.2112.0 try https://www.rsyslog.com/e/2207 ]
rsyslogd: error during parsing file bad.conf, on or before line 3: invalid character '"' - is there an invalid escape sequence somewhere? [v8.2112.0 try https://www.rsyslog.com/e/2207 ]
rsyslogd: error during parsing file bad.conf, on or before line 3: warnings occured in file 'bad.conf' around line 3 [v8.2112.0 try https://www.rsyslog.com/e/2207 ]
rsyslogd: error during parsing file bad.conf, on or before line 3: invalid character '"' - is there an invalid escape sequence somewhere? [v8.2112.0 try https://www.rsyslog.com/e/2207 ]
rsyslogd: error during parsing file bad.conf, on or before line 3: invalid character ')' - is there an invalid escape sequence somewhere? [v8.2112.0 try https://www.rsyslog.com/e/2207 ]
rsyslogd: invalid template type 'sting' [v8.2112.0]
rsyslogd: error during parsing file bad.conf, on or before line 5: error processing template object [v8.2112.0 try https://www.rsyslog.com/e/2207 ]
rsyslogd: Could not find template 0 'notexist' - action disabled [v8.2112.0 try https://www.rsyslog.com/e/3003 ]
rsyslogd: error during parsing file bad.conf, on or before line 5: errors occured in file 'bad.conf' around line 5 [v8.2112.0 try https://www.rsyslog.com/e/2207 ]
1
三类报错的判读经验:
- 关键字拼写错(
modul):解析器把括号内容当普通文本,报一串invalid character '(' / '=' / '"'——看到「invalid character」连环报,先查指令关键字拼写; - 参数取值非法(
type="sting"):直接点名invalid template type 'sting',这类报错最好定位; - 引用不存在(
template="notexist"):报Could not find template 0 'notexist' - action disabled——注意措辞是 action disabled:校验期不阻断但运行时该 action 静默失效,日志会凭空消失,这是最危险的一类。
⚠️ 注意:真实事故里最常见的不是语法错,而是「校验通过但 action 被禁用」——
-N1返回码可能仍是 0 但输出里有action disabled。发布前检查脚本要同时盯返回码和报错行。
四、参数总览
rsyslog v8 配置参数按对象分七类,实验配置(完整文件见五~八章各节)覆盖了其中六类:
| 对象 | 语法形态 | 职责 | 本文实测覆盖 |
|---|---|---|---|
| global | global(param="value") | 全局参数(工作目录等) | ✅ workDirectory |
| module | module(load="imxxx" param="value") | 装载输入/输出/解析模块 | ✅ imuxsock/imfile/imudp/imtcp/impstats |
| input | input(type="imxxx" param="value") | 实例化一个输入源 | ✅ imfile 文件监听、imudp/imtcp 端口监听、imuxsock 自定义 socket |
| template | template(name="..." type="...") | 定义输出格式 | ✅ string 型模板 + 内置转发模板 |
| ruleset | ruleset(name="...") { ... } | 路由流水线(过滤+动作) | ✅ coll/rcvudp/rcvtcp 三个规则集 |
| action | action(type="omxxx" param="value") | 单个输出动作 | ✅ omfile/omfwd + 队列参数 |
| legacy | $指令 值($ 开头) | v5 以前遗留语法,仍在兼容 | 系统主配置自带(见安装篇 8.1),实验全用 v8 语法 |
💡 技术拓展:rsyslog 的配置语言不止 v8 RainerScript 一种——
形态 语法特征 状态 legacy $指令每行一条 $ActionFileDefaultTemplate ...兼容支持,Ubuntu 主配置大量使用 传统 selector auth,authpriv.* /var/log/auth.log50-default.conf 的形态,只按 facility.priority 过滤 RainerScript(v8) if/then/ruleset/action(...)脚本化本文主线,表达力最强 三种形态可在同一配置混用;新写配置一律用 RainerScript,老 selector 在 50-default.conf 里保留即可。本文采用 RainerScript,因为条件路由与队列参数只有它支持。
五、Global 全局指令与实验配置
5.1 workDirectory:队列与状态文件的家
global(workDirectory="...") 是磁盘队列缓冲文件、imfile 状态文件、检查点文件的父亲。实验 A 实例与 B 实例各自隔离:
global(workDirectory="/opt/data/quzuo/tmp/rsyslog/spool-a")
目录不存在时 -N1 直接给出实证(本实验第一次校验的真实报错):
rsyslogd: $WorkDirectory: /opt/data/quzuo/tmp/rsyslog/spool-a can not be accessed, probably does not exist - directive ignored [v8.2112.0 try https://www.rsyslog.com/e/2181 ]
rsyslogd: imfile: no working or state file directory set, imfile will create state files in the current working directory (probably the root dir). Use global(workDirectory="/some/path") to set the working directory [v8.2112.0 try https://www.rsyslog.com/e/2450 ]
两条要点:目录必须先建(mkdir -p),否则指令被忽略且 imfile 把状态文件写进当前目录;报错里明确说「probably the root dir」——生产上忘建目录的后果是状态文件散落根目录。实测 mkdir -p spool-a spool-b 后报错消失。imfile 的状态文件实测落在其中(文件名含被监听文件的 inode 信息):
-rw------- 1 root root 113 10月 20 13:23 imfile-state:9306187
5.2 实验 A 实例完整配置(test-a.conf)
这是本文主线实验的 A 实例,承载 imfile 采集、模板、条件路由、双协议转发与队列:
# A 实例:imfile 采集 + 自定义模板 + 分级路由 + omfwd 双协议转发 + action queue
global(workDirectory="/opt/data/quzuo/tmp/rsyslog/spool-a")
module(load="imuxsock" SysSock.Use="off")
input(type="imuxsock" Socket="/opt/data/quzuo/tmp/rsyslog/a.sock")
module(load="imfile" mode="inotify")
module(load="impstats" interval="5" severity="7" log.syslog="off" log.file="/opt/data/quzuo/tmp/rsyslog/stats-a.log")
# 自定义模板:日期 RFC3339 时间 主机名 标签 消息体
template(name="mytpl" type="string"
string="%$YEAR%-%$MONTH%-%$DAY% %timereported:::date-rfc3339% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n")
# 默认规则集:本地 socket 进来的消息落到 local.log(演示规则集隔离)
action(type="omfile" file="/opt/data/quzuo/tmp/rsyslog/local.log" template="mytpl")
# imfile:监听模拟应用日志文件
input(type="imfile" File="/opt/data/quzuo/tmp/rsyslog/app.log"
Tag="applog:" Severity="info" Facility="local0" ruleset="coll")
ruleset(name="coll") {
if ($msg contains "ERROR") then {
action(type="omfile" file="/opt/data/quzuo/tmp/rsyslog/error.log" template="mytpl"
action.resumeRetryCount="0")
}
action(type="omfile" file="/opt/data/quzuo/tmp/rsyslog/collected.log" template="mytpl")
# UDP 转发(无队列直通)
action(type="omfwd" target="127.0.0.1" port="10515" protocol="udp" template="RSYSLOG_ForwardFormat")
# TCP 转发(disk-assisted 内存队列,下游不可达时缓冲)
action(type="omfwd" target="127.0.0.1" port="10515" protocol="tcp" template="RSYSLOG_ForwardFormat"
queue.type="LinkedList" queue.size="10000" queue.filename="fwdq"
queue.maxDiskSpace="1048576" queue.saveOnShutdown="on" queue.highWatermark="8000"
queue.lowWatermark="2000" action.resumeRetryCount="-1")
}
逐项说明(与后文各章详解对应):
module(load="imuxsock" SysSock.Use="off"):装载 imuxsock 但关闭默认系统 socket——第二实例绝不能抢占/run/systemd/journal/syslog,否则系统日志被实验实例劫持;input(type="imuxsock" Socket="..."):在自定义路径开一个 Unix socket,logger -u可定向投递;module(load="impstats" ...):周期(5 秒)把 rsyslog 内部统计写到文件,是验证队列行为的探针;ruleset(name="coll")内三个 action 依次执行:条件落 error.log → 全量落 collected.log → 双协议转发。
5.3 实验 B 实例完整配置(test-b.conf)
# B 实例:10515 双协议接收,按协议分文件落盘
global(workDirectory="/opt/data/quzuo/tmp/rsyslog/spool-b")
module(load="imuxsock" SysSock.Use="off")
input(type="imuxsock" Socket="/opt/data/quzuo/tmp/rsyslog/b.sock")
module(load="imudp")
module(load="imtcp")
template(name="btpl" type="string"
string="%timegenerated% [SRC %fromhost-ip%] %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n")
input(type="imudp" port="10515" ruleset="rcvudp")
input(type="imtcp" port="10515" ruleset="rcvtcp")
ruleset(name="rcvudp") {
action(type="omfile" file="/opt/data/quzuo/tmp/rsyslog/forwarded-udp.log" template="btpl")
}
ruleset(name="rcvtcp") {
action(type="omfile" file="/opt/data/quzuo/tmp/rsyslog/forwarded-tcp.log" template="btpl")
}
两实例启动与监听确认(实测):
rsyslogd -f test-b.conf -i /opt/data/quzuo/tmp/rsyslog/b.pid
rsyslogd -f test-a.conf -i /opt/data/quzuo/tmp/rsyslog/a.pid
ps -ef | grep -E 'rsyslogd -f test' | grep -v grep
ss -lnup | grep -w 10515
ss -lntp | grep -w 10515
实测回显:
root 1276926 1 0 13:19 ? 00:00:00 rsyslogd -f test-b.conf -i b.pid
root 1276973 1 2 13:19 ? 00:00:00 rsyslogd -f test-a.conf -i a.pid
UNCONN 0 0 0.0.0.0:10515 0.0.0.0:* users:(("rsyslogd",pid=1276926,fd=4))
UNCONN 0 0 [::]:10515 [::]:* users:(("rsyslogd",pid=1276926,fd=6))
LISTEN 0 25 0.0.0.0:10515 0.0.0.0:* users:(("rsyslogd",pid=1276926,fd=7))
LISTEN 0 25 [::]:10515 [::]:* users:(("rsyslogd",pid=1276926,fd=8))
💡 说明:多实例并存的三个前提——独立配置文件(-f)、独立 pid 文件(-i,用绝对路径更稳)、socket/端口互不冲突(SysSock.Use="off" + 高位端口)。命令行标志的完整清单见命令详解篇。
六、模块与 input 参数详解
6.1 imuxsock:本地 socket 输入
模块级参数 SysSock.Use="off" 关闭默认 socket;输入对象参数 Socket 指定自定义路径(实测 8.2112.0 上 imuxsock 的 input 参数表里没有 SocketName,写上会报 parameter 'SocketName' not known——这是本实验第一次校验时踩到的真实报错,8.2112.0 只认 Socket)。
实测定向投递(-u 指定 socket):
logger -u /opt/data/quzuo/tmp/rsyslog/a.sock -t myapp "hello via custom socket"
该输入未绑定 ruleset → 走默认规则集 → 落 local.log,实测回显:
2026-10-20 2026-10-20T13:19:26.159988+08:00 ops myapp: hello via custom socket
6.2 imfile:文件监听采集
imfile 把任意文本日志文件变成 syslog 消息流,核心参数:
File:被监听文件路径(支持通配符);Tag:给每条消息打的标签(渲染时显示为applog:);Severity/Facility:赋予的 syslog 严重级与设施;ruleset:消息交给哪个规则集处理;mode="inotify":内核事件驱动的监听模式(默认),比轮询省资源、实时性好。
实测:向被监听文件追加四行(含一条 ERROR、一条 WARN),验证采集与状态文件:
printf '%s\n' 'INFO user alice logged in from 192.168.1.10' 'ERROR db connection timeout after 30s' 'INFO order 10086 created' 'WARN disk usage 85%' >> app.log
约 1 秒后(inotify 事件驱动)collected.log 实测内容:
2026-10-20 2026-10-20T13:19:26.158704+08:00 ops applog: INFO user alice logged in from 192.168.1.10
2026-10-20 2026-10-20T13:19:26.158734+08:00 ops applog: ERROR db connection timeout after 30s
2026-10-20 2026-10-20T13:19:26.158735+08:00 ops applog: INFO order 10086 created
2026-10-20 2026-10-20T13:19:26.158736+08:00 ops applog: WARN disk usage 85%
imfile 状态文件实测内容(断点续采的依据,记录文件名与读取偏移量):
$FileCreateMode 0600
imfile-state:9306187
tf="/opt/data/quzuo/tmp/rsyslog/app.log" wt="applog:" si="info" fa="local0"
9306187 225
💡 说明:末行的
225是文件读取偏移量。imfile 靠它实现「重启不重采、不漏采」;轮转后的新文件因 inode 变化会被当作新文件从头采集。这也是状态文件必须落 WorkDirectory(不能丢)的原因。
6.3 imudp / imtcp:网络接收
input(type="imudp" port="10515" ruleset="rcvudp") 与 input(type="imtcp" port="10515" ruleset="rcvtcp") 同端口双协议监听(实测 ss 回显见 5.3)。要点:
- imtcp 是多 worker 模型,默认
FlowControl开启可对抗突发; - 网络端口绑定高位(10515)是实验惯例,生产中心节点用标准 514(启用方法见安装篇第九章);
- 接收侧规则集把「UDP 来的」与「TCP 来的」分流到不同文件,为第七章的转发实验提供独立观测点。
6.4 impstats:内部统计探针
module(load="impstats" interval="5" severity="7" log.syslog="off" log.file="...") 每 5 秒输出一次内部计数到文件,不用接任何监控系统就能看到队列深浅与速率。实测输出形态(节选):
Tue Oct 20 13:19:41 2026: resource-usage: origin=impstats utime=13388 stime=14717 maxrss=3668 minflt=245 majflt=0 inblock=0 oublock=48 nvcsw=23 nivcsw=0 openfiles=19
Tue Oct 20 13:19:41 2026: action-4-builtin:omfwd queue[DA]: origin=core.queue size=0 enqueued=0 full=0 discarded.full=0 discarded.nf=0 maxqsize=0
Tue Oct 20 13:19:41 2026: action-4-builtin:omfwd queue: origin=core.queue size=0 enqueued=4 full=0 discarded.full=0 discarded.nf=0 maxqsize=4
Tue Oct 20 13:19:41 2026: main Q: origin=core.queue size=0 enqueued=5 full=0 discarded.full=0 discarded.nf=0 maxqsize=4
判读:maxrss=3668 是常驻内存 3.6MB;main Q 是主队列;action-4-builtin:omfwd queue 是 TCP 转发 action 的私有队列;带 [DA] 后缀的是它的磁盘辅助子队列(disk-assisted,正常时为空)。这些数字是第八章队列实验的观测依据。
七、template 模板与 RainerScript 路由
7.1 string 型模板与属性替换器
实验主模板:
template(name="mytpl" type="string"
string="%$YEAR%-%$MONTH%-%$DAY% %timereported:::date-rfc3339% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n")
语法三要素:name 引用名、type="string"(字符串型,另有 list 型与 subtree 型)、string 里的 %属性% 占位。实测输出(collected.log 首行):
2026-10-20 2026-10-20T13:19:26.158704+08:00 ops applog: INFO user alice logged in from 192.168.1.10
逐个属性解读:
%$YEAR%-%$MONTH%-%$DAY%:$开头的是系统变量(当前日期),与消息自带时间无关;%timereported:::date-rfc3339%:消息时间戳,:::后是属性替换器(replacer)——date-rfc3339把时间渲染成2026-10-20T13:19:26.158704+08:00;%HOSTNAME%:来源主机名;%syslogtag%:标签(imfile 的 Tag 参数值);%msg:::sp-if-no-1st-sp%:若消息体不以空格开头则补一个空格(保持「TAG MSG」间隔的文件美观性);%msg:::drop-last-lf%:去掉消息体末尾换行(imfile 读入的行自带 LF,不 drop 会双换行)。
常用内置模板(转发与落盘的标准答案,不用自己写):
| 内置模板名 | 格式 | 用途 |
|---|---|---|
| RSYSLOG_TraditionalFileFormat | 传统 BSD 时间戳文件格式 | 文件落盘默认(Ubuntu 主配置显式指定) |
| RSYSLOG_FileFormat | 高精度 RFC3339 文件格式 | 现代文件落盘 |
| RSYSLOG_ForwardFormat | RFC3164 + 高精度时间转发格式 | omfwd 转发推荐(本文实验实测采用) |
| RSYSLOG_SyslogProtocol23Format | RFC5424 完整格式 | 标准协议转发 |
7.2 转发必须用转发模板:一次完整的排障实录
这是本文最重要的坑,完整还原定位过程。初版实验里,A 实例的 omfwd 也用了 mytpl(文件模板),结果 B 实例的 TCP 接收文件迟迟不出内容:
- 现象:
forwarded-udp.log正常,forwarded-tcp.log不存在;而 A 端 impstats 显示 TCP actionprocessed=5 failed=0(A 自认为发送成功); - 排除 B 端:用 nc 直连 10515 发一行标准 RFC3164 报文
"<14>Oct 20 13:22:00 myhost mytag: wellformed rfc3164 line",B 立刻正确落盘:
Oct 20 13:21:57 [SRC 127.0.0.1] mytag: wellformed rfc3164 line
- 抓线上字节定位(tcpdump 在 loopback 抓 10515 端口,同时向 app.log 追加一条消息),实测 A 实际发出的 TCP 载荷:
2026-10-20 2026-10-20T13:22:14.861863+08:00 ops applog: INFO third round tcpdump probe
- 根因:omfwd 发到线上的内容就是模板的渲染结果。mytpl 是给文件用的,渲染结果没有 PRI(
<14>)与 syslog 时间戳头,B 收到后无法解析成合法 syslog 报文,静默丢弃——所以 A 认为发成功了、B 认为没收到任何消息; - 修复:转发 action 改用内置
RSYSLOG_ForwardFormat(见 5.2 配置),重启 A 实例后实测 TCP 与 UDP 同时到达:
Oct 20 13:23:52 [SRC 127.0.0.1] applog: INFO after forwardformat fix
⚠️ 注意:转发 action 的模板必须含完整 syslog 报文头(或直接用 RSYSLOG_ForwardFormat/RSYSLOG_SyslogProtocol23Format 内置模板);落盘模板用于转发是「A 显示成功、B 静默丢弃」的双盲事故,只能靠接收端观测或抓包发现。
顺带沉淀一个同类坑:实验早期 UDP 链路虽然通了,B 端渲染出 2026-10-20T13: 19:26(时间戳中间多了个空格)——这是 B 把 A 裸模板文本的行首日期当成 syslog 时间戳字段重新解析造成的错位,换 ForwardFormat 后消失。
7.3 RainerScript 条件路由与 ruleset 隔离
实验规则集里的条件语句:
if ($msg contains "ERROR") then {
action(type="omfile" file="/opt/data/quzuo/tmp/rsyslog/error.log" template="mytpl")
}
action(type="omfile" file="/opt/data/quzuo/tmp/rsyslog/collected.log" template="mytpl")
实测结果:error.log 只有一行(条件命中),collected.log 四行全量(if 之后没有 stop,两条流水都走):
2026-10-20 2026-10-20T13:19:26.158734+08:00 ops applog: ERROR db connection timeout after 30s
常用过滤操作符与函数(RainerScript 全集的常用子集):
- 比较:
contains/icontains(忽略大小写)、startswith、==/!=、正则:re与erewrite; - 属性引用:
$msg(消息体)、$fromhost-ip(来源 IP)、$syslogfacility-text、$programname(TAG 去 PID 部分); - 流程控制:
stop(命中即止,防止消息继续流入后续 action)、call <ruleset>(规则集互调)、set/unset(改写变量)。
规则集隔离是 ruleset 的核心价值:绑定到 input 的 ruleset 与默认规则集互不干扰。实验实证——logger -u a.sock 的消息走默认规则集(local.log),而 imfile 的消息走 coll 规则集(collected/error/转发),互不串流(两份落盘文件内容与 6.1/6.2 实测一致)。
八、action 与 queue 队列参数详解
8.1 队列三模式与技术选型
💡 技术拓展:rsyslog 队列有三种模式,选型决定「不丢日志」的承诺等级——
模式 参数取值 原理/特点 适用场景 direct queue.type="Direct"(默认)无队列直通,action 慢会拖慢整条流水线 写本地文件等极速输出 内存型 LinkedList/FixedArray内存缓冲, disk参数开启磁盘辅助网络转发(本文 TCP action 实测采用) 磁盘型 queue.type="Disk"纯磁盘队列,极可靠但慢 断网续传、削峰兜底 本文 TCP 转发 action 采用「LinkedList 内存队列 + 磁盘辅助」:正常时零磁盘 IO,异常时水位超过 highWatermark 自动落盘,是官方推荐的转发标配。Direct 模式用于 omfile——实测 main Q 的入队出队速率就是直接消费。
8.2 TCP 转发 action 的队列参数逐项解读
action(type="omfwd" target="127.0.0.1" port="10515" protocol="tcp" template="RSYSLOG_ForwardFormat"
queue.type="LinkedList" queue.size="10000" queue.filename="fwdq"
queue.maxDiskSpace="1048576" queue.saveOnShutdown="on" queue.highWatermark="8000"
queue.lowWatermark="2000" action.resumeRetryCount="-1")
queue.type="LinkedList":链表内存队列(入队出队 O(1),比 FixedArray 灵活,官方推荐);queue.size="10000":内存队列容量上限(条数);queue.filename="fwdq":磁盘辅助模式的落盘文件前缀——配置了这个参数磁盘辅助才被激活;queue.maxDiskSpace="1048576":磁盘队列最大占用 1MB(防磁盘写爆的保险丝);queue.saveOnShutdown="on":实例正常停止时把队列残余写盘,下次启动续传;queue.highWatermark/lowWatermark="8000"/"2000":水位触发线——超 8000 条激活磁盘辅助,回落到 2000 以下停止落盘;action.resumeRetryCount="-1":下游失败后无限重试(-1)——配队列才有意义,Direct 模式下无限重试会卡死整条流水线。
8.3 队列生效实测:下游故障演练(核心实验)
实验目的:证明队列参数真的在保护日志。演练脚本:杀掉 B 实例(下游消失)→ 继续投递 5 条消息 → 观察队列缓冲 → 拉起 B → 验证零丢失续传。
第一步:杀 B 实例,确认下游死亡:
kill $(cat b.pid)
第二步:向 app.log 追加 5 条消息(此时 A 的 TCP 转发 action 连不上 10515):
printf '%s\n' 'INFO buffered-1 during outage' 'INFO buffered-2 during outage' 'ERROR buffered-3 during outage' 'INFO buffered-4 during outage' 'INFO buffered-5 during outage' >> app.log
第三步:观察 impstats——5 条消息滞留在 TCP action 队列(实测):
Tue Oct 20 13:24:24 2026: action-4-builtin:omfwd: origin=core.action processed=6 failed=0 suspended=0 suspended.duration=0 resumed=0
Tue Oct 20 13:24:24 2026: action-4-builtin:omfwd queue[DA]: origin=core.queue size=0 enqueued=0 full=0 discarded.full=0 discarded.nf=0 maxqsize=0
Tue Oct 20 13:24:24 2026: action-4-builtin:omfwd queue: origin=core.queue size=5 enqueued=6 full=0 discarded.full=0 discarded.nf=0 maxqsize=5
判读:queue: size=5 ——5 条全部滞留在内存队列;discarded.full=0 discarded.nf=0 ——零丢弃;queue[DA] size=0 ——水位未到 8000,磁盘辅助未触发(spool-a 目录实测只有 imfile 状态文件,无 fwdq 队列文件)。同时 A 实例的采集、条件路由、UDP 转发(UDP 无队列,报文自然丢弃)不受影响——这正是 action queue 的隔离意义。
第四步:拉起 B 实例:
rsyslogd -f test-b.conf -i /opt/data/quzuo/tmp/rsyslog/b.pid
第五步:等待重试周期(action.resumeInterval 默认 30 秒),实测 forwarded-tcp.log——故障期间缓冲的 5 条全部按序续传(13:24:51 B 恢复后立即送达):
Oct 20 13:21:10 [SRC 127.0.0.1]
Oct 20 13:21:57 [SRC 127.0.0.1] mytag: wellformed rfc3164 line
Oct 20 13:23:52 [SRC 127.0.0.1] applog: INFO after forwardformat fix
Oct 20 13:24:51 [SRC 127.0.0.1] applog: INFO buffered-1 during outage
Oct 20 13:24:51 [SRC 127.0.0.1] applog: INFO buffered-2 during outage
Oct 20 13:24:51 [SRC 127.0.0.1] applog: ERROR buffered-3 during outage
Oct 20 13:24:51 [SRC 127.0.0.1] applog: INFO buffered-4 during outage
Oct 20 13:24:51 [SRC 127.0.0.1] applog: INFO buffered-5 during outage
第六步:确认队列排空与 action 恢复(impstats 实测):
Tue Oct 20 13:25:29 2026: action-4-builtin:omfwd: origin=core.action processed=6 failed=0 suspended=0 suspended.duration=0 resumed=1
Tue Oct 20 13:25:29 2026: action-4-builtin:omfwd queue: origin=core.queue size=0 enqueued=6 full=0 discarded.full=0 discarded.nf=0 maxqsize=5
resumed=1(action 从挂起恢复)、size=0(队列清空)、enqueued=6(累计入队 6 条 = 修复前 1 条 + 故障期 5 条)——队列「下游故障零丢失」的承诺实测兑现。
8.4 omfile 关键参数(对照简表)
实验里 omfile 只用了基础参数,生产常用补充(含义据官方 omfile 手册,参数名以 rsyslogd -N1 校验为准):
| 参数 | 默认 | 说明 |
|---|---|---|
| file | 必填 | 目标文件路径 |
| template | 文件默认模板 | 指定输出格式 |
| flushOnTXEnd | on | 每个写事务结束即 flush(掉电少丢但 IO 多) |
| asyncWriting | off | 开启后台写(配合 flushInterval) |
| dynaFileCacheSize | 127 | 动态文件缓存槽位(用 dynaFile 时关注) |
| createDirs | on | 自动创建父目录 |
九、生产配置模板
以下三份模板按资源档位给出,变量只保留端口与路径,其余为实测可跑的完整形态。
9.1 小机型(4GB 内存,本机采集+转发一条)
global(workDirectory="/var/spool/rsyslog")
module(load="imuxsock")
module(load="imjournal" StateFile="imjournal.state")
module(load="imfile" mode="inotify")
template(name="fwd" type="string" string="<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %app-name% %procid% %msgid% %msg%\n")
input(type="imfile" File="/var/log/myapp/app.log" Tag="myapp:" ruleset="toCenter")
ruleset(name="toCenter") {
action(type="omfwd" target="10.0.0.10" port="514" protocol="tcp" template="RSYSLOG_ForwardFormat"
queue.type="LinkedList" queue.size="10000" queue.filename="fwdq"
queue.saveOnShutdown="on" queue.highWatermark="8000" queue.lowWatermark="2000"
action.resumeRetryCount="-1")
}
适用:单机内存 4GB 级、转发目标是中心节点;队列 10000 条约缓冲十几 MB,内存无压力。
9.2 中心日志服务器(16GB 内存,接收+分类落盘)
global(workDirectory="/var/spool/rsyslog")
$FileOwner syslog
$FileGroup adm
$FileCreateMode 0640
$PrivDropToUser syslog
$PrivDropToGroup syslog
module(load="imuxsock" SysSock.Use="off")
module(load="imudp")
module(load="imtcp")
input(type="imudp" port="514" ruleset="byHost")
input(type="imtcp" port="514" ruleset="byHost")
template(name="hostTpl" type="string" string="/var/log/remote/%fromhost-ip%/%$YEAR%%$MONTH%.log")
ruleset(name="byHost") {
action(type="omfile" dynaFile="hostTpl" dirCreateMode="0750" fileCreateMode="0640"
template="RSYSLOG_FileFormat" flushOnTXEnd="off" asyncWriting="on"
queue.type="LinkedList" queue.size="50000" queue.filename="remoteWrite"
queue.saveOnShutdown="on" queue.highWatermark="40000" queue.lowWatermark="10000")
}
适用:中心节点按来源 IP 分目录落盘;大队列 + 异步写吸收 UDP 突发;dynaFile 按来源自动建目录。
9.3 纯转发链路(沿途节点,只增不改)
global(workDirectory="/var/spool/rsyslog")
module(load="imuxsock")
template(name="fwd" type="string" string="<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %app-name% %procid% %msgid% %msg%\n")
action(type="omfwd" target="10.0.0.10" port="514" protocol="tcp" template="fwd"
queue.type="LinkedList" queue.size="50000" queue.filename="relayq"
queue.maxDiskSpace="1073741824" queue.saveOnShutdown="on"
queue.highWatermark="40000" queue.lowWatermark="10000"
action.resumeRetryCount="-1" action.resumeInterval="10")
适用:链式转发节点;maxDiskSpace 提到 1GB,resumeInterval 缩到 10 秒加快故障恢复。
十、常见问题(FAQ)
Q1:第二实例启动报 rsyslogd: run failed with error -3000?
这是 pid 文件路径不可写(或目录不存在)。pid 文件用绝对路径且目录先建好:rsyslogd -f test.conf -i /full/path/a.pid。本实验曾因相对路径 pid 文件踩过该坑。
Q2:实例能启动但消息「凭空消失」?
按三条路径排查:消息进了没有(impstats 的 imuxsock/imfile submitted 计数)→ 路由到哪了(ruleset 绑定关系)→ action 是否被禁用(rsyslogd -N1 输出里的 Could not find template ... action disabled)。B 实例的默认规则集没有 action 时,B 自己的内部错误消息也会无处可去,加重「静默」感——实验配置建议至少给默认规则集留一个 omfile。
Q3:转发到对端显示「成功」,对端却没收到?
九成是模板问题:转发 action 用了文件模板(无 PRI/时间戳头),对端解析不了静默丢弃。改用 RSYSLOG_ForwardFormat(完整排障过程见 7.2)。
Q4:Socket/SocketName 报 parameter not known?
模块级与 input 级参数表不同:imuxsock 的 Socket 是 input 参数(写在 input(type="imuxsock" ...)),SysSock.Use 才是 module 参数;8.2112.0 的 input 参数表里没有 SocketName。把参数挪到正确的对象层级即可。
Q5:故障恢复后消息迟迟不续传?
默认 action.resumeInterval 是 30 秒且指数退避,本实验从 B 恢复到消息送达约 7 秒(在重试窗口内);链式转发场景可显式调小 action.resumeInterval="10"(见 9.3)。
Q6:imfile 重启后重复采集或漏采?
WorkDirectory 下的 imfile-state:* 文件是断点依据:删了会重采、状态文件写不进去会漏采。确认 global(workDirectory) 指向的目录存在且实例用户可写。
十一、参考链接
- RainerScript 官方手册:https://www.rsyslog.com/doc/rainerscript/index.html
- 队列机制官方文档:https://www.rsyslog.com/doc/concepts/queues.html
- omfwd 模块手册:https://www.rsyslog.com/doc/configuration/modules/omfwd.html
- imfile 模块手册:https://www.rsyslog.com/doc/configuration/modules/imfile.html
- 属性替换器(replacer)手册:https://www.rsyslog.com/doc/configuration/templates.html
- 本专栏相关篇目:《rsyslog 8.2608.0 介绍与选型指南》《Ubuntu 22.04 安装 rsyslog 8.2112.0 指南》