工业网关 / 边缘设备最典型的日志诉求:本地留一份带轮转的详情日志方便现场排查,同时把关键错误实时送到远端日志中心做集中监控告警。
架构
┌──────────── app (zlog) ────────────┐ │ category "app" │ │ ├─ INFO+ ──→ /var/log/app.log│ 本地文件(轮转) ← 通道1 │ └─ ERROR/FATAL ──→ >syslog ───────┤ └────────────────────────────────────┘ │ 本地 rsyslogd │ *.* @logserver:514 (UDP) ▼ 远程日志中心 (rsyslog / ELK / Loki ...) ← 通道2- 通道 1(本地):zlog 把业务日志写到本地文件,带大小轮转,便于现场
tail排障。 - 通道 2(远程):zlog 把 ERROR/FATAL 同时送到系统 syslog,由板子上的
rsyslogd转发到远程日志中心,做集中存储 / 告警。
1. zlog.conf:一个 category,两路输出
[global] strict init = true log level = DEBUG [formats] file_fmt = "%d(%Y-%m-%d %H:%M:%S.%ms) [%V] %m%n" ; %V 才是级别,%p 是进程 PID sys_fmt = "%m" ; 送 syslog 只放消息体 [rules] # 通道1:日常日志落本地文件,带大小轮转 app.INFO "/var/log/app.log", 10MB * 5 ~; file_fmt # 通道2:ERROR/FATAL 同时进系统 syslog(再被 rsyslogd 转发出去) # >syslog 必须带 facility,如 LOG_LOCAL0 / LOG_USER app.ERROR >syslog, LOG_LOCAL0 ; sys_fmt app.FATAL >syslog, LOG_LOCAL0 ; sys_fmt
>syslog是 zlog 内置的输出目标:它会把日志按级别映射成 syslog 优先级(DEBUG→LOG_DEBUG、INFO→LOG_INFO……),并用 category 名作为ident调用系统syslog()。无需在代码里再 openlog,zlog 自己搞定。
验证配置文件:
LD_LIBRARY_PATH=. ./zlog-chk-conf ./zlog.conf --[./zlog.conf]syntax right2. 板子 rsyslog:把 syslog 转发到远程
在板子的 rsyslog 配置里加一条转发规则(Debian / Yocto 系通常放/etc/rsyslog.d/30-remote.conf):
# UDP 转发全部日志到中心服务器(@ 是 UDP,@@ 是 TCP)*.* @192.168.1.100:514# 只想转发 app 的 ERROR 以上,可限定设施,例如:# local0.* @192.168.1.100:514busybox 轻量系统(无 rsyslogd)则改/etc/syslog.conf或syslog-ng.conf的转发语句,语义类似。
改完重启守护进程让配置生效:
# systemd 系统systemctl restart rsyslog# 老式 init / busybox/etc/init.d/rsyslog restart# 或 kill -HUP $(cat /var/run/rsyslogd.pid)3. 应用代码(只管 zlog,双通道自动发生)
/* zlog_syslog_dual.c —— 本地文件 + 远程 syslog 双通道 */#include<stdio.h>#include"zlog.h"intmain(void){intrc;zlog_category_t*zc;rc=zlog_init("zlog.conf");if(rc){printf("zlog_init failed\n");return-1;}zc=zlog_get_category("app");if(!zc){zlog_fini();return-2;}zlog_info(zc,"app started, pid=%d",(int)getpid());/* 仅本地文件 */zlog_warn(zc,"config item missing, use default");/* 仅本地文件 */zlog_error(zc,"db connect failed: %m");/* 文件 + 远程syslog */zlog_fatal(zc,"cannot continue, going down");/* 文件 + 远程syslog */zlog_fini();return0;}交叉编译(Arm Linux):
arm-linux-gnueabihf-gcc zlog_syslog_dual.c-oapp-lzlog-lpthread4. 验证远程收到
在中心服务器用nc抓包快速验证(UDP 514):
nc-ul514# 应能收到板子发来的 ERROR/FATAL 行生产环境中心侧通常用 rsyslog 服务端、或 Vector / Filebeat 接 ELK、或 Promtail 接 Loki 做可视化与告警。
5. 想要更细的设施(facility)控制?——混合 libc syslog 方案
zlog 的>syslog走的是系统默认设施,若想把 app 日志单独归到local0以便在中心侧精准过滤,可在关键路径直接用 libc 的syslog()(互补而非替代 zlog):
#include<syslog.h>#include"zlog.h"/* 初始化时挂上系统 syslog 的 ident/facility */openlog("myapp",LOG_PID,LOG_LOCAL0);/* 业务正常日志:zlog 管本地文件 */zlog_error(zc,"critical op failed: %m");/* 同一事件再同步到系统 syslog(最终被 rsyslog 转发到 local0.*) */syslog(LOG_ERR,"critical op failed: %m");closelog();板子 rsyslog 侧只需转发该设施:local0.* @192.168.1.100:514。
⚠️两点提醒
- 两种方式任选其一即可,不要重复:纯 zlog
>syslog最干净;需要自定义 facility 时才用「zlog 文件 + libc syslog 双发」的混合写法。- 远程用 UDP(
@)零握手、低延迟但可能丢;对可靠性要求高改 TCP(@@),代价是连接断开时可能阻塞 rsyslog 队列。