journalctl 查不到昨天的日志,是 journald 没开持久化

举报
phantomxjc 发表于 2026/10/20 08:59:04 2026/10/20
【摘要】 前阵子我一台跑在办公室的小服务半夜挂了,第二天早上九点多才有人发现。我 SSH 上去第一反应就是 journalctl u xxx.service 看日志,结果翻出来的第一条时间是今天早上八点四十——正是我重启服务的时间点。昨晚三点到早上八点那段,一条都没有。 那一刻我还以为日志被谁删了。查了一圈才发现,这事跟删日志没关系,是 journald 压根就没把日志往磁盘上写。 先确认日志到底存在哪 j

前阵子我一台跑在办公室的小服务半夜挂了,第二天早上九点多才有人发现。我 SSH 上去第一反应就是 journalctl -u xxx.service 看日志,结果翻出来的第一条时间是今天早上八点四十——正是我重启服务的时间点。昨晚三点到早上八点那段,一条都没有。

那一刻我还以为日志被谁删了。查了一圈才发现,这事跟删日志没关系,是 journald 压根就没把日志往磁盘上写。

先确认日志到底存在哪

journald 有两套存放位置:

  • /run/log/journal/ —— 在内存里(tmpfs),重启就没了
  • /var/log/journal/ —— 在磁盘上,能跨重启保留

到底用哪个,取决于 /etc/systemd/journald.conf 里的 Storage=。默认值是 auto,而 auto 的意思是:如果 /var/log/journal 这个目录存在,就存磁盘;不存在,就退回到内存。

坑就在这。Debian、Ubuntu 系默认不带 /var/log/journal 这个目录,所以默认状态下你的日志全在 /run/log/journal,每次重启自动清空。我那台机器正是这样。

验证很简单:

# 看实际用了哪种存储
journalctl --list-boots
# 只输出一条 -0(当前这次启动),说明没持久化

ls -la /var/log/journal/
# 目录不存在或者里面是空的,实锤

--list-boots 这个命令很直观。开了持久化的机器会列出一串启动记录,每次开机一行;没开的机器永远只有一行。

改成持久化:两条命令的事

不用改配置文件也能开,创建目录就行——因为 auto 的判定就是看目录在不在:

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

中间那条 systemd-tmpfiles 别省。它负责把目录的属主、权限按系统规则设好(应该是 root:systemd-journal),少了这步 journald 可能拒绝往里写,日志里会报权限问题。

不过我更推荐直接写进配置,省得哪天有人手贱删了目录又悄悄退化回内存:

sudo vim /etc/systemd/journald.conf

把 [Journal] 段里的 Storage 改成:

[Journal]
Storage=persistent

重启生效后再跑一次 journalctl --list-boots,应该能看到多条记录了。

日志能存了,还得防止它把盘吃掉

持久化的另一面是:journald 会一直写,直到占满分区。它自己有上限策略,默认是分区的 10%(且不超过 4G),对小盘机器还是有点多。我一般会显式写死:

[Journal]
Storage=persistent
SystemMaxUse=500M
SystemKeepFree=1G
MaxRetentionSec=2week
  • SystemMaxUse:日志总量上限
  • SystemKeepFree:给分区留出的余量,比 SystemMaxUse 更实用,盘小的时候会先触发
  • MaxRetentionSec:只保留最近两周

手工清理也有现成命令:

journalctl --disk-usage              # 先看占了多少
journalctl --vacuum-size=500M        # 压到 500M
journalctl --vacuum-time=7d          # 只留最近 7 天

这里有个我踩过的坑:--vacuum-* 只处理已经归档(archived)的日志文件,当前正在写的那个 active 文件清不动。所以有时明明超限了却清不下来。解决办法是先强制轮转一次,让当前文件先归档:

sudo systemctl kill --kill-who=main --signal=SIGUSR2 systemd-journald
sudo journalctl --vacuum-size=500M

实在不行就 systemctl restart systemd-journald,效果一样,只是会短暂中断日志收集。

真正查故障时,我常用的几个组合

日志留下来之后,查起来才有的可查。几个高频用法:

# 按时间窗精准切一段(半夜 3 点那次)
journalctl -u myapp.service --since "2026-10-19 02:30" --until "2026-10-19 04:00"

# 上一次启动的日志(服务挂掉后重启的场景)
journalctl -u myapp.service -b -1

# 所有启动的记录一起看
journalctl -u myapp.service -b all

# 只看错误级别
journalctl -u myapp.service -p err -b

# 去掉默认的分页器,方便管道处理
journalctl -u myapp.service --no-pager | grep -i timeout

# 看内核消息,查 OOM kill 很有用
journalctl -k --no-pager | grep -i "out of memory"

--since / --until 的时间格式挺宽松,"yesterday"、"-3h"、"2026-10-19 02:30:00" 都能认,排查时用自然语言写法最省事。

还有个容易被忽略的点:journalctl -u xxx 默认只看本次启动。很多人查历史问题直接敲这条,发现没东西就以为日志丢了,其实加个 -b -1 或 -b all 就出来了。

按进程过滤也挺好使:

journalctl _PID=1234
journalctl _COMM=python3 --since "1 hour ago"

这些下划线开头的字段叫 trusted fields,journald 会自动索引,比 grep 快得多。想知道某条日志有哪些字段可用,用 -o json-pretty 打一条出来看:

journalctl -u myapp.service -n 1 -o json-pretty

顺带说一句 Docker

如果你和我一样把服务跑在容器里,journalctl -u docker.service 只能看到 Docker 守护进程自己的日志,容器里应用输出的 stdout 是不进 journald 的——默认走的是 json-file,落在 /var/lib/docker/containers/<id>/ 下面。

想统一到 journald 里查,可以在 compose 里指定:

services:
  myapp:
    image: myapp:latest
    logging:
      driver: journald
      options:
        tag: myapp

然后就能按容器名查了:

journalctl CONTAINER_NAME=myapp -f
journalctl CONTAINER_TAG=myapp --since "-30min"

这样容器日志也能跨重启保留,还顺带解决了之前写过的 json-file 日志把系统盘写满的问题。

收个尾

现在我的新机器装机清单里多了两条:建 /var/log/journal 目录、写死 journald 的 SystemMaxUse 和 MaxRetentionSec。花不了两分钟,但省掉的是"日志呢?日志去哪了?"这种完全没头绪的十分钟。

排查故障最难受的从来不是问题难,而是证据没了。日志能留下来,问题就已经解决一半了。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。