如何使用journalctl 来观察和操作systemd的日志
介绍
systemd的一些不错的有点就是它能涉及到进程的系统的日志。对于其他日志工具,日志通常被分布到整个系统中,由不同的daemon和进程来管理,因此当他们扫描多个应用的时候,他们在翻译日志的时候可能就有点困难。systemd通过提供一个中心化的管理解决方案来记录所有kernel级别和user级别的进程。其中systemd所收集的日志中,都可以通过journal来获取。
journal是通过journald这个daemon来实现的,它可以处理所有来自于kernel,initrd,services等的日志messages.下面将着重介绍如何使用journalctl的使用,通过它可以随意访问和操作由journal产生的数据。
主旨
systemd日志的其中一个出发点,就是让来自各个进程的日志消息中心化,这样一来,很多boot进程和服务管理都被systemd进程管理,这样systemd就可以让所有日志的收集和处理统一化。journald的daemon进程从所有日志源哪里获取数据,同时将他们存储为二进制文件,这样对日志的处理和管理操作更容易。
这样做有很多优点。通过和一个应用实体进程进行交互来获取数据,管理员能够完全根据自己的需要来动态显示日志数据。因此可以很容易的查看重启几次的日志,而且可以将相互关联的不同服务进行联合查询,依此更好的debug。
将日志数据存储为二进制格式代表你可以根据自己需求将数据展现为你想要展示的格式。例如,每天的日志管理系统你可以以标准syslog格式显示,但是如果以后决定对服务中断进行图形处理,则可以将每个条目作为JSON对象输出,以使其可用于图形服务。如果数据以文本的形式写入到磁盘,那么当你需要一个特定格式的需求时,那么就不会有对话形式的输出。
systemd日志可以被用作syslog形式的日志,它也可以在功能上代替syslog,完全取决于你的需求。systemd日志几乎可以满足大多数管理员日志需求,他也可以为已经实现的日志机制进行补充。比如。你可能已经有中心化的syslog服务器,你可以从多个服务器集群来收集日志数据。但是你也可能希望想将多个服务器的日志集成到一个systemd日志里。这样你就可以将这些技术完全结合起来。
系统时间的设置setting the system time
二进制日志文件的一个好处就是你可以使用UTC时间或者当地时间为索引来查看日志。默认systemd显示你本地时间。
因此,在我们开始journal之前,我们需要确定时区的设置是正确的。systemd组件可与timedatectl工具结合使用,可以帮助你实现:
- 查看都有那些时区(list-timezones)
timedatectl list-timezones
该命令将列出你系统的所有可用时区。当你发现与你的服务器所匹配的时区,你可以通过set-timezone:
sudo timedatectl set-timezone <zone>
为了保证你的机器使用的正确的时间,使用timedatectl命令,或者status选项来显示:
timedatectl status
第一行应该显示正确的时间
Local time: Thu 2015-02-05 14:08:06 EST
Universal time: Thu 2015-02-05 19:08:06 UTC
RTC time: Thu 2015-02-05 19:08:06
Time zone: America/New_York (EST, -0500)
NTP enabled: no
NTP synchronized: no
RTC in local TZ: no
DST active: n/a
查看基本的log日志
为了查看journald这个daemon所收集的日志,使用journalctl命令,当你单独使用的时候,显示所有的记录,按照时间从前到后进行显示:
journalctl
这样你可能会有很多页需要翻越查看。
-- Logs begin at Tue 2015-02-03 21:48:52 UTC, end at Tue 2015-02-03 22:29:38 UTC. --
Feb 03 21:48:52 localhost.localdomain systemd-journal[243]: Runtime journal is using 6.2M (max allowed 49.
Feb 03 21:48:52 localhost.localdomain systemd-journal[243]: Runtime journal is using 6.2M (max allowed 49.
Feb 03 21:48:52 localhost.localdomain systemd-journald[139]: Received SIGTERM from PID 1 (systemd).
Feb 03 21:48:52 localhost.localdomain kernel: audit: type=1404 audit(1423000132.274:2): enforcing=1 old_en
Feb 03 21:48:52 localhost.localdomain kernel: SELinux: 2048 avtab hash slots, 104131 rules.
Feb 03 21:48:52 localhost.localdomain kernel: SELinux: 2048 avtab hash slots, 104131 rules.
Feb 03 21:48:52 localhost.localdomain kernel: input: ImExPS/2 Generic Explorer Mouse as /devices/platform/
Feb 03 21:48:52 localhost.localdomain kernel: SELinux: 8 users, 102 roles, 4976 types, 294 bools, 1 sens,
Feb 03 21:48:52 localhost.localdomain kernel: SELinux: 83 classes, 104131 rules
. . .
习惯于标准syslog日志记录的人会熟悉该格式。 但是,这实际上比传统的syslog实现所能收集的数据来源更多。 它包括来自早期引导过程,内核,initrd和应用程序标准错误以及退出的日志。 这些都可以在日记中找到。
你会发现所有的时间戳都是基于当地时间。如果你想以UTC时间展示时间戳,你可以使用--utc:
journalctl --utc
通过时间对journal进行过滤
虽然访问如此大量的数据绝对有用,但是从心理上很难检查和处理如此大量的信息。 因此,journalctl的最重要功能之一是其过滤选项。
显示当前boot的日志
您可能每天使用的最基本的是-b标志。 这将显示自最近重启以来收集的所有日记帐分录。
joutnalctl -b
这将帮助您识别和管理与当前环境有关的信息。
In cases where you aren’t using this feature and are displaying more than one day of boots, you will see that journalctl has inserted a line that looks like this whenever the system went down:
. . .
-- Reboot --
. . .
这可以用来帮助您在逻辑上将信息分成启动会话。
Past Boots
虽然您通常希望显示当前引导中的信息,但是在某些情况下,过去的引导当然也会有所帮助。 日志可以保存以前许多启动中的信息,因此可以使journalctl轻松显示信息。
有些发行版默认启用保存以前的引导信息,而其他发行版禁用此功能。 要启用持久启动信息,您可以通过输入以下内容来创建目录来存储日志:
sudo mkdir -p /var/log/journal
你也可以编辑journal的配置文件:
sudo nano /etc/systemd/journald.conf
在配置journal配置文件时,在[Journal]区域,你可以设置Storage=persistent选项,来持久化存储日志。
/etc/systemd/journald.conf
. . .
[Journal]
Storage=persistent
在服务器上启用保存以前的启动时,journalctl提供了一些命令来帮助您将启动作为划分单位使用。 要查看已记录日记的boot,请在journalctl中使用--list-boots选项:
journalctl --list-boots
-2 caf0524a1d394ce0bdbcff75b94444fe Tue 2015-02-03 21:48:52 UTC—Tue 2015-02-03 22:17:00 UTC
-1 13883d180dc0420db0abcb5fa26d6198 Tue 2015-02-03 22:17:03 UTC—Tue 2015-02-03 22:19:08 UTC
0 bed718b17a73415fade0e4e7f4bea609 Tue 2015-02-03 22:19:12 UTC—Tue 2015-02-03 23:01:01 UTC
这将在每次启动时显示一行。 第一列是引导程序的偏移量,可用于轻松地使用journalctl引用引导程序。 如果需要绝对引用,则引导ID在第二列中。 您可以告诉时间引导会话所引用的时间,并在最后列出两个时间规范。
要显示这些引导的信息,您可以使用第一列或第二列中的信息。
例如,要查看上一次引导的日志,请使用带有-b标志的-1相对指针:
journalctl -b -1
你可以通过使用bootID来调用不同boot的日志:
journalctl -b caf0524a1d394ce0bdbcff75b94444fe
Time Windows
尽管通过引导查看日志条目非常有用,但通常您可能希望请求与系统启动不太匹配的时间窗口。 在处理运行时间较长且运行时间较长的服务器时,尤其如此。
也可以通过--since 和 --until 选项可以分别严格要显示的时间。
比如,我想查看在2019年10月1号到10月8号下午5:15的日志,你可以:
journalctl --since "2019-10-1" --until "2019-10-08 17:15:00"
如果不使用上述格式的组件,则会应用一些默认设置。 例如,如果省略日期,则采用当前日期。 如果缺少时间部分,则将替换为“ 00:00:00”(午夜)。 秒字段也可以保留为默认值“ 00”:
该日记还知道一些相对值和命名的快捷方式。 例如,您可以使用单词“昨天”,“今天”,“明天”或“现在”。 您可以通过在数字前面加上“-”或“ +”或在句子结构中使用诸如“ ago”之类的字来进行相对时间。
为了获取从昨天开始日志,你可以:
journalctl --since yesterday
如果您收到从9:00 AM开始一直持续到一个小时前的服务中断报告,则可以输入:
journalctl --since 09:00 --until "1 hour ago"
正如你缩减,你可以很灵活地使用相对时间窗口来过滤你想看的日志信息。
通过感兴趣的信息来过滤
我们从上面学到了一些可以使用时间约束来过滤日记数据的方法。 在本节中,我们将讨论如何根据您感兴趣的服务或组件进行过滤。systemd日记提供了多种执行此操作的方法。
By Unit
也许最有用的过滤方法是按您感兴趣的单位进行过滤。我们可以使用-u选项以这种方式进行过滤。
例如,要查看系统中Nginx单元的所有日志,我们可以输入:
journalctl -u nginx.service
通常,您可能还希望按时间进行过滤,以便显示您感兴趣的行。例如,要检查服务今天的运行方式,您可以键入:
journalctl -u nginx.service --since today
当您利用journalctl的功能来交错各个部分的记录时,这种类型的关注将变得非常有用。 例如,如果您的Nginx进程连接到PHP-FPM单元以处理动态内容,则可以通过指定两个单元按时间顺序合并两个条目:
journalctl -u nginx.service -u php-fpm.service --since today
这样可以更轻松地发现不同程序和调试系统之间的交互,而不是单个进程。
By Process, User, or Group ID
一些服务产生了各种各样的子进程来工作。 如果您已找出所需过程的确切PID,则也可以按此进行过滤。
为此,我们可以通过指定_PID字段进行过滤。 例如,如果我们感兴趣的PID是8088,则可以输入:
journalctl _PID=8088
在其他时候,您可能希望显示从特定用户或组记录的所有条目。 这可以通过_UID或_GID过滤器完成。 例如,如果您的Web服务器在www-data用户下运行,则可以通过键入以下内容找到用户ID:
id -u www-data
33
之后,您可以使用返回的ID来过滤日记帐结果:
journalctl _UID=33 --since today
systemd日记具有许多可用于过滤的字段。 其中一些是从正在记录的进程中传递的,而有些是使用日志记录时从系统收集的信息通过日记进行应用的。
前划线表示_PID字段属于后一种类型。 日志会自动记录并索引正在记录的进程的PID,以供以后过滤。 您可以通过键入以下内容查找所有可用的日记帐字段:
man systemd.journal-fields
我们将在本指南中讨论其中一些内容。 但就目前而言,我们将讨论一个更有用的选项,该选项与这些字段的过滤有关。 -F选项可用于显示给定日记帐字段的所有可用值。
例如,要查看systemd日记所属的组,可以键入:
journalctl -F _GID
32
99
102
133
81
84
100
0
124
87
这将显示日记帐为组ID字段存储的所有值。 这可以帮助您构造过滤器。
By Component Path
我们还可以通过提供路径位置进行过滤。
如果该路径指向可执行文件,则journalctl将显示涉及该可执行文件的所有条目。 例如,要查找涉及bash可执行文件的条目,可以键入:
journalctl /usr/bin/bash
通常,如果某个单元可用于可执行文件,则该方法会更干净并且提供更好的信息(来自相关子进程的条目等)。 但是,有时这是不可能的。
Displaying Kernel Messages
通常在dmesg输出中找到的内核消息也可以从日志中检索。
要仅显示这些消息,我们可以在命令中添加-k或--dmesg标志:
journalctl -k
默认情况下,这将显示当前引导中的内核消息。 您可以使用前面讨论的常规引导选择标志来指定备用引导。 例如,要获取五个引导之前的消息,可以输入:
journalctl -k -b -5
By Priority
系统管理员经常感兴趣的一种过滤器是消息优先级。 虽然以非常冗长的级别记录信息通常很有用,但是在实际消化可用信息时,低优先级日志可能会分散注意力和造成混乱。
You can use journalctl to display only messages of a specified priority or above by using the -p option. This allows you to filter out lower priority messages.
For instance, to show only entries logged at the error level or above, you can type:
journalctl -p err -b
这将向您显示标记为错误,严重,警报或紧急情况的所有消息。 日志实现标准的系统日志消息级别。 您可以使用优先级名称或其对应的数值。 按优先级从高到低的顺序为:
0: emerg
1: alert
2: crit
3: err
4: warning
5: notice
6: info
7: debug
上面的数字或名称可以与-p选项互换使用。 选择优先级将显示标记在指定级别及其上方的消息。
Modifying the Journal Display
上面,我们通过过滤演示了条目选择。 我们还有其他方法可以修改输出。 我们可以调整journalctl显示以适应各种需求。
Truncate or Expand Output
我们可以通过告诉journalctl缩小或扩展输出来调整它们的显示方式。
默认情况下,journalctl将在寻呼机中显示整个条目,从而允许这些条目在屏幕右侧尾随。 可以通过按右箭头键访问此信息。
如果您希望输出被截断,请在省略了信息的地方插入省略号,可以使用--no-full选项:
journalctl --no-full
. . .
Feb 04 20:54:13 journalme sshd[937]: Failed password for root from 83.234.207.60...h2
Feb 04 20:54:13 journalme sshd[937]: Connection closed by 83.234.207.60 [preauth]
Feb 04 20:54:13 journalme sshd[937]: PAM 2 more authentication failures; logname...ot
您也可以与此相反,并告诉journalctl显示其所有信息,而不管其是否包含不可打印的字符。 我们可以使用-a标志来做到这一点:
journalctl -a
Output to Standard Out
默认情况下,journalctl在寻呼机中显示输出,以便于使用。 但是,如果计划使用文本处理工具处理数据,则可能希望能够输出到标准输出。
您可以使用--no-pager选项执行此操作:
journalctl --no-pager
可以根据需要将其立即传送到处理实用程序中,或重定向到磁盘上的文件中。
Output Formats
如上所述,如果您正在处理日记帐分录,则如果数据采用更易消耗的格式,则很有可能会更轻松地解析数据。 幸运的是,可以根据需要以多种格式显示日记。 您可以将-o选项与格式说明符一起使用。
例如,您可以通过输入以下内容以JSON输出日记帐分录:
journalctl -b -u nginx -o json
{ "__CURSOR" : "s=13a21661cf4948289c63075db6c25c00;i=116f1;b=81b58db8fd9046ab9f847ddb82a2fa2d;m=19f0daa;t=50e33c33587ae;x=e307daadb4858635", "__REALTIME_TIMESTAMP" : "1422990364739502", "__MONOTONIC_TIMESTAMP" : "27200938", "_BOOT_ID" : "81b58db8fd9046ab9f847ddb82a2fa2d", "PRIORITY" : "6", "_UID" : "0", "_GID" : "0", "_CAP_EFFECTIVE" : "3fffffffff", "_MACHINE_ID" : "752737531a9d1a9c1e3cb52a4ab967ee", "_HOSTNAME" : "desktop", "SYSLOG_FACILITY" : "3", "CODE_FILE" : "src/core/unit.c", "CODE_LINE" : "1402", "CODE_FUNCTION" : "unit_status_log_starting_stopping_reloading", "SYSLOG_IDENTIFIER" : "systemd", "MESSAGE_ID" : "7d4958e842da4a758f6c1cdc7b36dcc5", "_TRANSPORT" : "journal", "_PID" : "1", "_COMM" : "systemd", "_EXE" : "/usr/lib/systemd/systemd", "_CMDLINE" : "/usr/lib/systemd/systemd", "_SYSTEMD_CGROUP" : "/", "UNIT" : "nginx.service", "MESSAGE" : "Starting A high performance web server and a reverse proxy server...", "_SOURCE_REALTIME_TIMESTAMP" : "1422990364737973" }
. . .
这对于使用实用程序进行解析很有用。 您可以使用json-pretty格式来更好地处理数据结构,然后再将其传递给JSON使用者:
journalctl -b -u nginx -o json-pretty
{
"__CURSOR" : "s=13a21661cf4948289c63075db6c25c00;i=116f1;b=81b58db8fd9046ab9f847ddb82a2fa2d;m=19f0daa;t=50e33c33587ae;x=e307daadb4858635",
"__REALTIME_TIMESTAMP" : "1422990364739502",
"__MONOTONIC_TIMESTAMP" : "27200938",
"_BOOT_ID" : "81b58db8fd9046ab9f847ddb82a2fa2d",
"PRIORITY" : "6",
"_UID" : "0",
"_GID" : "0",
"_CAP_EFFECTIVE" : "3fffffffff",
"_MACHINE_ID" : "752737531a9d1a9c1e3cb52a4ab967ee",
"_HOSTNAME" : "desktop",
"SYSLOG_FACILITY" : "3",
"CODE_FILE" : "src/core/unit.c",
"CODE_LINE" : "1402",
"CODE_FUNCTION" : "unit_status_log_starting_stopping_reloading",
"SYSLOG_IDENTIFIER" : "systemd",
"MESSAGE_ID" : "7d4958e842da4a758f6c1cdc7b36dcc5",
"_TRANSPORT" : "journal",
"_PID" : "1",
"_COMM" : "systemd",
"_EXE" : "/usr/lib/systemd/systemd",
"_CMDLINE" : "/usr/lib/systemd/systemd",
"_SYSTEMD_CGROUP" : "/",
"UNIT" : "nginx.service",
"MESSAGE" : "Starting A high performance web server and a reverse proxy server...",
"_SOURCE_REALTIME_TIMESTAMP" : "1422990364737973"
}
. . .
可以使用以下格式进行显示:
- cat: Displays only the message field itself.
- export: A binary format suitable for transferring or backing up.
- json: Standard JSON with one entry per line.
- json-pretty: JSON formatted for better human-readability
- json-sse: JSON formatted output wrapped to make add server-sent event compatible
- short: The default syslog style output
- short-iso: The default format augmented to show ISO 8601 wallclock timestamps.
- short-monotonic: The default format with monotonic timestamps.
- short-precise: The default format with microsecond precision
- verbose: Shows every journal field available for the entry, including those usually hidden internally.
这些选项允许您以最适合您当前需求的格式显示日记帐分录。
Active Process Monitoring
journalctl命令模拟了多少管理员使用tail来监视活动或最近的活动。 此功能内置在journalctl中,使您无需使用其他工具即可访问这些功能。
Displaying Recent Logs
要显示一定数量的记录,可以使用-n选项,该选项与尾号-n完全相同。
默认情况下,它将显示最近的10个条目:
journalctl -n
您可以使用-n后面的数字指定要查看的条目数:
journalctl -n 20
Following Logs
要在记录日志时积极跟踪它们,可以使用-f标志。 同样,如果您有使用tail -f的经验,这可以按您预期的那样工作:
journalctl -f
Journal Maintenance
您可能想知道是否要花成本来存储到目前为止我们看到的所有数据。 此外,您可能会在清理一些较旧的日志并释放空间方面感兴趣。
Finding Current Disk Usage
您可以使用--disk-usage标志找出日志当前在磁盘上所占用的空间量:
journalctl --disk-usage
Journals take up 8.0M on disk.
Deleting Old Logs
如果您希望缩小日记本,可以用两种不同的方法(在218版及更高版本的系统版本中可用)。
如果使用--vacuum-size选项,则可以通过指定大小来缩小日记帐。 这将删除旧条目,直到磁盘上占用的日志总空间达到请求的大小为止:
sudo journalctl --vacuum-size=1G
收缩日志的另一种方法是使用--vacuum-time选项提供截止时间。 超过该时间的所有条目将被删除。 这使您可以保留在特定时间之后创建的条目。
例如,要保留上一年的条目,可以输入:
sudo journalctl --vacuum-time=1years
Limiting Journal Expansion
您可以配置服务器以限制日志可占用的空间。 可以通过编辑/etc/systemd/journald.conf文件来完成。
以下各项可用于限制日记帐的增长:
SystemMaxUse =:指定日志在持久性存储中可以使用的最大磁盘空间。
SystemKeepFree =:指定将日记帐分录添加到持久性存储时日记应保留的可用空间量。
SystemMaxFileSize =:控制旋转前在持久性存储中可以增加到单个日记文件的大小。
RuntimeMaxUse =:指定可用于易失性存储(在/ run文件系统中)的最大磁盘空间。
RuntimeKeepFree =:指定将数据写入易失性存储(在/ run文件系统中)时留给其他用途的空间量。
RuntimeMaxFileSize =:指定单个日记文件在旋转之前可以在易失性存储(在/ run文件系统中)占用的空间量。
通过设置这些值,您可以控制日记记录消耗和保留服务器上空间的方式。 请记住,SystemMaxFileSize和RuntimeMaxFileSize将以归档文件为目标,以达到规定的限制。 在清理操作之后解释文件计数时,记住这一点很重要。
Conclusion
如您所见,systemd日志对于收集和管理系统和应用程序数据非常有用。 大多数灵活性来自自动记录的大量元数据和日志的集中式性质。 journalctl命令使您可以轻松利用日志的高级功能,并对不同的应用程序组件进行广泛的分析和关系调试。