工业网关 / 边缘设备最典型的日志诉求:本地留一份带轮转的详情日志方便现场排查,同时把关键错误实时送到远端日志中心做集中监控告警。
架构
┌──────────── 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 right
2. 板子 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:514
busybox 轻量系统(无 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"
int main(void) {
int rc;
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();
return 0;
}
交叉编译(Arm Linux):
arm-linux-gnueabihf-gcc zlog_syslog_dual.c -o app -lzlog -lpthread
4. 验证远程收到
在中心服务器用 nc 抓包快速验证(UDP 514):
nc -ul 514 # 应能收到板子发来的 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 队列。
如果觉得不错,欢迎 点赞、收藏、转发 ,如果想第一时间收到推送,也可以给个星标⭐~~