问题确定既是一门科学,又是一门艺术,有时,甚至感觉一点魔法也很有用。每个人都遇到过报告的故障无法重现的情况,这总是让用户和系统管理员都感到沮丧。即使是家用电器和汽车,在维修人员出现时也可能很固执,拒绝发生故障。
抛开拟人化的说法不谈,系统管理员有一些工具可以显示他们的 Linux 计算机中发生的事情,粒度各不相同。有一些工具,如 top、htop、glances、sar、iotop、tcpdump、traceroute、mtr、iptraf-ng、df、du 等等,所有这些工具都可以显示主机的当前状态,其中一些工具可以生成各种详细程度的日志。
虽然这些工具可以用来查找正在发生的问题,但对于瞬态问题或那些没有直接可观察症状的问题,它们并没有特别的帮助——至少在发生一些重大甚至灾难性问题之前是不可观察的。
我用于问题确定的一个重要工具是系统日志——以及使用 systemd 的系统日志。systemd 日志始终是我解决问题时首先求助的工具之一,特别是那些在我观看时似乎不会发生的问题。在我的系统管理员职业生涯的早期,我花了很长时间才意识到日志文件中蕴含着丰富的信息,而这一发现大大提高了我在解决问题方面的速度。
您已经在本系列之前的许多文章中看到了 journalctl
命令的一些用法。在本文中,我将探讨有关 systemd 日志的一些细节、它的工作原理以及使用 journalctl
查找和识别问题的方法。
关于日志
任何日志或日志的目的是维护主机上运行的服务和程序的正常活动的时间顺序历史记录,并记录发生的任何错误或警告消息。日志消息过去保存在 /var/log
中的单独文件中,通常内核一个文件,主机上运行的大多数服务分别一个文件。不幸的是,大量的日志文件可能会分散必要的信息,并延迟发现问题的根本原因。当您试图确定系统在发生错误时发生了什么时,这尤其耗时。
旧的 /var/log/dmesg
文件通常用于内核,但该文件几年前已停止使用,转而使用 dmesg
命令来显示相同的信息,并将这些消息(以及更多)集成到 /var/log/messages
文件中。将其他日志合并到 messages
文件中有助于加快问题确定速度,因为它将大部分数据保存在一个文件中,但仍有许多服务的日志未集成到更中心的 messages
文件中。
systemd 日志旨在将所有消息收集到一个统一的结构中,该结构可以显示系统在特定时间或事件发生时及周围发生的所有事情的完整图片。由于事件(无论来源如何)都位于一个位置并按时间顺序排列,因此可以一目了然地看到在特定时间点或时间范围内发生的所有事情。在我看来,这是 systemd 日志的主要好处之一。
关于 systemd 日志
systemd 日志服务由 systemd-journald
守护程序实现。根据 systemd-journald
手册页
systemd-journald
是一种系统服务,用于收集和存储日志数据。它基于从各种来源接收的日志信息创建和维护结构化、索引化的日志
- 内核日志消息,通过
kmsg
- 简单的系统日志消息,通过
libc syslog(3)
调用- 结构化的系统日志消息,通过原生 Journal API,请参阅
sd_journal_print(3)
- 服务单元的标准输出和标准错误。有关更多详细信息,请参见下文。
- 审计记录,源自内核审计子系统
守护程序将隐式地为每个日志消息收集许多元数据字段,以安全且不可伪造的方式进行。有关收集的元数据的更多信息,请参阅
systemd.journal-fields(7)
。日志日志收集的数据主要基于文本,但在必要时也可以包含二进制数据。构成日志中存储的日志记录的单个字段的大小最大可达 2^64-1 字节。
配置更改
可以使用 /etc/systemd/journald.conf
文件配置 systemd 日志守护程序。对于许多主机,此文件不需要任何更改,因为默认值非常合理。如果您还没有查看过,请立即查看您的 journald.conf
文件。
您可能考虑的最常见的配置更改将指定最大日志文件大小、旧日志文件的数量以及最大文件保留时间。进行这些更改的主要原因是减少日志使用的存储空间(如果您的存储设备较小)。在任务关键型环境中,您可能还希望减少将存储在 RAM 内存中的日志数据同步到存储设备之间的时间。
journald.conf
手册页 包含更多详细信息。
关于数据格式的争议
围绕 systemd 的争议之一是以二进制格式存储日志内容。反对 systemd 的一些论点是基于 systemd 日志以二进制格式存储。这似乎与 Unix/Linux 哲学(使用 ASCII 文本作为数据)相悖,这是人们用来证明他们不喜欢 systemd 的一个论点。例如,管道的发明者 Doug McIlroy 说
“这就是 Unix 哲学:编写程序,使其做好一件事。编写程序以协同工作。编写程序以处理文本流,因为这是一个通用接口。” —Doug McIlroy,引自 Eric S. Raymond 的著作 The Art of Unix Programming
然而,这些论点似乎至少部分基于误解,因为手册页清楚地指出数据“主要基于文本”,尽管它允许使用二进制数据形式。Linux 内核创建者 Linus Torvalds 总是明确表达自己的感受,他说
“实际上,我对 systemd 本身没有任何特别强烈的意见。我对一些核心开发人员有问题,我认为他们在错误和兼容性方面过于轻率,并且我认为一些设计细节很疯狂(例如,我不喜欢二进制日志),但这些都是细节,而不是大问题。” —Linus Torvalds,引自 ZDNet 的“Linus Torvalds 和其他人谈 Linux 的 systemd”,2014 年
systemd 日志文件存储在 /var/log/journal
的一个或多个子目录中。登录到您具有 root 访问权限的测试系统,并将 /var/log/journal
设置为当前工作目录 (PWD)。列出其中的子目录,选择一个,并将其设置为 PWD。您可以使用多种方式查看这些文件。我从 stat
命令开始(请注意,您主机上的日志文件名将与我的不同)
[root@testvm1 3bccd1140fca488187f8a1439c832f07]# stat system@7ed846aadf1743139083681ec4042037-0000000000000001-0005a99c0280fd5f.journal
File: system@7ed846aadf1743139083681ec4042037-0000000000000001-0005a99c0280fd5f.journal
Size: 8388608 Blocks: 16392 IO Block: 4096 regular file
Device: fd04h/64772d Inode: 524384 Links: 1
Access: (0640/-rw-r-----) Uid: ( 0/ root) Gid: ( 190/systemd-journal)
Access: 2020-07-13 08:30:05.764291231 -0400
Modify: 2020-07-04 07:33:52.916001110 -0400
Change: 2020-07-04 07:33:52.916001110 -0400
Birth: -
[root@testvm1 3bccd1140fca488187f8a1439c832f07]#
日志文件被标识为“常规”文件,这并没有特别的帮助。file
命令将其标识为“日志”文件,但您已经知道了。使用 dd
命令查看文件内部。以下命令将输出数据流发送到 STDOUT;您可能希望通过 less
分页器管道传输它
[root@testvm1 3bccd1140fca488187f8a1439c832f07]# dd if=system@7ed846aadf1743139083681ec4042037-0000000000000001-0005a99c0280fd5f.journal | less
<SNIP>
9�P1�8��9_SOURCE_MONOTONIC_TIMESTAMP=191726���/��P����9MESSAGE=Inode-cache hash table entries: 1048576 (order: 11, 8388608 bytes, linear)�hx
9�P1�p�9��/��P�b������9��9_SOURCE_MONOTONIC_TIMESTAMP=191825�pdXY�7p�9��9MESSAGE=mem auto-init: stack:off, heap alloc:off, heap free:off�i��
��(n�O���@Y� �����Zս���82���7X�8�������8��DZR�����8<~B�4�<� �8tM˞8$����8��Ж��h9�&������9�����`@�9�pdXY�7b�ͺ��WV��9��9_SOURCE_MONOTONIC_TIM
ESTAMP=234745����4�h@�9��9MESSAGE=Memory: 12598028K/12963384K available (14339K kernel code, 2406K rwdata, 8164K rodata, 2468K init, 5072K b
ss, 365356K reserved, 0K cma-reserved)�j����(n�O���@Y� ����]��m�82���7X�8�������8��DZR�����8<~B�4�<� �8tM˞8$����8��Ж��h9�&�����9�ͺ��WV��9���
4�hbB���a��^��9��9_SOURCE_MONOTONIC_TIMESTAMP=234758��3�����9��9MESSAGE=random: get_random_u64 called from __kmem_cache_create+0x3e/0x610 wi
th crng_init=0�k���(n�O���@Y� ����j������82���7X��8C�X�Y"��8�������8��DZR�����8<~B�4�<� �8tM˞8$����8��Ж�à�9B���a���9�3���b�8�ȭ�����9h�9_SO�9h�9MESSAGE=SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1�l����(n�O���@Y� ������z��X�82���7X�8�������8��DZR�����8<~B�4�<� �8tM˞
b�(+I)�x�9�9_SOURCE_MONOTONIC_TIMESTAMP=235444r�%/p��9�9MESSAGE=Kernel/User page tables isolation: enabled�m����(n�O���@Y� ����k��B0��8
2���7X�8�������8��DZR�����8<~B�4�<� �8tM˞8$����8��Ж��h9�&����8�9�(+I)Ҡ�9�%/pb8O{ W���8�9��9_SOURCE_MONOTONIC_TIMESTAMP=235464u�N`�FP M��9
��9MESSAGE=ftrace: allocating 41361 entries in 162 pages�n����(n�O���@Y�
<SNIP>
即使是来自 dd
命令的数据流的这一小部分也显示了 ASCII 文本和二进制数据的有趣混合。另一个有用的工具是 strings
命令,它只是显示文件中包含的所有 ASCII 文本字符串,并忽略二进制数据
[root@testvm1 3bccd1140fca488187f8a1439c832f07]# strings system@7ed846aadf1743139083681ec4042037-0000000000000001-0005a99c0280fd5f.journal
<SNIP>
MESSAGE=Linux version 5.7.6-201.fc32.x86_64 (mockbuild@bkernel01.iad2.fedoraproject.org) (gcc version 10.1.1 20200507 (Red Hat 10.1.1-1) (GC
C), GNU ld version 2.34-3.fc32) #1 SMP Mon Jun 29 15:15:52 UTC 2020
MESSAGE
_BOOT_ID=6e944f99ebd9405984090f829a927fa4
_BOOT_ID
_MACHINE_ID=3bccd1140fca488187f8a1439c832f07
_MACHINE_ID
_HOSTNAME=testvm1.both.org
_HOSTNAME
PRIORITY=6
MESSAGE=Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.7.6-201.fc32.x86_64 root=/dev/mapper/VG01-root ro resume=/dev/mapper/VG01-swap rd.lv
m.lv=VG01/root rd.lvm.lv=VG01/swap rd.lvm.lv=VG01/usr selinux=0
MESSAGE=x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
MESSAGE=x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
MESSAGE=x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
Z_g3;
MESSAGE=x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: 256
Z_g3;
MESSAGE=x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format.
MESSAGE=BIOS-provided physical RAM map:
`k2X
MESSAGE=BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
MESSAGE=BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
MESSAGE=BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
PyLM
MESSAGE=BIOS-e820: [mem 0x0000000000100000-0x00000000dffeffff] usable
MESSAGE=BIOS-e820: [mem 0x00000000dfff0000-0x00000000dfffffff] ACPI data
MESSAGE=BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved
MESSAGE=BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
MESSAGE=BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
MESSAGE=BIOS-e820: [mem 0x0000000100000000-0x00000003373fffff] usable
<SNIP>
此数据可以由人解释,并且此特定段看起来与来自 dmesg
命令的输出数据流非常相似。我将留给您自行进一步探索,但我的结论是,日志文件显然是二进制和 ASCII 文本的混合物。这种混合使得使用传统的基于文本的 Linux 工具来提取可用数据变得繁琐。但是有一种更好的方法可以为提取和查看日志数据提供许多可能性。
关于 journalctl
journalctl
命令旨在通过使用强大而灵活的标准来识别所需数据,从而从 systemd 日志中提取可用信息。本系列之前的文章已经描述了 journalctl
,还有更多内容需要了解。
我将首先回顾一下基础知识,以防您没有阅读之前的文章,或者只是需要复习一下。
您可以不带任何选项或参数使用 journalctl
命令来查看包含所有日志和日志信息的 systemd 日志
[root@testvm1 ~]# journalctl
-- Logs begin at Mon 2020-06-08 07:47:20 EDT, end at Thu 2020-07-16 10:30:43 EDT. --
Jun 08 07:47:20 testvm1.both.org kernel: Linux version 5.6.6-300.fc32.x86_64 (mockbuild@bkernel03.phx2.fedoraproject.org) (gcc version 10.0>
Jun 08 07:47:20 testvm1.both.org kernel: Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.6.6-300.fc32.x86_64 root=/dev/mapper/VG01-root ro >
Jun 08 07:47:20 testvm1.both.org kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
Jun 08 07:47:20 testvm1.both.org kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
Jun 08 07:47:20 testvm1.both.org kernel: x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
Jun 08 07:47:20 testvm1.both.org kernel: x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: 256
Jun 08 07:47:20 testvm1.both.org kernel: x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format.
Jun 08 07:47:20 testvm1.both.org kernel: BIOS-provided physical RAM map:
Jun 08 07:47:20 testvm1.both.org kernel: BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
<SNIP>
Jul 16 09:51:00 testvm1.both.org NetworkManager[760]: <info> [1594907460.1765] dhcp4 (enp0s3): option requested_routers => '1'
Jul 16 09:51:00 testvm1.both.org NetworkManager[760]: <info> [1594907460.1765] dhcp4 (enp0s3): option requested_static_routes => '1'
Jul 16 09:51:00 testvm1.both.org NetworkManager[760]: <info> [1594907460.1765] dhcp4 (enp0s3): option requested_subnet_mask => '1'
Jul 16 09:51:00 testvm1.both.org NetworkManager[760]: <info> [1594907460.1765] dhcp4 (enp0s3): option requested_time_offset => '1'
Jul 16 09:51:00 testvm1.both.org NetworkManager[760]: <info> [1594907460.1766] dhcp4 (enp0s3): option requested_wpad => '1'
Jul 16 09:51:00 testvm1.both.org NetworkManager[760]: <info> [1594907460.1766] dhcp4 (enp0s3): option routers => '192.168.0.2>
Jul 16 09:51:00 testvm1.both.org NetworkManager[760]: <info> [1594907460.1766] dhcp4 (enp0s3): option subnet_mask => '255.255.255>
Jul 16 09:51:00 testvm1.both.org NetworkManager[760]: <info> [1594907460.1766] dhcp4 (enp0s3): state changed extended -> extended
Jul 16 09:51:00 testvm1.both.org systemd[1]: Starting Network Manager Script Dispatcher Service...
Jul 16 09:51:00 testvm1.both.org systemd[1]: Started Network Manager Script Dispatcher Service.
Jul 16 09:51:00 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=NetworkManager-dispatcher com>
Jul 16 09:51:10 testvm1.both.org systemd[1]: NetworkManager-dispatcher.service: Succeeded.
Jul 16 09:51:10 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=NetworkManager-dispatcher comm>
Jul 16 09:59:13 testvm1.both.org systemd[1]: Starting dnf makecache...
Jul 16 09:59:13 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=dnf-makecache comm="systemd" >
Jul 16 09:59:13 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=dnf-makecache comm="systemd" e>
Jul 16 09:59:13 testvm1.both.org systemd[1]: dnf-makecache.service: Succeeded.
Jul 16 09:59:13 testvm1.both.org systemd[1]: Finished dnf makecache.
Jul 16 09:59:14 testvm1.both.org dnf[378549]: Metadata cache refreshed recently.
Jul 16 10:00:42 testvm1.both.org systemd[1]: Starting system activity accounting tool...
Jul 16 10:00:42 testvm1.both.org systemd[1]: sysstat-collect.service: Succeeded.
Jul 16 10:00:42 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=sysstat-collect comm="systemd>
Jul 16 10:00:42 testvm1.both.org systemd[1]: Finished system activity accounting tool.
Jul 16 10:00:42 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=sysstat-collect comm="systemd">
Jul 16 10:01:01 testvm1.both.org CROND[378562]: (root) CMD (run-parts /etc/cron.hourly)
Jul 16 10:01:01 testvm1.both.org run-parts[378565]: (/etc/cron.hourly) starting 0anacron
Jul 16 10:01:01 testvm1.both.org run-parts[378571]: (/etc/cron.hourly) finished 0anacron
您还可以显式显示 dmesg
命令呈现的相同数据。并排打开两个终端会话,在一个会话中发出 dmesg
命令,在另一个会话中发出以下命令
[root@testvm1 ~]# journalctl --dmesg
您应该看到的唯一区别是时间格式。dmesg
命令采用单调格式,显示自系统启动以来的秒数。journalctl
输出采用日期和时间格式。short-monotonic 选项显示自启动以来的时间
[root@testvm1 ~]# journalctl --dmesg -o short-monotonic
-- Logs begin at Mon 2020-06-08 07:47:20 EDT, end at Mon 2020-07-20 13:01:01 EDT. --
[ 0.000000] testvm1.both.org kernel: Linux version 5.7.6-201.fc32.x86_64 (mockbuild@bkernel01.iad2.fedoraproject.org) (gcc version 10.1.>
[ 0.000000] testvm1.both.org kernel: Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.7.6-201.fc32.x86_64 root=/dev/mapper/VG01-root ro r>
[ 0.000000] testvm1.both.org kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
[ 0.000000] testvm1.both.org kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
[ 0.000000] testvm1.both.org kernel: x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
[ 0.000000] testvm1.both.org kernel: x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: 256
[ 0.000000] testvm1.both.org kernel: x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format.
<snip>
[ 0.000002] testvm1.both.org kernel: clocksource: kvm-clock: mask: 0xffffffffffffffff max_cycles: 0x1cd42e4dffb, max_idle_ns: 8815905914>
[ 0.000005] testvm1.both.org kernel: tsc: Detected 2807.988 MHz processor
[ 0.001157] testvm1.both.org kernel: e820: update [mem 0x00000000-0x00000fff] usable ==> reserved
[ 0.001159] testvm1.both.org kernel: e820: remove [mem 0x000a0000-0x000fffff] usable
[ 0.001162] testvm1.both.org kernel: last_pfn = 0x24ec00 max_arch_pfn = 0x400000000
[ 0.001172] testvm1.both.org kernel: MTRR default type: uncachable
[ 0.001173] testvm1.both.org kernel: MTRR variable ranges disabled:
[ 0.001173] testvm1.both.org kernel: Disabled
[ 0.001174] testvm1.both.org kernel: x86/PAT: MTRRs disabled, skipping PAT initialization too.
[ 0.001176] testvm1.both.org kernel: CPU MTRRs all blank - virtualized system.
[ 0.001179] testvm1.both.org kernel: x86/PAT: Configuration [0-7]: WB WT UC- UC WB WT UC- UC
[ 0.001182] testvm1.both.org kernel: last_pfn = 0xdfff0 max_arch_pfn = 0x400000000
[ 0.001238] testvm1.both.org kernel: found SMP MP-table at [mem 0x0009fff0-0x0009ffff]
[ 0.081068] testvm1.both.org kernel: RAMDISK: [mem 0x34194000-0x360c1fff]
[ 0.081088] testvm1.both.org kernel: ACPI: Early table checksum verification disabled
<snip>
[ 34.037575] testvm1.both.org kernel: 16:43:32.734466 main 6.1.10_Fedora r138449 started. Verbose level = 0
[ 34.042209] testvm1.both.org kernel: 16:43:32.739032 main vbglR3GuestCtrlDetectPeekGetCancelSupport: Supported (#1)
[ 55.746944] testvm1.both.org kernel: e1000: enp0s3 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX
[ 55.747738] testvm1.both.org kernel: IPv6: ADDRCONF(NETDEV_CHANGE): enp0s3: link becomes ready
<snip>
lines 624-681/681 (END)
journalctl
命令有许多选项,包括 -o
(输出)选项,它带有几个子选项,允许您选择满足不同组要求的时间和日期格式。我在下面列出了它们中的大多数,以及从 journalctl
手册页扩展或修改的简短描述。请注意,这些格式之间的大部分主要区别在于日期和时间的格式,其他信息保持不变。
journalctl 时间和日期格式
- short: 这是默认格式,生成与经典 syslog 文件格式最相似的输出,每个日志条目显示一行。此选项显示日志元数据,包括自启动以来的单调时间、完全限定的主机名和单元名称,例如内核、DHCP 等。
Jul 20 08:43:01 testvm1.both.org kernel: Inode-cache hash table entries: 1048576 (order: 11, 8388608 bytes, linear)
- short-full: 此格式与默认格式非常相似,但显示
--since=
和--until=
选项接受的格式的时间戳。与 short 输出模式中显示的时间戳信息不同,此模式在输出中包含星期几、年份和时区信息,并且与区域设置无关。
Mon 2020-06-08 07:47:20 EDT testvm1.both.org kernel: x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
- short-iso: short-iso 格式与默认格式非常相似,但显示 ISO 8601 挂钟时间戳。
2020-06-08T07:47:20-0400 testvm1.both.org kernel: kvm-clock: Using msrs 4b564d01 and 4b564d00
- short-iso-precise:
2020-06-08T07:47:20.223738-0400 testvm1.both.org kernel: Booting paravirtualized kernel on KVM
- short-monotonic:
[ 2.091107] testvm1.both.org kernel: ata1.00: ATA-6: VBOX HARDDISK, 1.0, max UDMA/133
- short-precise: 此格式也与默认格式相似,但显示具有完整微秒精度的经典 syslog 时间戳。
Jun 08 07:47:20.223052 testvm1.both.org kernel: BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
- short-unix: 与默认格式类似,但显示自 1970 年 1 月 1 日 UTC 以来经过的秒数,而不是挂钟时间戳(“Unix 时间”)。时间以微秒精度显示。
1591616840.232165 testvm1.both.org kernel: tcp_listen_portaddr_hash hash table entries: 8192
- cat: 生成非常简洁的输出,仅显示每个日志条目的消息,不包含元数据,甚至不包含时间戳。
ohci-pci 0000:00:06.0: irq 22, io mem 0xf0804000
- verbose: 此格式显示所有条目项的完整数据结构,包含所有字段。这是与所有其他格式最不同的格式选项。
Mon 2020-06-08 07:47:20.222969 EDT [s=d52ddc9f3e8f434b9b9411be2ea50b1e;i=1;b=dcb6dcc0658e4a8d8c781c21a2c6360d;m=242d7f;t=5a7912c6148f9;x=8f> _SOURCE_MONOTONIC_TIMESTAMP=0 _TRANSPORT=kernel PRIORITY=5 SYSLOG_FACILITY=0 SYSLOG_IDENTIFIER=kernel MESSAGE=Linux version 5.6.6-300.fc32.x86_64 (mockbuild@bkernel03.phx2.fedoraproject.org) (gcc version 10.0.1 20200328 (Red Hat 10.0.1-0> _BOOT_ID=dcb6dcc0658e4a8d8c781c21a2c6360d _MACHINE_ID=3bccd1140fca488187f8a1439c832f07 _HOSTNAME=testvm1.both.org
使用 -o
选项可用的其他选择允许以各种格式(如二进制或 JSON)导出数据。我还发现 -x
选项具有启发性,因为它可以显示某些日志条目的其他解释性消息。如果您尝试此选项,请注意它可能会大大增加输出数据流。例如,类似于以下条目的附加信息
[ 4.503737] testvm1.both.org systemd[1]: Starting File System Check on /dev/mapper/VG01-root...
[ 4.691555] testvm1.both.org systemd-fsck[548]: root: clean, 1813/327680 files, 48555/1310720 blocks
[ 4.933065] testvm1.both.org systemd[1]: Finished File System Check on /dev/mapper/VG01-root.
扩展为以下内容
[ 4.503737] testvm1.both.org systemd[1]: Starting File System Check on /dev/mapper/VG01-root...
-- Subject: A start job for unit systemd-fsck-root.service has begun execution
-- Defined-By: systemd
-- Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- A start job for unit systemd-fsck-root.service has begun execution.
--
-- The job identifier is 36.
[ 4.691555] testvm1.both.org systemd-fsck[548]: root: clean, 1813/327680 files, 48555/1310720 blocks
[ 4.933065] testvm1.both.org systemd[1]: Finished File System Check on /dev/mapper/VG01-root.
-- Subject: A start job for unit systemd-fsck-root.service has finished successfully
-- Defined-By: systemd
-- Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- A start job for unit systemd-fsck-root.service has finished successfully.
--
-- The job identifier is 36
这里有一些新信息,但我认为主要好处是信息被情境化,在一定程度上澄清了原始简洁的消息。
缩小搜索范围
在大多数情况下,没有必要甚至不希望列出所有日志条目并手动搜索它们。有时我查找与特定服务相关的条目,有时我查找特定时间发生的条目。journalctl
命令提供了强大的选项,允许您仅查看您感兴趣查找的数据。
从 --list-boots
选项开始,该选项列出日志条目存在期间的所有启动。请注意,journalctl.conf
文件可能指定在日志条目达到一定年龄或日志占用的存储设备 (HDD/SSD) 空间达到指定最大量后丢弃日志条目
[root@testvm1 ~]# journalctl --list-boots
-10 dcb6dcc0658e4a8d8c781c21a2c6360d Mon 2020-06-08 07:47:20 EDT—Mon 2020-06-08 07:53:05 EDT
-9 7d61951a85f445c5946774aaae8bc2a4 Fri 2020-07-03 15:50:06 EDT—Fri 2020-07-03 18:21:23 EDT
-8 1b3a847577e544b4a2679fe576b62206 Fri 2020-07-03 18:21:58 EDT—Fri 2020-07-03 22:10:54 EDT
-7 5fef01a3568743af99118107ca6f61ae Fri 2020-07-03 22:18:41 EDT—Sat 2020-07-04 06:50:19 EDT
-6 6e944f99ebd9405984090f829a927fa4 Sat 2020-07-04 07:33:25 EDT—Sat 2020-07-04 07:58:59 EDT
-5 ec8b0c81ca4744b1bad071bdef432959 Sat 2020-07-04 08:12:06 EDT—Sat 2020-07-04 09:12:47 EDT
-4 cb173ec716824e21b87ccf6cb43a9a99 Sat 2020-07-04 10:19:53 EDT—Sat 2020-07-04 11:31:03 EDT
-3 4fe354a893194409843aa9623a36dbb0 Sat 2020-07-04 07:59:58 EDT—Sun 2020-07-05 09:39:30 EDT
-2 06fb81f1b29e4f68af9860844668446c Mon 2020-07-06 06:27:05 EDT—Mon 2020-07-13 08:50:06 EDT
-1 33dbf8e6b9de4113a591c4f487d0ac37 Mon 2020-07-13 04:50:33 EDT—Thu 2020-07-16 13:49:32 EDT
0 75c9b70913934748b5396b3b172bee50 Mon 2020-07-20 08:43:01 EDT—Fri 2020-07-24 12:44:06 EDT
最新的启动 ID 出现在底部;它是一个长的随机十六进制数。您可以使用此数据来查看特定启动的日志。可以使用最左列中的启动偏移量编号或第二列中的 UUID 指定此数据。此命令显示偏移量为 -2
的启动实例的日志——当前启动之前的第二个启动
[root@testvm1 ~]# journalctl -b -2
-- Logs begin at Mon 2020-06-08 07:47:20 EDT, end at Fri 2020-07-24 12:44:06 EDT. --
Jul 06 06:27:05 testvm1.both.org kernel: Linux version 5.7.6-201.fc32.x86_64 (mockbuild@bkernel01.iad2.fedoraproject.org) (gcc version 10.1>
Jul 06 06:27:05 testvm1.both.org kernel: Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.7.6-201.fc32.x86_64 root=/dev/mapper/VG01-root ro >
Jul 06 06:27:05 testvm1.both.org kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
Jul 06 06:27:05 testvm1.both.org kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
<SNIP>
或者您可以使用所需启动的 UUID。偏移量编号在每次启动后都会更改,但 UUID 不会更改
[root@testvm1 ~]# journalctl -b 06fb81f1b29e4f68af9860844668446c
-u
选项允许您选择要检查的特定单元。您可以使用单元名称或匹配模式,并且可以多次使用此选项来匹配多个单元或模式。在此示例中,我将其与 -b
结合使用以显示当前启动的 chronyd 日志条目
[root@testvm1 ~]# journalctl -u chronyd -b
-- Logs begin at Mon 2020-06-08 07:47:20 EDT, end at Sun 2020-07-26 09:10:47 EDT. --
Jul 20 12:43:31 testvm1.both.org systemd[1]: Starting NTP client/server...
Jul 20 12:43:31 testvm1.both.org chronyd[811]: chronyd version 3.5 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCD>
Jul 20 12:43:31 testvm1.both.org chronyd[811]: Frequency -0.021 +/- 0.560 ppm read from /var/lib/chrony/drift
Jul 20 12:43:31 testvm1.both.org chronyd[811]: Using right/UTC timezone to obtain leap second data
Jul 20 12:43:31 testvm1.both.org systemd[1]: Started NTP client/server.
Jul 20 12:44:00 testvm1.both.org chronyd[811]: Selected source 192.168.0.52
Jul 20 12:44:00 testvm1.both.org chronyd[811]: System clock TAI offset set to 37 seconds
Jul 20 12:44:00 testvm1.both.org chronyd[811]: System clock wrong by 1.412227 seconds, adjustment started
Jul 20 12:44:01 testvm1.both.org chronyd[811]: System clock was stepped by 1.412227 seconds
[root@testvm1 ~]#
假设您要查看在两个任意时间之间记录的事件。您还可以使用 -S
(--since
) 和 -U
(--until
) 来指定开始和结束时间。以下命令显示从 2020 年 7 月 24 日 15:36:00 开始到当前时间的日志条目
[root@testvm1 ~]# journalctl -S "2020-07-24 15:36:00"
此命令显示从 2020 年 7 月 24 日 15:36:00 开始到 7 月 25 日 16:00:00 结束的所有日志条目
[root@testvm1 ~]# journalctl -S "2020-07-24 15:36:00" -U "2020-07-25 16:00:00"
此命令结合了 -S
、-U
和 -u
,以提供从 2020 年 7 月 24 日 15:36:00 到 7 月 25 日 16:00:00 的 NetworkManager 服务单元的日志条目
[root@testvm1 ~]# journalctl -S "2020-07-24 15:36:00" -U "2020-07-25 16:00:00" -u NetworkManager
可以使用 --facility
选项查看某些 syslog 功能,例如 cron、auth、mail、daemon、user 等。您可以使用 --facility=help
列出可用的功能。在此示例中,mail 功能不是将用于电子邮件服务的 Sendmail 服务,而是 Linux 用于将电子邮件发送给 root 作为事件通知的本地客户端。Sendmail 实际上有两部分,服务器(对于 Fedora 和相关发行版,默认情况下未安装)和客户端,始终安装客户端,以便它可以用于将系统电子邮件传递给本地收件人,特别是 root
[root@testvm1 ~]# journalctl --facility=mail
journalctl
手册页列出了可用于缩小搜索范围的所有选项。下表总结了我最常用的一些选项。大多数这些选项可以以各种组合使用,以进一步缩小搜索范围。有关创建和测试时间戳的详细信息,以及诸如在时间戳周围使用引号等重要提示,请参阅我之前的文章 分析 systemd 日历和时间跨度。
缩小日志搜索范围的选项
选项 | 描述 |
---|---|
--list-boots |
此选项显示启动列表。该信息可用于仅显示特定启动的日志条目。 |
-b [偏移量|启动 ID] |
此选项指定要显示信息的启动。它包括从该启动到关机或重启的所有日志条目。 |
--facility=[功能名称] |
此选项指定 syslog 已知的功能名称。使用 --facility=help 列出有效的功能名称。 |
-k , --dmesg |
这些选项仅显示内核消息,等效于使用 dmesg 命令。 |
-S , --since [时间戳] |
这些选项显示自指定时间(之后)以来的所有日志条目。它们可以与 --until 结合使用以显示任意时间范围。也允许使用模糊时间,例如“yesterday”和“2 hours ago”——带引号。 |
-u [单元名称] |
-u 选项允许您选择要检查的特定单元。您可以使用单元名称或匹配模式。此选项可以多次使用以匹配多个单元或模式。 |
-U , --until [时间戳] |
这些选项显示直到(早于)指定时间的所有日志条目。它们可以与 --since 结合使用以显示任意时间范围。也允许使用模糊时间,例如“yesterday”和“2 hours ago”——带引号。 |
其他有趣的选项
journalctl
程序还提供了一些其他有趣的选项。这些选项对于优化数据搜索、指定日志数据的显示方式以及管理日志文件很有用。
其他有趣的 journalctl 选项
选项 | 描述 |
-f , --follow |
此 journalctl 选项类似于使用 tail -f 命令。它显示日志中与已指定的任何其他选项匹配的最新条目,并在新条目出现时也显示它们。这在监视事件和测试更改时非常有用。 |
-e , --pager-end |
-e 选项显示数据流的末尾而不是开头。这不会反转数据流的顺序,而是使分页器跳转到末尾。 |
--file [日志文件名] |
此选项命名 /var/log/journal/<日志子目录> 中的特定日志文件。 |
-r , --reverse |
此选项反转分页器中日志条目的顺序,使最新的条目位于顶部而不是底部。 |
-n , --lines=[X] |
此选项显示日志中最新的 X 行。 |
--utc |
此选项以 UTC 而不是本地时间显示时间。 |
-g , --grep=[REGEX] |
我喜欢 -g 选项,因为它使我能够在日志数据流中搜索特定模式。这就像通过 grep 命令管道传输文本数据流一样。此选项使用 Perl 兼容的正则表达式。 |
--disk-usage |
此选项显示当前和已存档日志使用的磁盘存储量。它可能没有您想象的那么多。 |
--flush |
存储在虚拟文件系统 /run/log/journal/ (易失性存储)中的日志数据被写入 /var/log/journal/ (持久性存储)。此选项确保所有数据在返回时都刷新到 /run/log/journal/ 。 |
--sync |
此选项将所有未写入的日志条目(仍在 RAM 中但不在 /run/log/journal 中)写入持久性文件系统。输入命令时日志系统已知的所有日志条目都将移动到持久性存储。 |
--vacuum-size= --vacuum-time= --vacuum-files= |
这些选项可以单独或组合使用,以删除最旧的存档日志文件,直到满足指定条件为止。这些选项仅考虑存档文件,而不考虑活动文件,因此结果可能与指定的完全不同。 |
我将在下面探讨其中一些条目。在 journalctl
手册页中可以找到更多选项。
日志文件
如果您尚未执行此操作,请确保列出主机上日志目录中的文件。请记住,包含日志文件的目录的名称是一个长的随机数。此目录包含多个活动和存档日志文件,包括一些用于用户的日志文件
[root@david ~]# cd /var/log/journal/ad8f29ed15044f8ba0458c846300c2a4/
[root@david ad8f29ed15044f8ba0458c846300c2a4]# ll
total 352308
-rw-r-----+ 1 root systemd-journal 33554432 May 28 13:07 system@0c91aaef57c441859ea5e421edff6528-0000000000000001-0005a6703120d448.journal
-rw-r-----+ 1 root systemd-journal 109051904 Jun 23 21:24 system@0c91aaef57c441859ea5e421edff6528-0000000000008238-0005a6b85e4e03c6.journal
-rw-r-----+ 1 root systemd-journal 100663296 Jul 21 18:39 system@0c91aaef57c441859ea5e421edff6528-0000000000021f3e-0005a8ca55efa66a.journal
-rw-r-----+ 1 root systemd-journal 41943040 Jul 30 09:34 system.journal
-rw-r-----+ 1 root systemd-journal 8388608 May 28 13:07 user-1000@037bcc7935234a5ea243b3af304fd08a-0000000000000c45-0005a6705ac48a3c.journal
-rw-r-----+ 1 root systemd-journal 16777216 Jun 23 21:24 user-1000@bc90cea5294447fba2c867dfe40530db-0000000000008266-0005a6b85e910761.journal
-rw-r-----+ 1 root systemd-journal 41943040 Jul 21 16:08 user-1000@bc90cea5294447fba2c867dfe40530db-0000000000021f4b-0005a8ca68c83ab7.journal
-rw-r-----+ 1 root systemd-journal 8388608 Jul 30 09:34 user-1000.journal
[root@david ad8f29ed15044f8ba0458c846300c2a4]#
您可以在此列表中看到用户 ID (UID) 1000(即我的 Linux 帐户)的用户文件。--files
选项允许我查看指定文件的内容,包括用户文件
[root@david ad8f29ed15044f8ba0458c846300c2a4]# journalctl --file user-1000.journal
<SNIP>
Jul 29 14:13:32 david.both.org tumblerd[145509]: Registered thumbnailer /usr/bin/gdk-pixbuf-thumbnailer -s %s %u %o
Jul 29 14:13:32 david.both.org Thunar[2788]: ThunarThumbnailer: got 0 handle (Queue)
Jul 29 14:13:32 david.both.org Thunar[2788]: ThunarThumbnailer: got 0 handle (Error or Ready)
Jul 29 14:13:32 david.both.org Thunar[2788]: ThunarThumbnailer: got 0 handle (Finished)
Jul 29 14:15:33 david.both.org tumblerd[145552]: error: Broken zip file structure
Jul 29 14:20:34 david.both.org systemd[2466]: dbus-:1.2-org.freedesktop.thumbnails.Thumbnailer1@11.service: Succeeded.
Jul 29 14:34:17 david.both.org systemd[2466]: Starting Cleanup of User's Temporary Files and Directories...
Jul 29 14:34:17 david.both.org systemd[2466]: systemd-tmpfiles-clean.service: Succeeded.
Jul 29 14:34:17 david.both.org systemd[2466]: Finished Cleanup of User's Temporary Files and Directories.
Jul 29 14:48:26 david.both.org systemd[2466]: Started dbus-:1.2-org.freedesktop.thumbnails.Thumbnailer1@12.service.
Jul 29 14:48:26 david.both.org tumblerd[145875]: Registered thumbnailer gsf-office-thumbnailer -i %i -o %o -s %s
<SNIP>
此输出显示了 UID1000 用户的临时文件清理等内容。与单个用户相关的数据可能有助于查找用户空间中出现的问题的根本原因。我在此输出中找到了一些有趣的条目。在您的主机上尝试一下,看看您发现了什么。
添加日志条目
将您自己的条目添加到日志中可能很有用。这可以通过 systemd-cat
程序完成,该程序允许将命令或程序的 STDOUT 管道传输到日志。此命令可以用作命令行或脚本中的管道的一部分
[root@testvm1 ~]# echo "Hello world" | systemd-cat -p info -t myprog
[root@testvm1 ~]# journalctl -n 10
Jul 27 09:01:01 testvm1.both.org CROND[976442]: (root) CMD (run-parts /etc/cron.hourly)
Jul 27 09:01:01 testvm1.both.org run-parts[976445]: (/etc/cron.hourly) starting 0anacron
Jul 27 09:01:01 testvm1.both.org run-parts[976451]: (/etc/cron.hourly) finished 0anacron
Jul 27 09:07:53 testvm1.both.org unknown[976501]: Hello world
Jul 27 09:10:47 testvm1.both.org systemd[1]: Starting system activity accounting tool...
Jul 27 09:10:47 testvm1.both.org systemd[1]: sysstat-collect.service: Succeeded.
Jul 27 09:10:47 testvm1.both.org systemd[1]: Finished system activity accounting tool.
Jul 27 09:10:47 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=sysstat-collect comm="systemd" exe="/usr/lib/syst>
Jul 27 09:10:47 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=sysstat-collect comm="systemd" exe="/usr/lib/syste>
Jul 27 09:17:10 testvm1.both.org myprog[976516]: Hello world
[root@testvm1 ~]#
-p
选项指定优先级,可以是 emerg、alert、crit、err、warning、notice、info、debug,也可以是介于 0 和 7 之间的值,表示每个命名级别。这些优先级值与 syslog(3)
定义的优先级值相同。默认值为 info。-t
选项是一个标识符,可以是任何任意短字符串,例如程序或脚本名称。此字符串可用于 journalctl
命令的搜索
[root@testvm1 ~]# journalctl -t myprog
-- Logs begin at Mon 2020-06-08 07:47:20 EDT, end at Mon 2020-07-27 09:21:57 EDT. --
Jul 27 09:17:10 testvm1.both.org myprog[976516]: Hello world
[root@testvm1 ~]#
日志管理
我使用 --disk-usage
选项来检查日志大小,以及与磁盘使用情况相关的其他命令,以确保我的 /var
文件系统没有被填满
[root@testvm1 ~]# journalctl --disk-usage
Archived and active journals take up 136.0M in the file system.
[root@testvm1 ~]#
testvm1 主机上的日志的磁盘使用量约为 136MB。我的主工作站上的结果为 328MB,而我用于防火墙和路由器的主机使用 2.8GB 的日志。日志大小在很大程度上取决于主机的用途和每日运行时长。我的物理主机都 24x7 全天候运行。
可以使用 /etc/systemd/journald.conf
文件配置日志文件大小、轮换和保留时间,以满足默认设置无法满足的任何需求。您还可以配置日志存储位置——您可以指定存储设备上的目录,或者是否将所有内容存储在 RAM 中(RAM 是易失性存储)。如果日志存储在 RAM 中,则它们在启动之间不会持久存在。
journald.conf
文件中的默认时间单位是秒,但可以使用后缀 year
、month
、week
、day
、h
或 m
覆盖它。
假设您要将分配给日志文件的总存储空间限制为 1GB,将所有日志条目存储在持久性存储中,最多保留 10 个文件,并删除超过一个月的任何日志存档文件。您可以使用以下配置在 /etc/systemd/journald.conf
中配置此项
SystemMaxUse=1G
Storage=persistent
SystemMaxFiles=10
MaxRetentionSec=1month
默认情况下,SystemMaxUse
是可用磁盘空间的 10%。默认设置对于我使用的系统来说已经足够好了,我不需要更改任何设置。journald.conf
手册页指出,用于指定在单个文件中存储日志条目的时间或保留旧文件的时间的基于时间的设置通常不是必需的。这是因为文件数量和大小配置通常会在任何时间设置可能需要之前强制轮换和删除旧文件。
SystemKeepFree
选项确保保留特定数量的空间用于其他数据。许多数据库和应用程序程序使用 /var
文件系统来存储数据,因此在硬盘驱动器较小且分配给 /var
的空间最少的系统中,确保足够的可用存储空间可能至关重要。
如果您对此配置进行更改,请务必在适当的时间段内仔细监控结果,以确保它们按预期执行。
日志文件轮换
日志文件通常根据 /etc/systemd/journald.conf
文件中的配置自动轮换。每当满足指定的条件之一时,文件就会轮换。因此,例如,如果分配给日志文件的空间超出,则会删除最旧的文件,将活动文件转换为存档文件,并创建一个新的活动文件。
日志文件也可以手动轮换。我建议使用 --flush
选项以确保在运行命令之前将当前数据移动到持久性存储
[root@testvm1 ~]# journalctl --rotate
还有另一种方法可以清除旧日志文件,而无需执行文件轮换。vacuum-size=
、vacuum-files=
和 vacuum-time=
命令可用于删除旧的存档文件,直到总大小、文件数或先前时间达到指定值。选项值仅考虑存档文件,而不考虑活动文件,因此总文件大小的最终减少量可能略低于预期。
以下命令清除旧的存档文件,以便仅保留不到一个月的存档文件。您可以使用 s
、m
、h
、days
、months
、weeks
和 years
后缀
[root@testvm1 ~]# journalctl --vacuum-time=1month
此命令删除除最近四个存档文件外的所有存档文件。如果存档文件少于四个,则不会发生任何事情,并且原始文件数保持不变
[root@testvm1 ~]# journalctl --vacuum-files=4
最后一条 vacuum
命令删除存档文件,直到剩余 200MB 或更少的存档文件
[root@testvm1 ~]# journalctl --vacuum-size=200M
仅删除完整的文件。vacuum 命令不会截断存档文件以满足规范。它们也仅适用于存档文件,而不适用于活动文件。
最后的想法
本文介绍了如何使用 journalctl
命令以不同格式从 systemd 日志中提取各种类型的数据。它还探讨了管理日志文件以及如何从命令和脚本向日志添加条目。
与旧的 syslogd 程序相比,systemd 日志系统为条目提供了大量的元数据和上下文。这些附加数据以及事件发生前后其他日志条目提供的上下文可以帮助系统管理员比搜索多个 syslog 文件更快地找到并解决问题。
在我看来,journalctl
命令符合 Unix 哲学,即程序应该做好一件事并做好。journalctl
唯一做的就是从日志中提取数据,并提供许多选项来选择和格式化该数据。它大约 85K,不是很大。当然,这不包括共享库,但根据定义,这些库与其他程序共享。
您现在应该有足够的信息来更有效地使用 systemd 日志。如果您想了解比我在此处介绍的更多内容,请查看 journalctl
和 systemd-cat
的手册页。
资源
互联网上有大量关于 systemd 的信息,但其中很多都很简洁、晦涩甚至具有误导性。除了本文中提到的资源外,以下网页还提供了关于 systemd 启动的更详细和可靠的信息。自从我开始撰写本系列文章以来,此列表不断增长,以反映我所做的研究。
- DigitalOcean 有一篇关于 journalctl 以及如何查看和操作 systemd 日志 的非常好的文章。
- Fedora 项目有一个很好的实用 指南 systemd 指南。它几乎包含了您需要了解的所有内容,以便使用 systemd 配置、管理和维护 Fedora 计算机。
- Fedora 项目还有一个很好的 速查表,其中交叉引用了旧的 SystemV 命令和可比较的 systemd 命令。
- Red Hat 文档包含对 单元文件结构 以及其他重要信息的良好描述。
- 有关 systemd 的详细技术信息以及创建 systemd 的原因,请查看 Freedesktop.org 的 systemd 描述。
- Linux.com 的 “Systemd 更多乐趣” 提供了更高级的 systemd 信息和技巧。
还有一系列由 Lennart Poettering(systemd 的设计者和主要开发者)为 Linux 系统管理员撰写的深入技术文章。这些文章写于 2010 年 4 月至 2011 年 9 月之间,但它们现在和当时一样具有现实意义。关于 systemd 及其生态系统的其他优秀文章大多基于这些论文。
评论已关闭。