systemd 的 journalctl:如何按消息过滤?

art*_*bot 10 systemd debian-jessie journalctl

journalctl看起来是一个很好的查看日志的工具,但我被困在一个简单的问题上:我想查看包含短语的所有 cron 消息update-ipsets

我当然可以这样做

journalctl -u cron.service | grep update-ipsets
Run Code Online (Sandbox Code Playgroud)

但是随后您将失去 journalctl 输出的所有其他好处(颜色编码、自动分页、实时取景等)

我试过了:

journalctl -u cron.service MESSAGE=update-ipsets
journalctl -u cron.service "MESSAGE=*update-ipsets*"
journalctl -u cron.service "MESSAGE=.*update-ipsets.*"
journalctl -u cron.service "MESSAGE=/.*update-ipsets.*/"
Run Code Online (Sandbox Code Playgroud)

而且您不想通过点击tab后进行实验MESSAGE=- 挂起(zsh / Debian Jessie)shell并且Ctrl-C也没有帮助!

我有点不敢相信它没有内置这个基本功能,所以我确定我一定错过了什么?

谢谢。

Tom*_*art 14

由于systemctl --version版本237可能有带有-g/--grepswitch 的 grep 模式支持,但它必须在PRCE2支持下编译(它似乎没有包含在 Debian Buster 中>=242需要,可以从 中安装buster-backports

journalctl -g ipsets*
Run Code Online (Sandbox Code Playgroud)

如果没有 grep 支持,您仍然可以切换到cat输出模式并使用grep's 匹配:

journalctl -b -o cat --no-pager | grep "update-ipsets"
Run Code Online (Sandbox Code Playgroud)

如果您想要寻呼机,最好将结果通过管道传输到less. 您可以使用反向匹配-v / --invert-match来排除某些消息

journalctl -b -o cat --no-pager | grep -v "ACPI" | less
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用json格式:

journalctl -b -o json | jq -C . | less -R
Run Code Online (Sandbox Code Playgroud)

给出详细的单行输出

{
  "SYSLOG_IDENTIFIER": "kernel",
  "_MACHINE_ID": "d72735cff36a41f0a5326f0bb7eb1778",
  "_SOURCE_MONOTONIC_TIMESTAMP": "0",
  "__REALTIME_TIMESTAMP": "1614516018297106",
  "__CURSOR": "s=2b1deb3dba3e42e4a758cc8f011d19c5;i=1;b=c0f6b0e5143a4d3db9f04f00da1a4ff4;m=670dd9;t=5bc64cdc13912;x=ee44184076fc0590",
  "__MONOTONIC_TIMESTAMP": "6753753",
  "SYSLOG_FACILITY": "0",
  "_HOSTNAME": "w16",
  "PRIORITY": "5",
  "_BOOT_ID": "c0f6b0e5143a4d3db9f04f00da1a4ff4",
  "_TRANSPORT": "kernel",
  "MESSAGE": "Linux version 4.19.0-14-amd64 (debian-kernel@lists.debian.org) (gcc version 8.3.0 (Debian 8.3.0-6)) #1 SMP Debian 4.19.171-2 (2021-01-30)"
}
Run Code Online (Sandbox Code Playgroud)

使用jq您可以轻松地过滤消息:

$ journalctl -b -o json | jq '. | select(._COMM=="sensors")' | jq -r .MESSAGE | less
$ journalctl -b -o json | jq '. | select(._TRANSPORT=="kernel")' | jq -r .MESSAGE | head -n 1
Linux version 4.19.0-14-amd64 (debian-kernel@lists.debian.org) (gcc version 8.3.0 (Debian 8.3.0-6)) #1 SMP Debian 4.19.171-2 (2021-01-30)
Run Code Online (Sandbox Code Playgroud)


小智 5

目前, journalctl 不支持字段匹配中的模式或通配符。grep是您最好的选择。

我遇到了同样的问题,我认为journalctl只在NAME=VALUE作为参数传递时搜索 VALUE 的完全匹配。

我的调查:

  1. 手册页

    journalctl(1)

    匹配项的描述中未提及该模式:

     [...] A match is in the format "FIELD=VALUE", e.g.
     "_SYSTEMD_UNIT=httpd.service", referring to the components
     of a structured journal entry. [...]
    
    Run Code Online (Sandbox Code Playgroud)

    手册页-u仅在描述选项时引用一种模式。

       -u, --unit=UNIT|PATTERN
           Show messages for the specified systemd unit UNIT 
           (such as a service unit), or for any of the units
           matched by PATTERN. 
    
    Run Code Online (Sandbox Code Playgroud)
  2. 源代码

    fnmatchin函数src/journal仅在搜索单位时使用

  3. 调试日志

    启用调试输出,您可以看到模式仅在使用-u.

    $ SYSTEMD_LOG_LEVEL=debug journalctl -n1 -u gdm*
    ...
    Matched gdm.service with pattern _SYSTEMD_UNIT=gdm*
    Matched gdm.service with pattern UNIT=gdm*
    Journal filter: ((OBJECT_SYSTEMD_UNIT=gdm.service AND _UID=0) OR (UNIT=gdm.service AND _PID=1) OR (COREDUMP_UNIT=gdm.service AND _UID=0 AND MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1) OR _SYSTEMD_UNIT=gdm.service)
    ...
    
    Run Code Online (Sandbox Code Playgroud)

    所有匹配项都被视为精确匹配,包括UNIT

    $ SYSTEMD_LOG_LEVEL=debug journalctl -n1 UNIT=gdm.*
    ...
    Journal filter: UNIT=gdm*
    ...
    
    Run Code Online (Sandbox Code Playgroud)

  • 请注意,这实际上是在最后一个 systemd 版本中实现的 https://github.com/systemd/systemd/commit/6becf48ca3e03cd16d58942b7c8a99f7e49275c5 (2认同)