上一篇讲了 syslog 的 C 接口,并埋了个伏笔:多进程示例里父进程用 LOG_LOCAL0、子进程用 LOG_LOCAL1。光在代码里分好设施(facility)还不够——真正决定"这些日志去哪个文件、要不要发到中心服务器"的,是系统日志守护进程的配置文件。
Arm Linux 上跑完整 rsyslogd 的板子(Yocto/Debian 系),份配置是 /etc/rsyslog.conf。把 local0/local1 落入不同文件,再把全部日志可靠地转发到远程日志服务器。
rsyslog 配置文件由三部分组成:
imuxsock 接收 /dev/log 上的应用日志,imklog 接收内核日志。$WorkDirectory、$FileOwner 等。设施.级别 动作,一行一条。选择器(selector)写法:facility.priority,例如 local0.info 表示 local0 设施、info 及以上(注意:级别是"及以上")。* 是通配。
动作(action)可以是:
/var/log/parent.log@host:port(UDP)、@@host:port(TCP)*(控制台) 等rsyslog 的规则是从上到下逐条匹配执行
rsyslog 的规则是从上到下逐条匹配执行,规则顺序:先远程转发 → 再写本地文件 → 最后 stop,同时优化队列作用范围(仅给转发加异步队列,不影响本地写文件性能)。
如果板子是老派 rsyslog(或习惯看传统写法),直接用这套:
# /etc/rsyslog.conf —— 传统格式模板# ---------- 1. 模块 ----------$ModLoad imuxsock # 监听 /dev/log,接收应用 syslog()$ModLoad imklog # 接收内核日志# ---------- 2. 全局 ----------$WorkDirectory /var/spool/rsyslog # 队列工作目录(转发缓存用)$FileOwner root$FileCreateMode 0644# ---------- 3. 通用系统日志(排除 local0/local1,避免重复)----------*.info;mail.none;authpriv.none;cron.none;local0.none;local1.none /var/log/messages# ---------- 4. 按设施分文件(对接上篇多进程示例)----------local0.* /var/log/parent.loglocal1.* /var/log/child.log# ---------- 5. 远程转发(TCP,全部日志)----------*.* @@192.168.1.100:514# ---------- 6. 内核/紧急日志落本地,不转发也行 ----------*.emerg *要点说明:
local0.none;local1.none 让 local0/local1不再进/var/log/messages,只进各自专用文件,避免一份日志写两处。@@ 双 at 表示 TCP;要 UDP 改成单个 @:*.* @192.168.1.100:514。修改后内容:
# /etc/rsyslog.conf configuration file for rsyslog## For more information install rsyslog-doc and see# /usr/share/doc/rsyslog-doc/html/configuration/index.html##################### MODULES #####################module(load="imuxsock") # provides support for local system loggingmodule(load="imklog") # provides kernel logging support#module(load="immark") # provides --MARK-- message capability# 本机作为发送端无需开启 imtcp/imudp;仅接收远程日志时才打开#module(load="imtcp")#input(type="imtcp" port="514")#module(load="imudp")#input(type="imudp" port="514")############################### GLOBAL DIRECTIVES ###############################$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat$FileOwner root$FileGroup adm$FileCreateMode 0640$DirCreateMode 0755$Umask 0022$WorkDirectory /var/spool/rsyslog$IncludeConfig /etc/rsyslog.d/*.conf################### RULES ##################### First some standard log files. Log by facility.#auth,authpriv.* /var/log/auth.log*.*;auth,authpriv.none -/var/log/syslog#cron.* /var/log/cron.logdaemon.* -/var/log/daemon.logkern.* -/var/log/kern.loglpr.* -/var/log/lpr.logmail.* -/var/log/mail.loguser.* -/var/log/user.log## Logging for the mail system.#mail.info -/var/log/mail.infomail.warn -/var/log/mail.warnmail.err /var/log/mail.err# ============================================================# 【修正】local0 / local1 处理逻辑# 顺序:先转发 → 再写本地文件 → 最后 stop 终止# ============================================================# 1. 远程 TCP 转发(必须放在 stop 之前)# 仅给转发动作配置异步磁盘队列,远端不可达时缓存本地、恢复后自动重发$ActionQueueType LinkedList$ActionQueueFileName fwd_local01$ActionQueueMaxDiskSpace 1g$ActionQueueSaveOnShutdown on$ActionQueueDiscardMark 50000$ActionQueueDiscardSeverity 8# ============================================================# 【新增】远程转发规则# 把整机的所有日志(含 local0/local1 如果你想一起转)发到日志服务器# 语法:# @@host:port → TCP# @host:port → UDP# 下面给两种写法,按需要选一个# ============================================================# 写法 A:转发全部日志(含 local0/local1),推荐*.* @@logserver.example.com:514# 写法 B:只转发 local0 和 local1(更细粒度)#local0.* @@logserver.example.com:514#local1.* @@logserver.example.com:514# 写法 C:走 UDP(不保证送达,但开销小)#*.* @logserver.example.com:514# 重置队列模式,不影响后续本地文件写入$ActionQueueType Direct# 2. 写入本地独立文件local0.* /var/log/local0.loglocal1.* /var/log/local1.log# 3. 终止处理,避免日志继续流入 syslog/messages 造成重复local0.* stoplocal1.* stop## Some "catch-all" log files.#*.=debug;\ auth,authpriv.none;\ news.none;mail.none;\ local0.none;local1.none -/var/log/debug*.=info;*.=notice;*.=warn;\ auth,authpriv.none;\ cron,daemon.none;\ mail,news.none;\ local0.none;local1.none -/var/log/messages## Emergencies are sent to everybody logged in.#*.emerg :omusrmsg:*生效指令:
# 1. 检查配置语法(务必先跑,避免改坏起不来)rsyslogd -N1 -f /etc/rsyslog.conf# 输出 "rsyslogd: End of config validation run. Bye." 表示 OK# 2. 重启服务systemctl restart rsyslog# 3. 验证logger -p local0.info "test local0 message"logger -p local1.warn "test local1 warning"tail /var/log/local0.logtail /var/log/local1.log# 4. 验证远程转发(在日志服务器上抓)# 服务器端开 TCP 514 监听看能否收到tcpdump -i eth0 port 514# 或在服务器端 rsyslog 开 imtcp 后看 /var/log/syslog新版本 rsyslog(v8+,Yocto/Debian 新版默认)推荐用 module() / action() 结构,可读性和可控性都更好,转发还能加磁盘辅助队列,网络抖动也不丢日志:
# /etc/rsyslog.conf —— RainerScript 现代格式模板# ---------- 1. 模块 ----------module(load="imuxsock") # 应用日志 (/dev/log)module(load="imklog") # 内核日志# ---------- 2. 全局 ----------global(workDirectory="/var/spool/rsyslog")# ---------- 3. 通用系统日志(排除 local0/local1)----------*.info;mail.none;authpriv.none;cron.none;local0.none;local1.none action(type="omfile" file="/var/log/messages")# ---------- 4. 按设施分文件 ----------local0.* action(type="omfile" file="/var/log/parent.log" createDirs="on")local1.* action(type="omfile" file="/var/log/child.log" createDirs="on")# ---------- 5. 远程转发(TCP + 可靠队列)----------*.* action(type="omfwd" target="192.168.1.100" port="514" protocol="tcp" action.resumeRetryCount="-1"# -1 = 无限重试,断网不丢 action.resumeInterval="10"# 每 10s 重试一次 queue.type="linkedList"# 内存队列 queue.saveOnShutdown="on"# 关机落盘,防丢 queue.maxDiskSpace="1g"# 磁盘队列上限 queue.fileName="fwdq") # 磁盘队列文件名前缀# ---------- 6. 紧急日志广播给在线用户 ----------*.emerg :omusrmsg:*为什么模板 B 的转发更稳:queue.type="linkedList" + queue.saveOnShutdown="on" + queue.fileName 组成"内存队列 + 断电落盘"的磁盘辅助队列。中心服务器宕机期间,日志先缓存在板子 /var/spool/rsyslog 里,action.resumeRetryCount="-1" 保证恢复后自动补传——这对工业网关断网场景非常关键。
💡 想用 UDP?把
protocol="tcp"改成protocol="udp",并去掉磁盘队列(UDP 本身不可靠)。
回顾上一篇 syslog_fork.c:父进程 openlog("syslog_parent", LOG_PID, LOG_LOCAL0),子进程 openlog("syslog_child", LOG_PID, LOG_LOCAL1)。套用上面的配置:
# 编译运行上篇的程序后:./syslog_fork# 父进程日志(LOG_LOCAL0)落在:tail -f /var/log/parent.log# 子进程日志(LOG_LOCAL1)落在:tail -f /var/log/child.log# 同时全部日志(含 local0/local1)被转发到 192.168.1.100:514一行 logger 也能快速验证设施路由:
logger -t syslog_parent -p local0.info "test from shell: parent line"logger -t syslog_child -p local1.warning "test from shell: child warn"rsyslog 自己不轮转日志文件,得靠 logrotate。给两个专用日志加配置:
# /etc/logrotate.d/armapp/var/log/parent.log /var/log/child.log { missingok notifempty size 10M # 超过 10MB 切 rotate 5 # 保留 5 份 compress delaycompress postrotate /usr/bin/killall -HUP rsyslogd 2>/dev/null || true# 通知重新打开文件 endscript}⚠️ 不配 logrotate,板子
/var/log迟早写满,轻则日志停写,重则业务分区爆盘。工业设备务必配上。
在 /etc/logrotate.d/ 目录下创建配置文件(例如 local-syslog),专门管理 local0.log 和 local1.log,参数与系统默认 rsyslog 轮转规则保持一致,便于统一维护。
/etc/logrotate.d/local-syslogcat > /etc/logrotate.d/local-syslog << 'EOF'/var/log/local0.log /var/log/local1.log { weekly rotate 8 missingok notifempty compress delaycompress create 0640 root adm sharedscripts postrotate systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true endscript}EOFweekly | daily 每天轮转 |
rotate 8 | |
missingok | |
notifempty | |
compress | |
delaycompress | .1 文件不压缩,下次轮转再压缩为 .2.gz,方便查看最近的历史日志 |
create 0640 root adm | |
sharedscripts | postrotate 仅执行一次 |
postrotate ... endscript |
这是生产环境最常用的模式:每天至少轮转1次,单日日志超出指定大小时提前轮转,兼顾归档规律性和大文件管控。 使用 daily + maxsize 组合实现,逻辑:
maxsize,下次 logrotate 运行时会提前触发轮转/etc/logrotate.d/local-syslog)# 写入干净的配置(按天+按大小组合模式)cat > /etc/logrotate.d/local-syslog << 'EOF'/var/log/local0.log /var/log/local1.log { daily maxsize 100M rotate 30 missingok notifempty compress delaycompress create 0640 root adm sharedscripts postrotate systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true endscript}EOFdaily:按天为轮转周期,保底每天轮转一次maxsize 100M:单文件超过 100MB 时提前轮转,可根据实际磁盘情况调整为 50M/200M 等rotate 30:保留 30 份历史日志,对应约 30 天的归档(如果当天多次轮转,保留份数会对应增加)如果不需要每日固定轮转,仅当日志大小达到阈值才轮转,不受时间限制,使用 size 参数替代 daily + maxsize:
/var/log/local0.log /var/log/local1.log { size 100M rotate 30 missingok notifempty compress delaycompress create 0640 root adm sharedscripts postrotate systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true endscript}注意:
size模式下,如果日志一直没达到阈值,可能长期不轮转,不利于日志归档管理。
logrotate 本身是被动触发的,默认通过系统 cron 每天执行一次(脚本位于 /etc/cron.daily/logrotate)。
maxsize/size 一天最多检查一次,即使日志半天就涨到阈值,也要等到次日 cron 执行才会轮转# 复制每日执行脚本到每小时目录cp /etc/cron.daily/logrotate /etc/cron.hourly/logrotate执行后系统每小时都会运行一次 logrotate,大小阈值的检测延迟会缩短到 1 小时以内。
logrotate 默认通过系统 cron 每日自动执行,无需额外启动服务。配置完成后可手动验证:
语法调试(不实际执行,仅检查配置是否正确)
logrotate -d /etc/logrotate.d/local-syslog强制手动轮转一次(验证实际效果)
logrotate -f /etc/logrotate.d/local-syslog检查结果
ls -l /var/log/local*.log*正常会看到 local0.log.1、local1.log.1 等轮转文件,且新的 local0.log/local1.log 权限为 0640 root adm。

rsyslogd -N1 # 只检查配置,不启动;有错直接报出行号kill -HUP $(cat /var/run/rsyslogd.pid) # 平滑重载,不丢连接# 或systemctl restart rsyslogps | grep rsyslogd板子若是 BusyBox(busybox-syslogd),不支持本篇这套 rsyslog 语法!它只认简单的 /etc/syslog.conf(格式为 *.INFO /var/log/messages 这类),没有远程转发/磁盘队列能力。需要高级功能请上完整 rsyslog 包。LOG_LOCAL0~7 区分模块/进程,配置文件侧用 localN.* 文件 分流。local0.none;local1.none,避免一份日志写两处。resumeRetryCount=-1 + saveOnShutdown),断网不丢。rsyslogd -N1 校验,再 kill -HUP 平滑重载。logrotate,否则 /var/log 写满拖垮整机。syslogd 不支持 rsyslog 语法与高级转发,需要请换完整 rsyslog。