rsyslog远程日志配置核心卡点在于协议语法(@为udp、@@为tcp)、模板必须显式调用(?templatename)且后接&~终止处理,否则日志重复落盘或丢失;服务端需按协议加载对应模块并监听,nat环境下$fromhost-ip不可靠,调试须用rsyslogd -n1校验语法、journalctl查错误、tcpdump抓包验证。

rsyslog 远程日志配置不是“开个端口+写一行转发”就能跑通的事,核心卡点在协议选择、模板作用域和 &~ 的位置——漏掉任意一个,日志就重复落盘或根本收不到。
UDP 和 TCP 转发写法差异必须分清
客户端配置里,@ 表示 UDP,@@ 表示 TCP,这是硬性语法,写反了服务端收不到任何数据。UDP 无连接、低开销但不保证送达;TCP 有连接、可重传、适合跨网段或高可靠性场景。
-
*.*@192.168.1.100:514:走 UDP,适合内网短距离、吞吐优先的场景 -
*.*@@192.168.1.100:514:走 TCP,防火墙需放行,服务端必须加载imtcp模块并启用$InputTCPServerRun 514 - 若服务端只开了
imudp却收到@@请求,日志静默丢弃,ss -tlnp | grep :514看不到监听,tcpdump -i any port 514也抓不到包
/etc/rsyslog.d/ 下的模板必须显式引用
很多人把 $template 写进 /etc/rsyslog.d/01-remote.conf 就以为生效了,其实不会——rsyslog 加载顺序是先读 /etc/rsyslog.conf,再按字母序读 /etc/rsyslog.d/*.conf,但模板定义后必须在规则中用 ?TemplateName 显式调用,否则只是废文本。
- 正确写法:
$template RemoteLogs,"/var/log/%FROMHOST-IP%/%PROGRAMNAME%.log"*.* ?RemoteLogs &~ -
&~必须紧跟在模板调用后,表示“这条规则匹配后终止处理”,否则日志会既写进远程目录,又继续往下走默认规则,落到/var/log/messages里 - 模板名大小写敏感,
?remotelogs不等于?RemoteLogs
服务端收日志时,$fromhost-ip 可能为空
当客户端通过 NAT 或负载均衡器转发日志时,$fromhost-ip 会变成中间设备 IP,甚至为 127.0.0.1。此时用 if $fromhost-ip == '192.168.1.10' 做路由会失效。
- 更稳妥的方式是让客户端在日志里带标识字段,比如加
$ActionForwardDefaultTemplate RSYSLOG_ForwardFormat后,在发送前插入hostname或自定义 tag - 或者改用
$inputname(如imtcp)配合$inputname == 'imtcp'判断来源协议类型 - 调试时可用
logger "test from $(hostname)"+tail -f /var/log/remote/*.log实时验证字段是否可达
重启后没生效?先查这三件事
rsyslog 不像 nginx 那样报错明显,配置错常表现为“看起来在运行,但日志就是不出现”。最该盯住的是模块加载、语法错误和权限路径。
- 执行
rsyslogd -N1检查配置语法,输出rsyslogd: run failed with error -2112就说明某行有错(比如少空格、$template后多空行) - 确认
/var/log/下目标目录存在且rsyslog用户(通常是syslog或root)有写权限,chown syslog:adm /var/log/remote - systemd 日志里搜关键字:
journalctl -u rsyslog | grep -i "fail\|error\|imtcp",常见报错如imtcp: could not create listener on port 514: Address already in use
真正难调的从来不是怎么写配置,而是怎么确认那条日志到底从哪来、被哪条规则拦下、又在哪个环节被静默丢弃——rsyslogd -dn 调试模式虽然输出爆炸,但它是唯一能看清整条链路的地方。











