Skip to content

journalctl 日志 ​

systemd 把服务日志收进 journald,好处是统一时间轴、结构化字段、按服务过滤。坏处是默认只在内存里,重启就没了。

场景 ​

服务起不来、行为异常、想按时间段查日志。journalctl 比在 /var/log 里翻文件快得多。

一、基本用法 ​

bash
journalctl -u order-api -n 100 --no-pager
journalctl -u order-api -f
journalctl -u order-api --since '10 min ago'
text
Oct 27 22:11:02 kafka-1 systemd[1]: Started Order API.
Oct 27 22:11:03 kafka-1 java[33120]: 2026-10-27 22:11:03.114 INFO  Started in 8.2s
Oct 27 22:14:31 kafka-1 java[33120]: 2026-10-27 22:14:31.882 ERROR Failed to fetch order 88213

三个高频组合:

bash
# 跟随 + 只看错误
journalctl -u order-api -f -p err

# 指定时间段
journalctl -u order-api --since '2026-10-27 21:00:00' --until '2026-10-27 22:00:00'

# 本次启动以来
journalctl -u order-api -b

二、过滤参数 ​

参数作用
-u <unit>指定服务
-f跟随
-n N最近 N 行
--since / --until时间范围
-p <级别>优先级过滤
-b / -b -1本次 / 上次启动
-k只看内核日志(等价 dmesg)
-t <标识>按 syslog identifier
_PID=<pid>按进程号
-o <格式>输出格式

优先级从高到低:

text
emerg(0) alert(1) crit(2) err(3) warning(4) notice(5) info(6) debug(7)

-p err 表示 err 及以上(0~3)。

输出格式 ​

bash
journalctl -u order-api -o cat -n 5
text
2026-10-27 22:11:03.114 INFO  Started in 8.2s
2026-10-27 22:14:31.882 ERROR Failed to fetch order 88213
格式用途
short(默认)时间 + 主机 + 标识 + 消息
cat只有消息(脚本里用)
json / json-pretty结构化,含所有字段
verbose所有字段平铺
with-unit带 unit 前缀
bash
journalctl -u order-api -o json-pretty -n 1
json
{
  "__CURSOR": "s=8f2c1e9a...",
  "__REALTIME_TIMESTAMP": "1761570290314000",
  "_PID": "33120",
  "_UID": "10001",
  "_SYSTEMD_UNIT": "order-api.service",
  "PRIORITY": "3",
  "MESSAGE": "Failed to fetch order 88213",
  "_BOOT_ID": "3d41b7c0..."
}

PRIORITY 是数字优先级,_SYSTEMD_UNIT 是所属服务。

三、时间表达式的时区坑 ​

bash
date
journalctl --since '10 min ago'

--since 用的是本机时区。如果日志来自容器(容器内是 UTC),你会看到时间戳差 8 小时。

两种情况要分清:

  1. journald 记录的时间始终带时区,用 --since 按本机时区过滤是对的。
  2. 应用自己打印的时间可能是 UTC(容器没设 TZ),看起来"晚 8 小时"。

排查时加 -o short-iso 看带时区的完整时间:

bash
journalctl -u order-api -o short-iso -n 3
text
2026-10-27T22:14:31+0800 kafka-1 java[33120]: 2026-10-27 14:14:31.882 ERROR ...

一眼就能看出应用打的是 UTC。

四、持久化:重启后还在吗 ​

默认情况下(/var/log/journal 不存在),journald 只写到 /run/log/journal,重启就清空。

bash
ls -d /var/log/journal 2>/dev/null || echo "未持久化"
journalctl --disk-usage
text
Archived and active journals take up 248.0M in the file system.

开启持久化:

bash
mkdir -p /var/log/journal
systemd-tmpfiles --create --prefix /var/log/journal
systemctl restart systemd-journald
ini
# /etc/systemd/journald.conf
Storage=persistent
SystemMaxUse=4G
SystemMaxFileSize=200M
MaxRetentionSec=30day
bash
systemctl restart systemd-journald
journalctl --disk-usage

日志量大的机器要限容

SystemMaxUse 不设时默认是文件系统的 10%。500G 盘就是 50G 日志。生产上显式设成 2~4G,并配 MaxRetentionSec。

清理:

bash
journalctl --vacuum-size=1G
journalctl --vacuum-time=7d
text
Deleted archived journal /var/log/journal/.../system@0005f2c1.journal (200.0M).
Vacuuming done, freed 1.2G of archived journals from /var/log/journal.

--vacuum-* 只删已归档的文件,当前正在写的那个不会删。

五、和 rsyslog 的关系 ​

很多发行版同时装了 systemd-journald 和 rsyslog:

  • journald 收 stdout/stderr 和内核日志。
  • rsyslog 从 journald 转发到 /var/log/messages、/var/log/secure。

所以同一个事件在两个地方都有。查传统日志文件:

bash
tail -f /var/log/messages
grep -i 'failed' /var/log/secure

两者都装时,journald.conf 里的 ForwardToSyslog=yes 决定是否转发。

六、结构化查询 ​

bash
# 按可执行文件名
journalctl /usr/local/jdk-17/bin/java -n 20

# 按 PID
journalctl _PID=33120 -n 20

# 列出所有字段
journalctl -u order-api -o verbose -n 1 | head -30

# 按字段值过滤
journalctl _SYSTEMD_UNIT=order-api.service PRIORITY=3 -n 20

查内核层面的 OOM:

bash
journalctl -k --since '1 hour ago' | grep -i -E 'oom|killed process'
text
Oct 27 21:31:02 kafka-1 kernel: Memory cgroup out of memory: Killed process 31882 (java)

七、配合 grep 使用 ​

bash
journalctl -u order-api --since today -o cat | grep -i -E 'error|exception' | tail -30

注意 journalctl ... | grep 是先取全部再过滤,日志量大时会慢。能用 -p err 或字段过滤就别用 grep。

bash
# 好:让 journald 过滤
journalctl -u order-api -p err --since today -o cat

# 差:全量输出再 grep
journalctl -u order-api --since today | grep ERROR

八、常见场景 ​

服务启动失败 ​

bash
systemctl status order-api --no-pager
journalctl -u order-api -b -n 80 --no-pager

看 Failed to start 前后的几行,通常是 ExecStart 路径、权限、端口占用。

查某次重启前发生了什么 ​

bash
journalctl -b -1 -p warning -n 100

-b -1 是上一次启动(即崩溃那次)。

追踪某个请求 ​

bash
journalctl -u order-api -f -o cat | grep '88213'

九、踩过的坑 ​

现象根因处置
重启后日志没了没开持久化建 /var/log/journal + Storage=persistent
journalctl 输出为空应用写文件不写 stdout看应用日志路径
时间差 8 小时容器 UTC / 应用打 UTC设 TZ,用 -o short-iso 看
磁盘被日志占满SystemMaxUse 太大或没设journalctl --vacuum-size
--since '10 min ago' 查不到时区或格式用绝对时间 --since '2026-10-27 21:00:00'
-p err 查不到 ERROR应用日志没带优先级,都算 info用 grep ERROR 或改应用日志级别映射
-u 找不到服务unit 名不对systemctl list-units | grep xxx
输出被分页卡住脚本里没 --no-pager加 --no-pager