journalctl —— systemd 统一日志

运维工具手册 05-服务与计划任务 6.1 KB 原文

journalctl —— systemd 统一日志

分类:05 服务与计划任务 适用:systemd 系统(journald) 一句话:服务日志、内核日志、启动日志统一入口,带结构化字段和精确时间过滤。

1. 它解决什么问题

  • 服务为什么起不来,日志一行行看。
  • 昨天 14:00 到 15:00 之间系统发生了什么。
  • 内核 OOM、磁盘错误、硬件告警。
  • 上一次启动时的日志(当前已经重启过)。

2. 基础

journalctl                      # 全部日志(从旧到新,进入分页器)
journalctl -n 100               # 最近 100 行
journalctl -f                   # 实时跟踪(类似 tail -f)
journalctl -r                   # 倒序(最新在前)
journalctl --no-pager           # 不分页,便于管道
journalctl -e                   # 直接跳到末尾

--no-pager 几乎总要加,否则输出会进入 less,脚本和管道会"卡住"。

3. 按服务看(最常用)

journalctl -u nginx                       # 某服务全部
journalctl -u nginx -n 200                # 最近 200 行
journalctl -u nginx -f                    # 实时
journalctl -u nginx --since today
journalctl -u nginx --since '2026-11-05 14:00' --until '2026-11-05 15:00'
journalctl -u nginx -p err                # 只看错误及以上
journalctl -u nginx -b                    # 本次启动以来
journalctl -u nginx -b -1                 # 上一次启动
journalctl -u nginx --since '-30 min' --no-pager

4. 时间过滤

--since today
--since yesterday
--since '2026-11-05'
--since '2026-11-05 14:00:00'
--since '30 min ago'
--since '-1h'
--until '2026-11-05 15:00'
--since '2026-11-05 14:00' --until '2026-11-05 14:10'

时间格式很宽松,YYYY-MM-DD HH:MM:SS、today、-2h、1 hour ago 都行。系统时区取决于 timedatectl 设置。

5. 优先级过滤

journalctl -p err              # err 及以上(0-3)
journalctl -p warning          # warning 及以上
journalctl -p 3                # 数字形式

级别:0 emerg、1 alert、2 crit、3 err、4 warning、5 notice、6 info、7 debug。

-p 是"及以上",-p info 会输出所有级别(等于不过滤),容易误解。

6. 启动与内核

journalctl -b                  # 本次启动
journalctl -b -1               # 上次启动
journalctl -b -2               # 上上次
journalctl --list-boots       # 启动记录列表
journalctl -k                  # 仅内核消息(等同 dmesg)
journalctl -k -b -1            # 上次启动的内核日志
journalctl -k -p err           # 内核错误

--list-boots 的输出:

-2 8f3a... Thu 2026-11-03 09:00:01 CST—Thu 2026-11-03 18:20:11 CST
-1 2b1c... Thu 2026-11-04 08:55:12 CST—Fri 2026-11-04 22:10:44 CST
 0 9d4e... Thu 2026-11-05 09:00:00 CST—Thu 2026-11-05 10:30:00 CST

排查"机器为什么重启",-b -1 的尾部是关键证据。

7. 输出格式

journalctl -o short              # 默认
journalctl -o short-iso          # ISO8601 时间,含时区
journalctl -o short-precise      # 微秒精度
journalctl -o json-pretty        # 结构化,字段全
journalctl -o json               # 每行一个 JSON(供 jq)
journalctl -o cat                # 只有消息,无元数据
journalctl -o verbose            # 所有字段

结构化输出配合 jq:

journalctl -u app -o json --since '-1h' \
  | jq -r 'select(.PRIORITY == "3") | "\(.__REALTIME_TIMESTAMP) \(.MESSAGE)"'

8. 高级过滤

journalctl _PID=1234                  # 按 PID
journalctl _COMM=nginx                # 按进程名
journalctl _UID=1000                  # 按用户
journalctl -t sshd                    # 按 syslog tag
journalctl -g 'timeout|refused'       # 按消息内容(正则,需 systemd 237+)
journalctl -F _COMM                   # 列出所有出现过的进程名
journalctl -F _SYSTEMD_UNIT           # 列出所有单元
journalctl --user-unit=myapp          # 用户级服务
journalctl --user                     # 当前用户的所有日志
journalctl -u a -u b                  # 多个单元(OR)
journalctl -u a + _PID=1              # `+` 表示 OR 分组

9. 磁盘占用与清理

journalctl --disk-usage                       # 当前占用
journalctl --vacuum-size=500M                 # 保留最近 500M
journalctl --vacuum-time=7d                   # 保留 7 天
journalctl --vacuum-files=5                   # 保留 5 个归档文件

持久化配置 /etc/systemd/journald.conf:

[Journal]
Storage=persistent          # 持久化到 /var/log/journal(默认 auto)
SystemMaxUse=2G             # 系统日志总上限
SystemKeepFree=1G           # 至少保留的磁盘空间
SystemMaxFileSize=200M      # 单文件上限
MaxRetentionSec=30day       # 最长保留
Compress=yes

改完 systemctl restart systemd-journald。

Storage 取值:

值 行为
volatile 只写 /run/log/journal,重启即丢
persistent 写 /var/log/journal,重启保留
auto 目录存在则持久化,否则易失(多数发行版默认)
none 不存储,仅转发

手动创建持久化目录:

mkdir -p /var/log/journal
systemd-tmpfiles --create --prefix /var/log/journal
systemctl restart systemd-journald

10. 实战场景

10.1 服务启动失败取证

systemctl status app --no-pager -l
journalctl -u app -b --no-pager | tail -50
journalctl -u app -p err -b --no-pager

10.2 排查 OOM

journalctl -k -g 'Out of memory|oom-kill|Killed process' --no-pager
dmesg -T | grep -i -E 'oom|killed process'

输出会给出被杀的进程名、PID、占用内存,是定位"服务莫名消失"的关键。

10.3 复盘重启原因

journalctl --list-boots
journalctl -b -1 -p warning --no-pager | tail -80
journalctl -b -1 -k --no-pager | tail -50
last -x | head -20        # 谁登录/重启过

10.4 导出某时段日志给厂商

journalctl --since '2026-11-05 14:00' --until '2026-11-05 15:00' \
  -o short-iso --no-pager > /tmp/log-20261105-1400.txt

带 ISO 时间戳,方便与其他系统日志对齐。

10.5 跟日志同时抓现场

journalctl -u app -f -o cat &
# 复现问题后
kill %1

11. 常见坑

  1. 不加 --no-pager 会进 less:脚本/管道场景必加。
  2. -p 是"及以上":-p info 等于全量。
  3. 默认存储是易失的:Storage=auto 且 /var/log/journal 不存在时,重启日志就没了,事后无法复盘。
  4. 日志不落 /var/log/messages:systemd 系统里 rsyslog 可能未装,传统路径没内容,别以为没日志。
  5. -u 只匹配 unit 名:通过脚本直接跑的进程日志不在该 unit 下,用 _COMM 或 _PID。
  6. 容器内 journald 不可用:容器通常没有 journald,日志走 stdout,用 docker logs/kubectl logs。
  7. 时间过滤受时区影响:--since today 按系统本地时区,跨时区协作要写绝对时间+时区。
  8. -b -1 需要日志持久化:易失模式下没有历史启动记录。
  9. --vacuum-size 不会立即释放 inode:极端碎片场景需 --rotate 后再 vacuum。
  10. -g 需要 systemd 237+:老版本(CentOS 7 的 219)不支持,用 | grep。
  11. 日志重复:rsyslog 与 journald 同时收,可能看到两份,属正常。
  12. Rate limit 丢日志:短时间大量输出会被限流,journalctl 里会提示 Suppressed N messages,调 RateLimitBurst/RateLimitIntervalSec。

12. 速查表

journalctl -u <svc> -n 100 --no-pager
journalctl -u <svc> -f
journalctl -u <svc> --since '2026-11-05 14:00' --until '2026-11-05 15:00'
journalctl -u <svc> -p err -b
journalctl -b -1                        # 上次启动
journalctl --list-boots
journalctl -k -g 'oom|Out of memory'
journalctl -o json-pretty -n 1
journalctl -o cat -u <svc>
journalctl _PID=1234
journalctl -g 'timeout'
journalctl --disk-usage
journalctl --vacuum-time=7d
journalctl --vacuum-size=500M
journalctl --verify