深入理解journalctl日志分析利器:生产级别十大用法总结及实践

2024-01-03 16:38:49 浏览数 (1)

一、前言

上一篇对于journalctl的扫盲篇幅过于冗长,对每个参数基本都细致入微讲解剖析,更像是一本厚重的“工具书”。生产上很少用到其中的大部分参数,所以也被催更对journalctl的一些常见用法和使用场景进行汇总,承蒙呼声之高,权当对前文的延续和回应。无论你是初学者还是经验丰富的技术专家,本文都将为你提供有价值的信息和见解。

二、用法汇总

1.基于boot引导筛选日志

首先可通过--list-boots参数列出当前系统所有的boot引导:

代码语言:shell复制
journalctl --list-boots

最左边的IDX列为序列号,0表示当前BOOT引导ID,-1表示上一次引导ID,以此类推,右边两列则为每个BOOT引导的时间范围,每次重启系统后都会生成一个新的BOOT ID。

明白此概念后,比如想筛选上一次引导所产生的错误日志,可以是:

代码语言:shell复制
journalctl -b -1  -g "fail|error"

-n 30 显示最近30条日志,不加则显示全部。

或者通过日志定义的优先级来筛选上一次启动期间0-3级(emerge、alert、crit、error)的错误日志:

代码语言:shell复制
journalctl -b -1 -p 0..3

2.指定时间范围筛选特定服务的日志

筛选特定systemd服务,使用-u参数,比如-u "sshd"筛选sshd服务的日志。

指定时间范围,则通过--since(-S)--until(-U)参数实现。

时间格式为标准的年月日时分秒(YYYY-MM-DD HH:MM:SS):“2023-06-09 18:00:00”,当然你也可以简写为"yesterday"、"today"、"tomorrow"

筛选从昨天开始到现在的sshd服务日志

代码语言:shell复制
journalctl -u sshd --since yesterday

当缺省"--unitl(-U)"时,则表示当前时间。

筛选2023年5月1号到5月31号的sshd服务日志并显示最近20条记录

代码语言:shell复制
journalctl -u sshd --since "2023-05-01" --until "2023-5-31" -n 20

3.使用正则表达式过滤特定日志

当日志数量庞大时,我们只想过滤特定符合条件内容的日志,此时--grep(-g)参数就派上了用场;journalctl的日志由很多字段组成,其中日志信息内容会记录到MESSAGE字段,-g参数的作用域也是这个字段,并支持Perl正则写法,具体语法可以通过man pcre2pattern来查看。

同时需要注意,如果写的表达式都是小写,那就不区分大小写,如果包含大写就会区分大小写,如果不想区分大小写可以使用--case-sensitive=false参数来生效,比如下面的几种情况:

  • --grep "abc",是不区分大小写的;
  • --grep "Abc",区分大小写,只过滤匹配Abc的日志;
  • --grep "Abc" --case-sensitive=false,仍然不区分大小写。

筛选sshd服务登录失败的日志并显示最近30条:

代码语言:shell复制
journalctl -u sshd --grep "Failed" -n 30

从上图可以观察到,如果日志跨了BOOT ID,会把对应的BOOT ID也展示出来。

筛选prometheus服务的master节点最近五行的错误日志,且不允许分页:

代码语言:shell复制
journalctl -u prometheus -g '(?i)Web master node.*error' -n 5 --no-pager

4.实时跟踪特定服务的日志

journalctl提供了-f(--follow)参数来追踪日志,可实时输出所产生的日志。

跟踪sshd服务从现在开始所产生的日志:

代码语言:shell复制
journalctl -u sshd -S now -f

跟踪grafana服务产生的日志,并显示最近10行已经存储的日志:

代码语言:shell复制
journalctl -u grafana -f

当不加-S now参数时,默认会把最近已产生的10行日志输出出来再进行实时跟踪,如果你想打印已经存储的所有行日志再进行追踪,加上--no-tail参数即可:

代码语言:shell复制
journalctl -u grafana -f --no-tail

5.筛选与内核相关的错误日志

--demgs或者-k参数j将会打印内核相关日志:

代码语言:shell复制
journalctl -k

而只想看到有没有错误日志,可以通过-p来指定日志优先级,比如输出错误级别为0-3级(emerge、alert、crit、error)的日志

代码语言:shell复制
jouornalctl -k -p 0..3

默认只会显示本次系统从启动到现在所产生的内核日志,如果想看到上一次的内核日志,则可以加上-b -1参数,比如想要查看上一次从开机到关机(boot为-1)所产生的内核日志,且级别为0-4级(emerge、alert、crit、erro、warning)

代码语言:shell复制
journalctl -k -p 0..4 -b -1

或者我想通过MESSAGE字段的内容来匹配满足我需要的内核日志

代码语言:shell复制
journalctl -k -g "fail|error|bug|out of memory" -b -1 -n -r

-n(--lines)不指定数字默认只显示最近10行,-r(--reverse)反向显示,从近到远。

6.筛选与身份验证相关的日志

systemd-journald会按照不同设备对日志分门别类,最常见的设备有:

  • kernel:内核产生的日志消息。
  • user:与用户操作和登录相关的日志消息。
  • mail:与邮件系统相关的日志消息。
  • auth:与身份验证和授权相关的日志消息。
  • syslog:由 syslog 守护程序生成的日志消息。
  • lpr:与打印系统相关的日志消息。
  • news:与新闻服务器相关的日志消息。
  • uucp:与 UUCP(Unix to Unix Copy)系统相关的日志消息。
  • cron:与定时任务(cron)相关的日志消息。
  • authpriv:与身份验证和授权的私有信息相关的日志消息。
  • ftp:与文件传输协议(FTP)服务器相关的日志消息。
  • ntp:与网络时间协议(NTP)服务器相关的日志消息。

然后通过--facility参数来指定设备模块所产生的日志,比如想筛选与身份验证相关的日志最近30行

代码语言:shell复制
journalctl --facility=auth -n 30

筛选与身份验证和授权的私有信息相关的日志最近20行:

代码语言:shell复制
journalctl --facility=authpriv -n 20

这里能详细打印出pam模块的验证过程。

筛选auth模块并且指定sshd标识符,且关键词为fail|invalid|error|timeout的日志最近30行

代码语言:shell复制
journalctl --facility=auth -t sshd -g "fail|invalid|error|timeout" -n 30

从日志可以看出,攻击者IP:143.42.56.115 在尝试多次登录服务器并用户名密码错误后,00:14:56开始的所有登录请求全部超时,因为00:12:59这个时间点已经被fail2ban给屏蔽了:

如果你对fail2ban比较感兴趣,可以参照我写的这篇。

7.以json格式输出日志

journalctl提供了格式化输出选项,除了json还支持short、verbose等,如果你想了解更多的输出格式,可以参照我这篇。

通过-o(--output)参数来指定输出格式,还是拿上一条举例,筛选auth模块并且指定sshd标识符,且关键词为fail|invalid|error|timeout的日志最近20行,但是以json格式输出

代码语言:shell复制
journalctl --facility=auth -t sshd -g "fail|invalid|error|timeout" -n 20 -o json

这么看不太直观,通过json-pretty参数可有优化输出:

代码语言:shell复制
journalctl --facility=auth -t sshd -g "fail|invalid|error|timeout" -n 1 -o json-pretty

8.根据进程PID过滤日志

当某个服务报错时,我们想通过进程PID来过滤出相关错误日志:

代码语言:shell复制
journalctl -n _PID=<PID> -b 0

-n只显示最近10行,-b 0只显示本次系统启动到目前为止的日志。

通过systemctl查看服务状态,可以看到失败时的PID,即使这个服务并没有运行成功,systemd-journald也会将记录存储到_PID字段,因此当服务并没有正常运行时,你通过lsof、netstat、pidof、ps诸如此类的命令是查不到PID的,不要觉得奇怪,因为它们只能查当前正在运行的进程PID,而systemd会记录进程的PID,不管服务是否正常。

我们不妨通过verbose或json格式来输出,这样你应该能清晰认识到为什么能够通过_PID字段来过滤日志:

代码语言:shell复制
journalctl -n _PID=75192 -b 0 -o verbose
journalctl -n _PID=75192 -b 0 -o json-pretty

很明显,完整的日志会存储到不同的字段,每个字段分工明确。不用怀疑,上面的字段你都可以拿来单独作为过滤条件或者组合使用都是没问题的。

比如指定_PID的情况下同时指定_SYSTEMD_UNIT字段

代码语言:shell复制
journalctl -n _PID=75192 _SYSTEMD_UNIT=nginx.service -o verbose
journalctl -n _PID=75192 _SYSTEMD_UNIT=nginx.service -o json-pretty

过滤条件越多日志越精准越具备唯一性。

当然你也可以通过-u参数来跟踪特定服务的日志:

代码语言:shell复制
journalctl -u nginx.service -n

9.禁止截断输出和截断输出

默认情况下,当日志过长,journalctl会截断输出,比如以下这条命令,显示身份验证模块的日志最近10行:

代码语言:shell复制
journalctl --facility=auth -t audit -g SER_AUTH -n

可以看到每一行末尾都用">"字符截断了,看不到完整内容,此时我们加上--no-pager参数即可:

代码语言:shell复制
journalctl --facility=auth -t audit -g SER_AUTH -n --no-pager

当然,如果你想省略中间内容,不需要完全显示,可以使用--no-full参数,journalctl会用"…"省略这部分内容:

--no-full的意思是如果日志信息太长,需要另起一行,则不显示所有,截断输出中间部分。

10.汇总统计日志字段出现次数

当使用一些组合命令时,可以轻松统计我们想要的字段出现的次数。

比如统计今天的错误日志(MESSAGE字段包含:fail|error|fatal的日志),汇总输出为对应的二进制命令的次数:

代码语言:shell复制
journalctl --no-pager --since today -g 'fail|error|fatal' -o json | jq '._EXE' | sort | uniq -c | sort -nr -k 1

把时间限定去掉:

代码语言:shell复制
journalctl --no-pager -g 'fail|error|fatal' -o json | jq '._EXE' | sort | uniq -c | sort -nr -k 1

可以看到其中第二行为null,情况有以下几种:

  • 系统日志记录的事件没有与特定的可执行文件关联;
  • 可执行文件的信息不可用(比如该文件已被删除或信息丢失);
  • 内核本身产生的日志,不需要与任何可执行文件关联。

上面是根据_EXE字段来统计汇总,那么其它字段也是同理,比如统计错误日志出现次数,并按照服务字段(_SYSTEMD_UNIT)汇总次数,取TOP 25行

代码语言:shell复制
journalctl --no-pager -g 'fail|error|fatal' -o json | jq '._SYSTEMD_UNIT' | sort | uniq -c | sort -nr -k 1 |head -n 25

各个字段含义可通过 man 7 systemd.journal-fields 获取。

又或者,按照系统日志消息存储的类别(_TRANSPORT)来统计

代码语言:shell复制
journalctl --no-pager -o json | jq '._TRANSPORT' | sort | uniq -c | sort -nr -k 1 # 统计范围为所有。
journalctl --no-pager -g 'fail|error|fatal' -o json | jq '._TRANSPORT' | sort | uniq -c | sort -nr -k 1 # 统计范围为匹配fail|error|fatal的日志。
  • stdout:表示消息通过标准输出(stdout)传输,通常是由应用程序直接打印到控制台或输出到文件中。
  • journal:表示消息通过本地套接字传输,由 systemd-journald 接收和处理。这是默认的传输方式,系统日志消息被写入到系统日志文件(通常位于 /var/log/journal/ 目录下)。
  • syslog:表示消息通过 syslog 协议传输,由 rsyslog 或其他类似的日志服务接收和处理。这种传输方式允许将日志消息发送到远程服务器或进行其他配置和处理。
  • journal console:表示消息同时通过本地套接字和标准输出传输,消息会同时被写入到系统日志和控制台。
  • journal syslog:表示消息同时通过本地套接字和 syslog 协议传输,消息会同时被写入到系统日志和 syslog

三、总结

通过本文,我们详细介绍了journalctl工具的用法和应用场景。作为一名系统管理员或开发人员,掌握journalctl的使用技巧对于有效管理和分析系统日志至关重要。

从前面的示例不难看出,journalctl是一个功能强大且灵活的命令行工具,它提供了多种过滤和排序选项,能够快速定位和解决问题。我们学习了如何按时间、进程和日志级别等方式过滤日志,并提到了使用正则表达式过滤日志、相关身份验证模块的介绍和使用、以及汇总统计日志字段的用法,我们还介绍了journalctl的实用功能,包括实时监视、高级搜索和过滤。通过使用日志标识符和元数据,我们能够更精确地定位特定事件,并深入分析应用程序的活动,每个场景拿来用于生产环境都是没有任何问题的。

掌握journalctl带来了许多价值和效益。它不仅能够帮助我们快速诊断故障和进行性能优化,还能用于安全审计和系统稳定性的维护。通过减少故障排除时间,提高工作效率,我们可以提升整个系统的可靠性和可用性。

同时也强烈建议深入学习journalctl的更多功能和用法。可参阅官方文档或者我的另一篇文章,探索更多高级特性和实践案例。

附带PDF版本:

深入理解journalctl日志分析利器:生产级别十大用法总结及实践.pdff

0 人点赞