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