关于Journal Log
简介
Journal是systemd 为自己提供的日志系统。使用systemd日志,无须额外提供日志服务(syslog)。读取日志的命令:
# journalctl
默认情况下(当 Storage=
在文件 /etc/systemd/journald.conf
中被设置为 auto
),日志记录将被写入 /var/log/journal/
。该目录是 systemd 软件包的一部分。若被删除,systemd 不会自动创建它,直到下次升级软件包时重建该目录。如果该目录缺失,systemd 会将日志记录写入 /run/systemd/journal
。这意味着,系统重启后日志将丢失。
提示: 如果
/var/log/journal/
位于 btrfs 文件系统,应该考虑对这个目录禁用写入时复制,方法参阅Btrfs#Copy-on-Write (CoW)。
Systemd 日志事件提示信息的记录按照优先级和功能进行分离,符合经典的 BSD syslog 协议风格([Syslog],RFC 5424)。
输出过滤
journalctl 可以根据特定字段过滤输出。
日志大小限制
如果按上面的操作保留日志的话,默认日志最大限制为所在文件系统容量的 10%,即:如果 /var/log/journal 储存在 50GiB 的根分区中,那么日志最多存储 5GiB 数据。可以修改配置文件指定最大限制。如限制日志最大 50MiB:
/etc/systemd/journald.conf
SystemMaxUse=50M
还可以通过配置片段而不是全局配置文件进行设置:
/etc/systemd/journald.conf.d/00-journal-size.conf
[Journal]
SystemMaxUse=50M
修改配置后要立即生效,需重启 systemd-journald.service
服务。
详情参见 journald.conf(5).
Journal log 日志流
日志输入
-
通过kmsg,获取内核日志
systemd-journald
会监听 socketdev/kmsg
来获取 kernel log messages.
journald-kmsg.c
int server_open_dev_kmsg(Server *s) { ... s->dev_kmsg_fd = open("/dev/kmsg", mode); ... }
-
通过syslog(3) 调用,获取简单系统日志。
src/core/namespace.c
static int mount_private_dev(MountEntry *m) { ... devlog = strjoina(temporary_mount, "/dev/log"); if (symlink("/run/systemd/journal/dev-log", devlog) < 0) ... }
journald-server.c
int server_init(Server *s, const char *namespace) { ... /* systemd-journald-dev-log.socket: /run/systemd/journal/dev-log */ r = server_open_syslog_socket(s, syslog_socket); ... }
Journal log 兼容syslog, 即通过syslog(3) 打印的log 也会存储到 Journal log 中.
systemd-journald
通过监听 socket/run/systemd/journal/dev-log
获取到 syslog(3). 因为通常在装有systemd的系统中/dev/log
是/run/systemd/journal/dev-log
的一个软连接,而syslog(3)会将log 发送到/dev/log
-
通过原生Journal API sd_journal_print(4),获取结构化系统日志
journal-send.c
_public_ int sd_journal_send(const char *format, ...) { ... r = sd_journal_sendv(iov, i); ... } _public_ int sd_journal_sendv(const struct iovec *iov, int n) { ... static const union sockaddr_union sa = { .un.sun_family = AF_UNIX, .un.sun_path = "/run/systemd/journal/socket", }; ... } _public_ int sd_journal_printv(int priority, const char *format, va_list ap) { ... return sd_journal_sendv(iov, 2); ... }
-
通过标准输出以及错误输出,获取systemd service 日志。
journal-send.c
_public_ int sd_journal_send(const char *format, ...) { ... r = sd_journal_sendv(iov, i); ... } _public_ int sd_journal_sendv(const struct iovec *iov, int n) { ... static const union sockaddr_union sa = { .un.sun_family = AF_UNIX, .un.sun_path = "/run/systemd/journal/socket", }; ... } _public_ int sd_journal_printv(int priority, const char *format, va_list ap) { ... return sd_journal_sendv(iov, 2); ... }
systemd service 可以通过设置
StandardOutput=journal
/StandardError=journal
将标准输出和错误输出存储到Journal log 中.
systemd-journald
通过监听 socket/run/systemd/journal/stdout
获取service的log(以systemd 启动的service, fd stdout/stderr (1/2) 会被重定向到/run/systemd/journal/stdout
)。 -
通过内核audit 子系统,获取Audit log
journald-audit.c
int server_open_audit(Server *s) { ... s->audit_fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT); ... }
日志输出
systemd 提供了 socket /run/systemd/journal/syslog
,以兼容传统日志服务。所有系统信息都会被传入。要使传统日志服务工作,需要让服务链接该 socket,而非 /dev/log
(官方说明)。
journald.conf
使用 no
转发socket . 为了使 syslog-ng 配合 journald , 你需要在 /etc/systemd/journald.conf
中设置 ForwardToSyslog=yes
. 参阅 Syslog-ng#Overview 了解更多细节.
journald-syslog.c
static void forward_syslog_iovec(
...
j = strjoina(s->runtime_directory, "/syslog");
...
}
如果选择使用 rsyslog , 因为 rsyslog 从日志中 直接 读取Log (sd_journal_open
/sd_journal_get_data
),所以不再需要改变那个选项.
rsyslog/plugins/imjournal/imjournal.c
static rsRetVal openJournal(void) {
...
if ((r = sd_journal_open(&journalContext.j, cs.bRemote? 0 : SD_JOURNAL_LOCAL_ONLY)) < 0) {
LogError(-r, RS_RET_IO_ERROR, "imjournal: sd_journal_open() failed");
iRet = RS_RET_IO_ERROR;
}
...
}
static int journalGetData(const char *field, const void **data, size_t *length)
{
...
ret = sd_journal_get_data(journalContext.j, field, data, length);
...
}
相关 socket
socket | 说明 |
---|---|
/run/systemd/journal/dev-log | 用以监听syslog(3)的输出 |
/run/systemd/journal/stdout | 用以监听systemd service 的标准/错误输出 |
/run/systemd/journal/socket | 用以监听jurnal原始打印API日志输入 |
/run/systemd/journal/syslog | 如果存在,systemd-journal 将收到的log 转发到该socket。但由于rsyslog更喜欢从日志中提取信息,而不是通过套接字接收消息,所以该socket一般不启用。 |
流程图
systemd-journal 日志流参考文章
systemd/Journal (简体中文)
systemd-journald.socket (8) - Linux Man Pages