Linux 日志流水线深度解析:syslog() → journald → rsyslog → /var/log/syslog

基于:glibc、systemd journald、rsyslog及MAN文档

适用系统:Ubuntu


1. 总体架构

复制代码
  ┌─────────────┐
  │ Application │  syslog(3) 调用
  └──────┬──────┘
         │ write() to /dev/log
         ▼
  ┌─────────────────────────────────────┐
  │ /dev/log → /run/systemd/journal/    │  ← systemd-journald-dev-log.socket
  │              dev-log                 │      (journald 拥有此 socket)
  └──────────────┬──────────────────────┘
         │
         ▼
  ┌─────────────────────────────────────┐
  │      systemd-journald               │  ← 结构化存储到 journal 文件
  │  (ForwardToSyslog=yes)              │      /var/log/journal/ 或 /run/log/journal/
  └──────────────┬──────────────────────┘
         │ 转发到 /run/systemd/journal/syslog
         ▼
  ┌─────────────────────────────────────┐
  │  syslog.socket → rsyslogd           │  ← rsyslog 的 imuxsock 模块读取
  │  (imuxsock)                         │
  └──────────────┬──────────────────────┘
         │ 根据 /etc/rsyslog.conf 规则
         ▼
  ┌─────────────────────────────────────┐
  │      /var/log/syslog                │  ← 传统文本日志文件
  │      /var/log/auth.log              │
  │      /var/log/kern.log              │
  └─────────────────────────────────────┘

2. 逐层深度解析

2.1 应用层:syslog(3) 函数

函数原型
c 复制代码
#include <syslog.h>

void openlog(const char *ident, int option, int facility);
void syslog(int priority, const char *format, ...);
void closelog(void);
调用流程(glibc 源码分析)

glibc 中 syslog() 的实现位于 misc/syslog.c。核心逻辑:

  1. 首次调用时初始化 :如果尚未 openlog(),自动调用 openlog(NULL, 0, LOG_USER)
  2. 构造消息 :格式化时间戳、ident(程序名)、PID(如果设置了 LOG_PID
  3. 打开 /dev/log socketsocket(AF_UNIX, SOCK_DGRAM, 0)connect()/dev/log
  4. 发送消息sendto()write() 发送格式化后的 syslog 协议消息

关键源码片段逻辑(伪代码):

c 复制代码
void __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap) {
    // 1. 构造消息头: "<PRI>timestamp hostname program[pid]: "
    // 2. 格式化用户消息
    // 3. 打开 /dev/log (AF_UNIX, SOCK_DGRAM)
    // 4. sendto(fd, buf, len, 0, &syslog_addr, addr_len)
    // 5. 如果失败且设置了 LOG_CONS,尝试写控制台
}

发送的消息格式(传统 BSD syslog 协议):

复制代码
<PRI>timestamp hostname program[pid]: message

其中 PRI = facility * 8 + level。例如 LOG_USER | LOG_INFOPRI = (1<<3) | 6 = 14,消息以 <14> 开头。

重要难点:为什么是 /dev/log

/dev/log 是一个 Unix Domain Socket (AF_UNIX, SOCK_DGRAM),传统上由 syslogd/rsyslogd 创建。在 systemd 系统中:

复制代码
/dev/log → /run/systemd/journal/dev-log

这个 socket 由 systemd-journald-dev-log.socket 单元创建并归 journald 所有。


2.2 传输层:/dev/log → journald

systemd-journald-dev-log.socket 单元
ini 复制代码
[Socket]
ListenDatagram=/run/systemd/journal/dev-log
PassCredentials=yes
PassSecurity=yes
Service=systemd-journald.service
SocketMode=0666
Symlinks=/dev/log
ReceiveBuffer=8M
SendBuffer=8M

关键点:

  • ListenDatagram :创建一个 DGRAM 类型 的 Unix socket
  • Symlinks=/dev/log :自动创建 /dev/log → /run/systemd/journal/dev-log 符号链接
  • PassCredentials=yes :接收 SCM_CREDENTIALS 辅助数据,获取发送进程的 PID、UID、GID
  • SocketMode=0666:任何人都可以写入
journald 接收处理

当 journald 收到消息后:

  1. 解析 syslog 协议:提取 PRI(facility + level)、时间戳、主机名、程序名
  2. 注入元数据 :自动添加 _PID=, _UID=, _GID=, _COMM=, _EXE=, _SYSTEMD_CGROUP= 等字段
  3. 速率限制 :默认 RateLimitIntervalSec=30s, RateLimitBurst=10000
  4. 存储 :写入 journal 文件(/var/log/journal/<machine-id>//run/log/journal/
重要难点:SCM_CREDENTIALS

这是 Unix socket 的 辅助数据(ancillary data) 机制。当发送方通过 Unix socket 发送消息时,内核会自动附加发送进程的真实凭据(PID、UID、GID),发送方无法伪造。这使得 journald 能可靠地知道谁发送了日志,即使发送方声称自己是其他程序。

c 复制代码
// 发送方示例(由 glibc syslog() 内部完成)
struct msghdr msg = {0};
struct iovec iov;
char buf[4096];
union {
    struct cmsghdr cmsg;
    char control[CMSG_SPACE(sizeof(struct ucred))];
} control;

// 填充消息...
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control.control;
msg.msg_controllen = sizeof(control.control);

struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_CREDENTIALS;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg);
cred->pid = getpid();    // 内核会验证并覆盖
cred->uid = getuid();    // 内核会验证并覆盖
cred->gid = getgid();    // 内核会验证并覆盖

sendmsg(fd, &msg, 0);

2.3 转发层:journald → rsyslog

journald.conf 配置
ini 复制代码
# /usr/lib/systemd/journald.conf.d/syslog.conf
[Journal]
ForwardToSyslog=yes

ForwardToSyslog=yes 时,journald 在收到每条日志后,会将其转发/run/systemd/journal/syslog socket。

syslog.socket 单元
ini 复制代码
[Socket]
ListenDatagram=/run/systemd/journal/syslog
SocketMode=0666
PassCredentials=yes
PassSecurity=yes
ReceiveBuffer=8M

这个 socket 用于激活 rsyslog 服务。当 journald 向此 socket 写入消息时,systemd 会启动 rsyslog.service(如果尚未运行)。

重要难点:双 socket 架构
复制代码
/dev/log (journald-dev-log.socket)     ← 应用写入这里
    ↓ journald 接收并处理
    ↓ ForwardToSyslog=yes
/run/systemd/journal/syslog (syslog.socket)  ← rsyslog 从这里读取

为什么需要两个 socket?

  • dev-log socket:接收原始 syslog 消息,由 journald 直接管理
  • syslog socket:用于 journald 向传统 syslog 守护进程转发消息

这样 journald 可以先处理消息(注入元数据、速率限制、结构化存储),再将处理后的消息转发给 rsyslog 做传统文件输出。


2.4 输出层:rsyslog → /var/log/syslog

rsyslog 配置
nginx 复制代码
# /etc/rsyslog.conf
module(load="imuxsock")   # 读取 Unix socket 输入

# /etc/rsyslog.d/50-default.conf
*.*;auth,authpriv.none    -/var/log/syslog
auth,authpriv.*            /var/log/auth.log
kern.*                     -/var/log/kern.log
imuxsock 模块

imuxsock(Input Module Unix Socket)是 rsyslog 的输入模块,默认监听 /dev/log。但在 systemd 系统中:

  • /dev/log 已被 journald 占用
  • rsyslog 改为从 /run/systemd/journal/syslog 读取(通过 syslog.socket 激活)

imuxsock 的工作流程:

  1. 打开 /run/systemd/journal/syslog socket(或传统 /dev/log
  2. 接收 syslog 协议消息
  3. 解析 facility 和 level
  4. 匹配规则(selector + action)
  5. 写入对应的日志文件
规则解析

*.*;auth,authpriv.none -/var/log/syslog 为例:

部分 含义
*.* 所有 facility 的所有 level
;auth,authpriv.none 排除 auth 和 authpriv facility
-/var/log/syslog 写入文件,- 表示每次写后不同步(提高性能)

3. 完整时序图

/var/log/syslog rsyslogd (imuxsock) /run/systemd/journal/syslog Journal File systemd-journald /dev/log (socket) glibc syslog() Application /var/log/syslog rsyslogd (imuxsock) /run/systemd/journal/syslog Journal File systemd-journald /dev/log (socket) glibc syslog() Application #mermaid-svg-HtC0qRgZN8YOrrfQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HtC0qRgZN8YOrrfQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HtC0qRgZN8YOrrfQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HtC0qRgZN8YOrrfQ .error-icon{fill:#552222;}#mermaid-svg-HtC0qRgZN8YOrrfQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HtC0qRgZN8YOrrfQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HtC0qRgZN8YOrrfQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HtC0qRgZN8YOrrfQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HtC0qRgZN8YOrrfQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HtC0qRgZN8YOrrfQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HtC0qRgZN8YOrrfQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HtC0qRgZN8YOrrfQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HtC0qRgZN8YOrrfQ .marker.cross{stroke:#333333;}#mermaid-svg-HtC0qRgZN8YOrrfQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HtC0qRgZN8YOrrfQ p{margin:0;}#mermaid-svg-HtC0qRgZN8YOrrfQ .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-HtC0qRgZN8YOrrfQ text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-HtC0qRgZN8YOrrfQ .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-HtC0qRgZN8YOrrfQ .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-HtC0qRgZN8YOrrfQ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-HtC0qRgZN8YOrrfQ .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-HtC0qRgZN8YOrrfQ #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-HtC0qRgZN8YOrrfQ .sequenceNumber{fill:white;}#mermaid-svg-HtC0qRgZN8YOrrfQ #sequencenumber{fill:#333;}#mermaid-svg-HtC0qRgZN8YOrrfQ #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-HtC0qRgZN8YOrrfQ .messageText{fill:#333;stroke:none;}#mermaid-svg-HtC0qRgZN8YOrrfQ .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-HtC0qRgZN8YOrrfQ .labelText,#mermaid-svg-HtC0qRgZN8YOrrfQ .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-HtC0qRgZN8YOrrfQ .loopText,#mermaid-svg-HtC0qRgZN8YOrrfQ .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-HtC0qRgZN8YOrrfQ .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-HtC0qRgZN8YOrrfQ .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-HtC0qRgZN8YOrrfQ .noteText,#mermaid-svg-HtC0qRgZN8YOrrfQ .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-HtC0qRgZN8YOrrfQ .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-HtC0qRgZN8YOrrfQ .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-HtC0qRgZN8YOrrfQ .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-HtC0qRgZN8YOrrfQ .actorPopupMenu{position:absolute;}#mermaid-svg-HtC0qRgZN8YOrrfQ .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-HtC0qRgZN8YOrrfQ .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-HtC0qRgZN8YOrrfQ .actor-man circle,#mermaid-svg-HtC0qRgZN8YOrrfQ line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-HtC0qRgZN8YOrrfQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 格式化消息\n<14> ... hello world /dev/log ->> /run/systemd/journal/dev-log 1.解析 syslog PRI\n2.注入元数据(_PID,_UID)\n3.速率限制检查 1.解析 facility/level\n2.匹配规则\n3.格式化输出 altForwardToSyslog=yes syslog(LOG_INFO, "hello world")sendto() DGRAM接收消息 + SCM_CREDENTIALS写入结构化 journal转发 syslog 消息imuxsock 接收写入 /var/log/syslog


4. 实践 Demo

4.1 基础 Demo:C 程序调用 syslog()

c 复制代码
// demo_syslog.c
#include <syslog.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    // 打开日志连接
    openlog("mydemo", LOG_PID | LOG_CONS, LOG_USER);

    printf("PID: %d\n", getpid());
    printf("正在发送日志到 syslog...\n");

    // 发送不同级别的日志
    syslog(LOG_EMERG,   "=== EMERG: 系统不可用 ===");
    syslog(LOG_ALERT,   "=== ALERT: 必须立即处理 ===");
    syslog(LOG_CRIT,    "=== CRIT: 严重条件 ===");
    syslog(LOG_ERR,     "=== ERR: 错误条件 ===");
    syslog(LOG_WARNING, "=== WARNING: 警告 ===");
    syslog(LOG_NOTICE,  "=== NOTICE: 正常但重要 ===");
    syslog(LOG_INFO,    "=== INFO: 信息消息 ===");
    syslog(LOG_DEBUG,   "=== DEBUG: 调试消息 ===");

    // 使用 %m 打印 errno
    FILE *f = fopen("/nonexistent/file", "r");
    if (!f) {
        syslog(LOG_ERR, "打开文件失败: %m");
    }

    closelog();
    printf("完成!请查看以下位置:\n");
    printf("  1. journalctl -f  (实时查看 journal)\n");
    printf("  2. tail -f /var/log/syslog  (查看传统日志)\n");
    printf("  3. journalctl _PID=%d  (过滤此进程)\n", getpid());

    return 0;
}

编译运行:

bash 复制代码
gcc -o demo_syslog demo_syslog.c
./demo_syslog

4.2 实时观察流水线

终端 1:实时观察 journal

bash 复制代码
journalctl -f -n 0

终端 2:实时观察 syslog 文件

bash 复制代码
tail -f /var/log/syslog

终端 3:运行 demo

bash 复制代码
./demo_syslog

你会看到:

  • journalctl 终端几乎立即显示日志(毫秒级)
  • syslog 终端也很快显示(journald 转发 + rsyslog 处理)

4.3 验证流水线各环节

bash 复制代码
# 1. 验证 /dev/log 指向 journald
ls -la /dev/log
# 输出: lrwxrwxrwx ... /dev/log -> /run/systemd/journal/dev-log

# 2. 验证 journald 拥有 dev-log socket
ss -xlp | grep dev-log
# 输出: ... /run/systemd/journal/dev-log ... users:(("systemd-journal",...))

# 3. 验证 syslog socket
ss -xlp | grep syslog
# 输出: ... /run/systemd/journal/syslog ...

# 4. 查看 journald 配置
systemd-analyze cat-config systemd/journald.conf | grep ForwardToSyslog
# 输出: ForwardToSyslog=yes

# 5. 查看 rsyslog 配置
cat /etc/rsyslog.d/50-default.conf | head -10

# 6. 查看特定进程的 journal 日志
./demo_syslog  # 记下 PID
journalctl _PID=<PID> -o verbose  # 查看完整元数据

4.4 高级 Demo:观察 SCM_CREDENTIALS

c 复制代码
// demo_cred.c - 尝试伪造身份
#include <syslog.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    // 即使我们声称是 "root",journald 通过 SCM_CREDENTIALS
    // 知道真实的 PID/UID/GID
    openlog("fake-root", LOG_PID, LOG_AUTH);
    syslog(LOG_INFO, "我是谁?journald 知道真相");
    closelog();

    printf("查看 journald 记录的元数据:\n");
    printf("journalctl _PID=%d -o verbose --no-pager\n", getpid());

    return 0;
}

运行后查看:

bash 复制代码
journalctl _PID=<PID> -o verbose --no-pager

你会看到类似输出:

复制代码
_PID=12345
_UID=1000          ← 真实 UID,不是 0
_GID=1000
_COMM=demo_cred
_EXE=/home/user/demo_cred
SYSLOG_IDENTIFIER=fake-root

注意 _UID=1000 而不是 0------这是 SCM_CREDENTIALS 的作用,内核强制附加真实凭据,程序无法伪造。

4.5 调试:strace 观察系统调用

bash 复制代码
# 跟踪 syslog() 的系统调用
strace -e trace=network,socket,write -f ./demo_syslog 2>&1 | grep -E 'socket|connect|sendto|write'

典型输出:

复制代码
socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3
connect(3, {sa_family=AF_UNIX, sun_path="/dev/log"}, 110) = 0
sendto(3, "<14>Jun 12 14:30:00 mydemo[12345]: === INFO: 信息消息 ===", 60, 0, NULL, 0) = 60

5. 重要难点专题

5.1 难点一:为什么 /dev/log 只能被一个进程绑定?

Unix Domain Socket (DGRAM 类型) 的绑定规则:

  • 一个 socket 文件路径只能被一个进程 bind()
  • 多个进程可以同时打开同一个 DGRAM socket 进行读写
  • 关键在于:谁 bind 了路径 决定了谁接收消息

在 systemd 系统中:

  • systemd-journald-dev-log.socket 在 systemd 初始化时创建并 bind /run/systemd/journal/dev-log
  • /dev/log 作为符号链接指向它
  • 只有 journald 从该 socket 接收消息
  • rsyslog 不能直接读取 /dev/log,必须通过 journald 转发

5.2 难点二:ForwardToSyslog 的默认值

配置来源 ForwardToSyslog 值
编译默认值 no
/etc/systemd/journald.conf 注释掉,使用默认值 no
/usr/lib/systemd/journald.conf.d/syslog.conf yes(发行版覆盖)
有效值 yes

这意味着:

  • 编译时默认不转发到 syslog
  • 但 Ubuntu/Debian 通过 drop-in 文件覆盖为 yes
  • 这是为了兼容传统 syslog 工具链

5.3 难点三:rsyslog 的 imuxsock 到底从哪里读取?

传统上,imuxsock/dev/log 读取。但在 systemd 系统中:

  1. /dev/log 被 journald 占用
  2. rsyslog 通过 syslog.socket 被激活
  3. syslog.socket 监听 /run/systemd/journal/syslog
  4. journald 在 ForwardToSyslog=yes 时向此 socket 写入
  5. rsyslog 的 imuxsock 模块从 syslog.socket 继承的 fd 读取

实际上,imuxsock 也可以配置为读取其他 socket 路径:

nginx 复制代码
# 如果 rsyslog 需要直接从 /dev/log 读取(不通过 journald 转发)
module(load="imuxsock" SysSock.Use="off")
# 然后配置其他 socket

5.4 难点四:消息格式转换

阶段 消息格式
syslog() 发送 <PRI>timestamp hostname prog[pid]: msg
journald 接收 解析 PRI → facility + level,存储为结构化字段
journald 转发 重新格式化为 syslog 协议格式
rsyslog 接收 解析 facility/level,匹配规则
rsyslog 写入 根据模板格式化(默认:%TIMESTAMP% %HOSTNAME% %syslogtag%%msg%

5.5 难点五:速率限制与消息丢失

ini 复制代码
# journald.conf
RateLimitIntervalSec=30s
RateLimitBurst=10000
  • 在 30 秒窗口内,如果某个 service 发送超过 10000 条消息,后续消息会被丢弃
  • 被丢弃的消息会有一条替代消息:"MESSAGE_ID=... Suppressed N messages from /user.slice/..."
  • 这保护系统不被日志洪泛打垮

6. 完整架构图

#mermaid-svg-sKA5rwDR4qWY5OLG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sKA5rwDR4qWY5OLG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sKA5rwDR4qWY5OLG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sKA5rwDR4qWY5OLG .error-icon{fill:#552222;}#mermaid-svg-sKA5rwDR4qWY5OLG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sKA5rwDR4qWY5OLG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sKA5rwDR4qWY5OLG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sKA5rwDR4qWY5OLG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sKA5rwDR4qWY5OLG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sKA5rwDR4qWY5OLG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sKA5rwDR4qWY5OLG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sKA5rwDR4qWY5OLG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sKA5rwDR4qWY5OLG .marker.cross{stroke:#333333;}#mermaid-svg-sKA5rwDR4qWY5OLG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sKA5rwDR4qWY5OLG p{margin:0;}#mermaid-svg-sKA5rwDR4qWY5OLG .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sKA5rwDR4qWY5OLG .cluster-label text{fill:#333;}#mermaid-svg-sKA5rwDR4qWY5OLG .cluster-label span{color:#333;}#mermaid-svg-sKA5rwDR4qWY5OLG .cluster-label span p{background-color:transparent;}#mermaid-svg-sKA5rwDR4qWY5OLG .label text,#mermaid-svg-sKA5rwDR4qWY5OLG span{fill:#333;color:#333;}#mermaid-svg-sKA5rwDR4qWY5OLG .node rect,#mermaid-svg-sKA5rwDR4qWY5OLG .node circle,#mermaid-svg-sKA5rwDR4qWY5OLG .node ellipse,#mermaid-svg-sKA5rwDR4qWY5OLG .node polygon,#mermaid-svg-sKA5rwDR4qWY5OLG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sKA5rwDR4qWY5OLG .rough-node .label text,#mermaid-svg-sKA5rwDR4qWY5OLG .node .label text,#mermaid-svg-sKA5rwDR4qWY5OLG .image-shape .label,#mermaid-svg-sKA5rwDR4qWY5OLG .icon-shape .label{text-anchor:middle;}#mermaid-svg-sKA5rwDR4qWY5OLG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sKA5rwDR4qWY5OLG .rough-node .label,#mermaid-svg-sKA5rwDR4qWY5OLG .node .label,#mermaid-svg-sKA5rwDR4qWY5OLG .image-shape .label,#mermaid-svg-sKA5rwDR4qWY5OLG .icon-shape .label{text-align:center;}#mermaid-svg-sKA5rwDR4qWY5OLG .node.clickable{cursor:pointer;}#mermaid-svg-sKA5rwDR4qWY5OLG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-sKA5rwDR4qWY5OLG .arrowheadPath{fill:#333333;}#mermaid-svg-sKA5rwDR4qWY5OLG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sKA5rwDR4qWY5OLG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sKA5rwDR4qWY5OLG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sKA5rwDR4qWY5OLG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-sKA5rwDR4qWY5OLG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sKA5rwDR4qWY5OLG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-sKA5rwDR4qWY5OLG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sKA5rwDR4qWY5OLG .cluster text{fill:#333;}#mermaid-svg-sKA5rwDR4qWY5OLG .cluster span{color:#333;}#mermaid-svg-sKA5rwDR4qWY5OLG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sKA5rwDR4qWY5OLG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-sKA5rwDR4qWY5OLG rect.text{fill:none;stroke-width:0;}#mermaid-svg-sKA5rwDR4qWY5OLG .icon-shape,#mermaid-svg-sKA5rwDR4qWY5OLG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sKA5rwDR4qWY5OLG .icon-shape p,#mermaid-svg-sKA5rwDR4qWY5OLG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-sKA5rwDR4qWY5OLG .icon-shape .label rect,#mermaid-svg-sKA5rwDR4qWY5OLG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sKA5rwDR4qWY5OLG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sKA5rwDR4qWY5OLG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sKA5rwDR4qWY5OLG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Application
syslog()
stdout/stderr
sd_journal_print()
/dev/log
systemd-journald
Journal Files
/run/systemd/journal/syslog
rsyslogd
/var/log/syslog
/var/log/auth.log
/var/log/kern.log


7. 关键命令速查

bash 复制代码
# 查看 journald 状态
systemctl status systemd-journald

# 查看 journald 配置
systemd-analyze cat-config systemd/journald.conf

# 查看 rsyslog 状态
systemctl status rsyslog

# 查看 rsyslog 配置
cat /etc/rsyslog.conf
cat /etc/rsyslog.d/50-default.conf

# 实时查看 journal
journalctl -f

# 查看特定 PID 的日志
journalctl _PID=<PID>

# 查看特定程序的日志
journalctl SYSLOG_IDENTIFIER=mydemo

# 查看完整元数据
journalctl -o verbose _PID=<PID>

# 查看 socket 信息
ss -xlp | grep -E 'log|syslog'

# 查看文件链接
ls -la /dev/log
readlink -f /dev/log

# 测试 syslog 发送
logger "Hello from logger command"
echo "test" | systemd-cat -t mytag

# 查看 journal 文件位置
ls -la /var/log/journal/

8. 总结

层级 组件 职责 关键机制
应用 syslog(3) 格式化并发送日志 sendto() DGRAM 到 /dev/log
传输 /dev/log Unix socket 传输 symlink → journald dev-log socket
采集 systemd-journald 接收、解析、存储、转发 SCM_CREDENTIALS, 结构化存储
转发 ForwardToSyslog=yes 转发到传统 syslog 写入 /run/systemd/journal/syslog
输出 rsyslogd 规则匹配、文件写入 imuxsock, selector/action 规则
持久化 /var/log/syslog 传统文本日志 rsyslog 模板格式化输出

核心设计思想 :journald 作为中央日志采集器 ,负责结构化存储和元数据注入;rsyslog 作为传统输出引擎,负责按规则写入文本文件。两者通过 Unix socket 桥接,各司其职。

相关推荐
凡人叶枫1 小时前
Effective C++ 条款08:别让异常逃离析构函数
java·linux·数据库·c++·嵌入式开发
新时代牛马1 小时前
内核调试方法
linux·学习
墨痕诉清风2 小时前
Linux系统设置上海时间(24小时制)
linux·运维·服务器
utf8mb4安全女神2 小时前
脚本模块化
linux·运维·服务器
daad7772 小时前
纪录无人机PID参数配置
linux
noipp2 小时前
推荐题目:洛谷 P1737 [NOI2016] 旷野大计算
linux·数据结构·算法
枕星而眠2 小时前
Linux守护进程完全指南:从原理到实战
linux·运维·服务器·c++·后端
网络系统管理2 小时前
第八届江苏技能状元大赛选拔赛信息通信网络运行管理项目模块D网络服务与系统运维-Linux样题解析
linux·运维·网络
不会C语言的男孩2 小时前
Linux 系统编程 · 第 2 章:系统调用与库函数
linux·c语言