rsyslog 8.2112.0 配置参数详解

rsyslog v8 配置体系七大构件拆解:global/module/input/template/RainerScript/ruleset/action 与 queue 参数逐项实测,含双实例自环转发、模板转发的 tcpdump 排障实录、下游故障队列零丢失续传演练,全部回显实机采集。

rsyslog监控rsyslog2026/10/20

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 周期统计输出

二、前置条件

  • 系统已安装 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 字典序合并)决定作用:

  1. global(...) 全局参数(工作目录、内部日志等);
  2. module(load="...") 模块装载——没装载的模块,其 input/action 参数写上去直接报错;
  3. template(...) 模板定义(必须先于引用它的 action?不一定——rsyslog 允许任意顺序,但引用不存在名字会在校验期报 Could not find template);
  4. input(...) 输入对象(决定日志从哪进);
  5. ruleset(name="...") { ... } 规则集与 action(决定日志怎么路由出去);
  6. 不在任何 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 配置参数按对象分七类,实验配置(完整文件见五~八章各节)覆盖了其中六类:

对象语法形态职责本文实测覆盖
globalglobal(param="value")全局参数(工作目录等)✅ workDirectory
modulemodule(load="imxxx" param="value")装载输入/输出/解析模块✅ imuxsock/imfile/imudp/imtcp/impstats
inputinput(type="imxxx" param="value")实例化一个输入源✅ imfile 文件监听、imudp/imtcp 端口监听、imuxsock 自定义 socket
templatetemplate(name="..." type="...")定义输出格式✅ string 型模板 + 内置转发模板
rulesetruleset(name="...") { ... }路由流水线(过滤+动作)✅ coll/rcvudp/rcvtcp 三个规则集
actionaction(type="omxxx" param="value")单个输出动作✅ omfile/omfwd + 队列参数
legacy$指令 值($ 开头)v5 以前遗留语法,仍在兼容系统主配置自带(见安装篇 8.1),实验全用 v8 语法

💡 技术拓展:rsyslog 的配置语言不止 v8 RainerScript 一种——

形态语法特征状态
legacy $ 指令每行一条 $ActionFileDefaultTemplate ...兼容支持,Ubuntu 主配置大量使用
传统 selectorauth,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_ForwardFormatRFC3164 + 高精度时间转发格式omfwd 转发推荐(本文实验实测采用)
RSYSLOG_SyslogProtocol23FormatRFC5424 完整格式标准协议转发

7.2 转发必须用转发模板:一次完整的排障实录

这是本文最重要的坑,完整还原定位过程。初版实验里,A 实例的 omfwd 也用了 mytpl(文件模板),结果 B 实例的 TCP 接收文件迟迟不出内容:

  • 现象:forwarded-udp.log 正常,forwarded-tcp.log 不存在;而 A 端 impstats 显示 TCP action processed=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 队列有三种模式,选型决定「不丢日志」的承诺等级——

模式参数取值原理/特点适用场景
directqueue.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文件默认模板指定输出格式
flushOnTXEndon每个写事务结束即 flush(掉电少丢但 IO 多)
asyncWritingoff开启后台写(配合 flushInterval)
dynaFileCacheSize127动态文件缓存槽位(用 dynaFile 时关注)
createDirson自动创建父目录

九、生产配置模板

以下三份模板按资源档位给出,变量只保留端口与路径,其余为实测可跑的完整形态。

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) 指向的目录存在且实例用户可写。

十一、参考链接