如何使用JournalCtl检查日志
1. 简介
在调试或解决我们的一项服务的问题时,通常我们首先要查看的是我们的系统和服务的日志。在执行此操作时,我们希望尽可能具体,并避免筛选来自不同来源的数千个日志条目。
大多数主要的 Linux 发行版都使用*systemd *来管理服务和系统组件。因此,我们需要知道它的日志管理实用程序journalctl 是如何工作的,以便能够在 Linux 系统上有效地检查日志。
在本文中,我们将了解如何使用journalctl工具检查、过滤和清理 Linux 系统上的日志。
2. 基本的 journalctl 命令
systemd以二进制格式存储系统和服务日志。这意味着我们不能直接使用cat 、tail 、grep 、sed 或awk 等常规文本处理工具来读取我们的日志,因为我们的日志不存储为纯文本文件。
因此,我们需要journalctl命令行工具来首先读取和输出我们的日志。让我们从几个基本的journalctl命令开始:
2.1. boots
journalctl可以通过系统的特定启动来检索我们的日志。
要获取boots列表,让我们运行:
$ journalctl --list-boots
-136 6e7ae03aa08a4887a6dc376a30ef1fdb Mon 2020-10-12 00:59:31 +03—Mon 2020-10-12 01:02:06 +03
-135 5e8f616769aa4413b198ef30277bf628 Mon 2020-10-12 01:02:38 +03—Mon 2020-10-12 02:55:47 +03
-134 7b839631c6b54dba8e183a0a91f4fa51 Mon 2020-10-12 02:56:29 +03—Wed 2020-10-14 00:16:38 +03
..
-3 539bf36b695f4d69b3474e1efad9f6e6 Wed 2021-01-27 10:25:02 +03—Wed 2021-01-27 20:46:49 +03
-2 d16424126db24a34b6079b933d0cc09a Wed 2021-01-27 20:47:43 +03—Wed 2021-01-27 23:53:16 +03
-1 d4ca259000374bb9a14e383df551aa6e Thu 2021-01-28 10:15:03 +03—Fri 2021-01-29 20:48:03 +03
0 041a418db54e47fabc646e35da606902 Fri 2021-01-29 20:48:41 +03—Sat 2021-01-30 20:57:10 +03
正如我们看到的,这个系统的第一次启动是-136th,最后一次启动是0。每个启动也有一个不同的哈希值。
要获取当前启动的所有日志,让我们运行:
$ journalctl -b
..
Jan 29 20:48:43 fcivaner-ThinkPad-T480s systemd[1]: Starting Authorization Manager...
Jan 29 20:48:43 fcivaner-ThinkPad-T480s systemd[1]: Reached target Bluetooth.
Jan 29 20:48:43 fcivaner-ThinkPad-T480s grub-common[1146]: ...done.
Jan 29 20:48:43 fcivaner-ThinkPad-T480s systemd[1]: Started LSB: Record successful boot for GRUB.
Jan 29 20:48:43 fcivaner-ThinkPad-T480s apport[1111]: ...done.
Jan 29 20:48:43 fcivaner-ThinkPad-T480s systemd[1]: Started LSB: automatic crash report generation.
Jan 29 20:48:43 fcivaner-ThinkPad-T480s polkitd[1203]: started daemon version 0.105 using authority implementation `local' version `0.105'
Jan 29 20:48:43 fcivaner-ThinkPad-T480s dbus-daemon[1115]: [system] Successfully activated service 'org.freedesktop.hostname1'
Jan 29 20:48:43 fcivaner-ThinkPad-T480s systemd[1]: Started Hostname Service.
Jan 29 20:48:43 fcivaner-ThinkPad-T480s NetworkManager[1141]: <info> [1611942523.8157] NetworkManager (version 1.10.6) is starting... (for the first time)
..
我们看到的日志条目来自所有服务,合并在一个日志中。我们可以看到,在我们的系统启动的早期,systemd正在启动与蓝牙相关的服务,然后我们看到我们的策略包(polkitd)启动,然后是我们的网络管理器。
要获取上次启动的所有日志条目,让我们运行:
$ journalctl -b -1
Jan 28 10:15:03 fcivaner-ThinkPad-T480s kernel: microcode: microcode updated early to revision 0xe0, date = 2020-06-17
Jan 28 10:15:03 fcivaner-ThinkPad-T480s kernel: Linux version 5.4.0-64-generic ([[email protected]](/cdn_cgi/l/email_protection)) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #72~18.04.1-Ubuntu SMP Fri Jan 15 14:06:34 UTC 2021
Jan 28 10:15:03 fcivaner-ThinkPad-T480s kernel: Command line: BOOT_IMAGE=/boot/vmlinuz-5.4.0-64-generic root=UUID=19112d3d-1e88-45c7-be9a-a0d3119a8b18 ro quiet splash vt.handoff=1
Jan 28 10:15:03 fcivaner-ThinkPad-T480s kernel: KERNEL supported cpus:
Jan 28 10:15:03 fcivaner-ThinkPad-T480s kernel: Intel GenuineIntel
Jan 28 10:15:03 fcivaner-ThinkPad-T480s kernel: AMD AuthenticAMD
Jan 28 10:15:03 fcivaner-ThinkPad-T480s kernel: Hygon HygonGenuine
Jan 28 10:15:03 fcivaner-ThinkPad-T480s kernel: Centaur CentaurHauls
Jan 28 10:15:03 fcivaner-ThinkPad-T480s kernel: zhaoxin Shanghai
Jan 28 10:15:03 fcivaner-ThinkPad-T480s kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'...
...
从我们的引导列表中可以看出,我们当前的引导总是有一个索引 0,而我们最后一次引导总是有一个 -1 的索引。我们可以通过在-b参数之后指定它来查看特定引导的日志。
2.2. 按日期或时间过滤
如果我们想按时间过滤日志,我们可以使用*–since和–until*参数。让我们继续尝试一下:
$ journalctl --since="2021-01-30 18:17:16"
Jan 30 18:33:53 fcivaner-ThinkPad-T480s wpa_supplicant[1153]: wlp61s0: WPA: Group rekeying completed with 18:31:bf:c2:98:40 [GTK=CCMP]
Jan 30 18:34:01 fcivaner-ThinkPad-T480s CRON[12094]: pam_unix(cron:session): session opened for user root by (uid=0)
Jan 30 18:34:01 fcivaner-ThinkPad-T480s CRON[12095]: (root) CMD ( test -x /etc/cron.daily/popularity-contest && /etc/cron.daily/popularity-contest --crond)
Jan 30 18:34:01 fcivaner-ThinkPad-T480s CRON[12094]: pam_unix(cron:session): session closed for user root
Jan 30 18:36:58 fcivaner-ThinkPad-T480s kernel: wlp61s0: AP 18:31:bf:c2:98:40 changed bandwidth, new config is 2417 MHz, width 1 (2417/0 MHz)
...
我们也可以使用相对时间参数来快速过滤:
$ journalctl --since "20 min ago"
...
要了解时间解析的工作原理,我们可以参考systemd时间规范 。
3. 进一步缩小范围
3.1. 单位
systemd将资源(服务、套接字、挂载..)标识为单位。我们可以使用-u*标志获取特定单元的日志:*
$ journalctl -u netcfg
也可以指定一个模式来匹配一个或多个单元。例如,要查看以“systemd-”开头的所有单元的日志,我们运行:
$ journalctl -u systemd-*
如果一个单元不是系统服务,而是我们定义为用户的服务,我们可以使用它来查看它的日志;
$ journalctl --user-unit my-application
请注意,当我们使用*–user-unit*时,我们只能看到与我们自己的用户关联的单元的日志。
3.2. 用户和进程
我们还可以过滤属于特定用户 ID 或特定进程 ID 的单元的消息:
$ journalctl _UID=100
$ journalctl _PID=1
3.3. 优先
我们可能还希望查看具有特定优先级的消息,例如错误或警告。
$ journalctl -p err..alert
以下是我们可以用来过滤消息的代码:
代码 | 优先 |
---|---|
0 | emerg |
1 | alert |
2 | crit |
3 | err |
4 | warning |
5 | notice |
6 | info |
7 | debug |
请注意,进程应为每条日志消息输出适当的级别前缀(例如“4”或“warning”表示警告),以便systemd知道每条日志消息的日志级别。否则,此过滤不适用于该进程的日志。
4. 跟踪日志
为了跟踪日志而不是打印它们,我们使用:
$ journalctl -f
例如,假设我们要跟踪服务apache的日志。让我们运行:
$ journalctl -f -u apache
要仅打印最后 10 条日志消息,请使用*-n*参数:
$ journalctl -u apache -n 10
5. 禁用分页以获取直接输出
有时,我们可能希望将日志发送到文件中,将它们通过管道传送到另一个程序进行处理,或者只是使用另一个分页。在这种情况下,我们可以使用*–no-pager选项,这样journalctl*就不会自动打开寻呼机供我们浏览日志:
$ journalctl --no-pager
要使用less 作为寻呼机,让我们尝试:
$ journalctl --no-pager | less -S
6. 清理日志
随着时间的推移,我们系统上的日志会变得非常大并导致问题。这些问题的范围可能从磁盘空间问题到甚至使我们的系统完全崩溃。
幸运的是,我们可以使用journalctl快速清理旧日志。例如,要清理我们的日志以使其磁盘空间使用量低于 100 MB,我们可以使用:
journalctl --vacuum-size=100M
或者要清理我们的日志,使其不包含超过 2 周的数据,我们可以使用:
journalctl --vacuum-time=2weeks
请记住,journald 之前应该将日志标记为“已归档”,以便能够清理它们。只有在我们在journald配置文件 ( /etc/systemd/journald.conf )中定义的参数过期后,它才会这样做。
这些参数是:
- SYSTEMKEEPFREE
- RUNTIMEKEEPFREE
- SYSTEMMAXFILESIZE
- RUNTIMEMAXFILESIZE
- MAXRETENTIONSEC
- MAXFILESEC
这些参数决定了我们有多少日志将被标记为已归档。我们只能清理标记为已归档的日志,因此调整要保留多少日志对我们来说很重要。
当我们在*/etc/systemd/journald.conf*中定义这些参数时,我们很可能想要调整以“ SYSTEM ”开头的参数。“ RUNTIME ” 参数仅在我们的日志存储在内存文件系统中时应用。通常,在我们将使用的大多数 Linux 系统中,日志将存储在持久文件系统中。
“ KEEPFREE ” 参数确定**journald将尝试保留多少空间供其他用户使用,“ MAXFILESIZE ” 参数确定活动日志条目可以在磁盘上占用的最大大小。如果存在冲突,则首选两者之间的最小空间。
要显示所有日志文件的总磁盘使用情况,我们可以使用:
journalctl --disk-usage
7. 授予用户查看系统日志的权限
默认情况下,只有具有特定权限的用户(root、sudo ers 或wheel)才能看到系统日志。如果我们没有这些权限,我们可能会收到一条错误消息:
"No journal files were opened due to insufficient permissions."
在进行系统管理时,我们可能希望没有 root 权限的用户能够查看所有日志以进行调试。systemd-journal、adm和wheel / sudo组的成员可以读取所有日志文件。另一方面,组adm和wheel / sudo通常还具有系统上的其他管理权限。
因此,使用systemd-journal作为我们将添加用户的组是一个更好的选择。
要允许用户读取系统日志,请运行:
$ usermod -a -G systemd-journal USER
我们将USER替换为我们想要访问的用户名。
8. 输出格式
我们可能还想以不同的方式格式化我们的日志,也许将它们发送到其他系统进行存储和分析。我们可以使用*-o*参数来做到这一点:
$ journalctl -b -u docker -o json
正如预期的那样,我们将看到 JSON 格式的条目:
{
"__CURSOR": "s=188c4f9b9b9148e8b51e1d83acece38c;i=3262ca;b=1b845a1c4af044128eb82da1b49f8a9e;m=14cfbac;t=5bb02ecf82bd3;x=bdd8df9be3959797",
"__REALTIME_TIMESTAMP": "1612996123569107",
"__MONOTONIC_TIMESTAMP": "21822380",
"_BOOT_ID": "1b845a1c4af044128eb82da1b49f8a9e",
"PRIORITY": "6",
"_UID": "0",
"_GID": "0",
"_SELINUX_CONTEXT": "unconfined\n",
"_SYSTEMD_SLICE": "system.slice",
"_MACHINE_ID": "ed152e13dffc4a0aa8ab86f0b781cd23",
"_HOSTNAME": "fcivaner-ThinkPad-T480s",
"SYSLOG_FACILITY": "3",
"_CAP_EFFECTIVE": "3fffffffff",
"_TRANSPORT": "stdout",
"SYSLOG_IDENTIFIER": "dockerd",
"_COMM": "dockerd",
"_EXE": "/usr/bin/dockerd",
"_CMDLINE": "/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock",
"_SYSTEMD_CGROUP": "/system.slice/docker.service",
"_SYSTEMD_UNIT": "docker.service",
"_STREAM_ID": "61ec716173cb4e52bd940795991b3463",
"_PID": "2002",
"_SYSTEMD_INVOCATION_ID": "5f3e883264d347c0aec150e82c6b79e5",
"MESSAGE": "time=\"2021-02-11T01:28:43.568571629+03:00\" level=info msg=\"Docker daemon\" commit=46229ca graphdriver(s)=overlay2 version=20.10.3"
},
...