本文译者是一位开源理念的坚定支持者,所以本文虽然不是软件,但是遵照开源的精神发布。
本文译者十分愿意与他人分享劳动成果,如果你对我的其他翻译作品或者技术文章有兴趣,可以在如下位置查看现有的作品集:
由于译者水平有限,因此不能保证译文内容准确无误。如果你发现了译文中的错误(哪怕是错别字也好),请来信指出,任何提高译文质量的建议我都将虚心接纳。
systemd-journald.service, systemd-journald.socket, systemd-journald-dev-log.socket, systemd-journald-audit.socket, systemd-journald — 日志服务
systemd-journald.service
systemd-journald.socket
systemd-journald-dev-log.socket
systemd-journald-audit.socket
/usr/lib/systemd/systemd-journald
systemd-journald
是一个收集并存储各类日志数据的系统服务。
它创建并维护一个带有索引的、结构化的日志数据库,
并可以收集来自各种不同渠道的日志:
通过 kmsg 收集内核日志
通过 libc
的
syslog(3)
接口收集系统日志
通过 本地日志接口 sd_journal_print(3) 收集结构化的系统日志
捕获服务单元的标准输出(STDOUT)与标准错误(STDERR)。 详见下文。
通过内核审计子系统收集审计记录
日志守护进程会以安全且不可伪造的方式自动收集每条日志的元数据。 参见 systemd.journal-fields(7) 以了解究竟收集了哪些元数据。
收集到的大部分日志数据都是文本数据,但同样也可以收集二进制数据。 组成日志记录的各个字段大小上限为16ZB(16*1024*1024TB)。
日志服务要么将日志持久存储在 /var/log/journal
目录中、
要么将日志临时存储在 /run/log/journal/
目录中(关机即丢失)。默认情况下,
如果在启动期间存在 /var/log/journal/
目录,那么日志将会被持久存储在此目录中,
否则将会临时存储在 /run/log/journal/
目录中。可以使用 Storage=
选项(参见
journald.conf(5) 手册)
设置日志的存储位置(无论 /var/log/journal/
目录是否存在)。
如果 /var/log/journal/
目录不存在,
同时又将日志配置为持久存储(这是 journald.conf
的默认配置),那么将会尽可能自动创建该目录,
并为其设置正确的权限与拥有者:
mkdir -p /var/log/journal systemd-tmpfiles --create --prefix /var/log/journal
详见 journald.conf(5) 以了解如何配置此日志服务。
所有服务进程的标准输出(STDOUT)与标准错误(STDERR)默认都会被连接到日志服务。
但这个默认行为可以通过
StandardOutput=
/StandardError=
进行修改(详见
systemd.exec(5) 手册)。
日志服务会将通过此方式接收到的日志字节流,按照换行符("\n
", ASCII 10
)
与 NUL
字节("\0
", ASCII 0
)进行切分,最终转化为一条条日志记录。
如果 systemd-journald.service
被停止,那么连接到服务进程的所有日志流都将被终止,
继续写入日志流将会导致 EPIPE
错误。为了从容应对这种情况,
强烈建议将日志输出到标准输出(STDOUT)或标准错误(STDERR)的服务进程忽略 EPIPE
错误。
如果没有阻止或关闭 SIGPIPE
信号处理器,
这种写入还会导致产生 SIGPIPE
进程信号(详见
signal(7) 手册)。
为了避免上述问题,systemd 默认关闭所有被调用进程的 SIGPIPE
信号(但是可以通过
IgnoreSIGPIPE=
选项专门为某些个别单元打开,详见
systemd.exec(5) 手册)。
要想恢复被终止的标准输出(STDOUT)与标准错误(STDERR)日志流,只能再次启动日志服务。
在常规情况下,
systemd-journald.service
会将日志流的文件描述符副本存储在 systemd 服务管理器中。
如果 systemd-journald.service
被 systemctl
restart 命令或等价操作重启(而不是一对分隔的 systemctl stop 与
systemctl start 命令或等价操作),那么日志流连接不会在重启过程中发生中断。
因此,重启 systemd-journald.service
是安全的(但是千万不要停止它)。
从上述标准输出(STDOUT)/标准错误(STDERR)日志流中提取的日志记录的元数据由最初创建日志流的端点决定。 如果将日志流连接传递给另外一个进程(例如从主服务进程派生出来的子进程), 那么日志记录的元数据将不会反映出后继的日志实际上是来自于另一个进程(仍然认为是来自于最初的进程)。 这不同于前文列举的其他日志收集渠道。 对于其他日志收集渠道而言,元数据天生就是基于一条条独立的日志记录生成的, 所以天然的不存在这个问题。
除了服务单元的标准输出(STDOUT)/标准错误(STDERR)隐含的使用了日志流来记录,还可以通过 systemd-cat(1) 命令行工具来使用日志流。
目前, systemd-journald
最多同时接受 4096 个日志流。
到达此限制之后,后继的日志流虽然可以成功建立连接,但是会在一开始写入就得到
EPIPE
错误。
要求将
/run/
中的日志数据刷写到
/var/
中(若存在且可写入),
并等待其完成,以确保被永久保存。这通常是挂载
/var/
之后的必要动作,
否则 /run
中的日志数据永远也不会被刷写到
/var
中(无论配置文件怎样设置)。
journalctl --flush
命令就是使用这个信号的典型例子。
详见
journalctl(1)
手册。
要求立即滚动日志,并等待其完成。 journalctl --rotate 命令就是 使用这个信号的典型例子。
要求将所有缓存中的日志刷写到磁盘上,并等待其完成。 journalctl --sync 命令就是 使用这个信号的典型例子。
一些
journald.conf
中的配置参数可以被内核引导选项覆盖,
具体说来就是:
systemd.journald.forward_to_syslog=
, systemd.journald.forward_to_kmsg=
, systemd.journald.forward_to_console=
, systemd.journald.forward_to_wall=
¶允许/禁止将收集到的日志: 转发到传统的 syslog 守护进程, 转发到内核日志缓冲区, 转发到系统控制台, 作为wall警告信息转发给所有已登录的用户
详见 journald.conf(5) 手册。
日志文件默认属于root用户及
"systemd-journal
" 组,权限为"640",
也就是仅对root用户可读写、仅对 "systemd-journal
" 组可读。
若想允许某个用户读取日志,可将其加入到 "systemd-journal
" 组中。
默认情况下,每个已登录用户都在
/var/log/journal/
中拥有自己专属的日志文件,
但是这些专属日志文件的属主依然是root用户。
这样做的目的在于:在禁止用户修改日志的同时,
又可以通过文件系统的访问控制列表(ACL)赋予用户对日志的只读权限。
还可以通过文件系统的访问控制列表(ACL)
将日志的访问权限赋予特定的用户、组。
例如,下面的命令就赋予了
"wheel
" 与 "adm
"
组的所有用户读取日志的权限:
# setfacl -Rnm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal/
注意,此命令不但更新了
/var/log/journal/
目录中已有日志文件的访问控制列表(ACL),
而且对未来创建的日志文件也有效。
/etc/systemd/journald.conf
¶配置 systemd-journald 的行为,详见 journald.conf(5) 手册。
/run/log/journal/machine-id
/*.journal
, /run/log/journal/machine-id
/*.journal~
, /var/log/journal/machine-id
/*.journal
, /var/log/journal/machine-id
/*.journal~
¶systemd-journald 将日志文件存放在
/run/log/journal/
或
machine-id
//var/log/journal/
目录中,并用 "machine-id
/.journal
" 作为日志文件的后缀名。
如果守护进程未能干净的退出或者日志文件未能通过正确性检查,
那么当前日志文件的后缀名将会被重命名为 ".journal~
" ,
同时 systemd-journald 将会从一个全新的日志文件开始记录。
仅在下列两种情况下,才会使用 /run
目录记录日志文件:
(1)当 /var/log/journal
目录不可用时;
(2)明确设置了 Storage=volatile
时(位于
journald.conf(5)
配置文件中)。
当 systemd-journald
结束一个日志文件的写入时,
该日志文件将被重命名为 "
"
或 "original-name
@suffix.journal
" ,
以完成日志文件的"归档"。original-name
@suffix.journal~
一般来说,可以安全的读取与拷贝任意日志文件(无论是否已经归档)。 journalctl(1) 工具与 sd-journal(3) 库应该能够读取所有已经写入到文件系统的日志项。
systemd-journald
会自动删除最早的日志归档以限制磁盘空间的用量。
详见 SystemMaxUse=
选项以及其他
journald.conf(5) 中的相关选项。
/dev/kmsg
, /dev/log
, /run/systemd/journal/dev-log
, /run/systemd/journal/socket
, /run/systemd/journal/stdout
¶systemd-journald 除了监听上述文件, 还通过 netlink 监听 审计系统事件。
systemd(1), journalctl(1), journald.conf(5), systemd.journal-fields(7), sd-journal(3), systemd-coredump(8), setfacl(1), sd_journal_print(3), pydoc systemd.journal