日志越攒越多、查起来越费劲?先把 journal 与轮转规则理清楚
日志越攒越多、查起来越费劲?先把 journal 与轮转规则理清楚
磁盘报警常常不是业务数据撑爆的,而是日志。更麻烦的是另一头:真出故障要查的时候,日志要么早被删光了,要么几十个文件翻不到关键那一行。日志治理就两件事:平时别让它无限长,查的时候能按时间、按服务、按级别一下子定位。先分清手里有哪几种日志,再给每一种定规则。
一、先分清:你手里到底有几种日志
一台 Linux 服务器上,日志通常分三路,查法和管法各不相同,混在一起翻最费时间:
# 1. systemd 接管的服务日志:journal
journalctl -u <服务名> --no-pager | tail -n 100
# 2. 传统文本日志:/var/log 下的文件
ls -lh /var/log/
# 3. 应用自己写的文件日志:看应用配置里的 log 路径,别猜
grep -ri "log" /etc/<应用名>/ 2>/dev/null | head -n 20
- journal 是 systemd 收集的标准输出和标准错误,服务只要走 systemd 启动,日志就进 journal,不用应用自己写文件。
/var/log里的messages、secure、cron这类是 rsyslog/syslog 写的文件日志,系统级事件多在这里。- 应用自写的文件日志最杂:有的按天切分,有的永远写同一个文件,有的混在数据目录里。先确认它到底写到哪,再谈轮转。
先算一笔账,看看日志到底占了多少,再决定先治哪一路:
# journal 占了多少
journalctl --disk-usage
# /var/log 占了多少,排个序
du -sh /var/log/* 2>/dev/null | sort -rh | head -n 20
df -h /var /var/log 2>/dev/null
如果 /var/log 和根分区是同一个分区,日志长满就是根分区满,服务连写临时文件都写不进去——这就是 10 月 24 日那篇磁盘排查里讲过的连锁反应,日志治理首先是磁盘治理。
二、查日志:先缩范围,再翻内容
日志多的时候,tail 和 grep 全文翻是最慢的路。journalctl 的本事就是先按维度缩圈:
# 只看某个服务、某段时间、某个级别
journalctl -u <服务名> --since "2026-10-30 09:00" --until "2026-10-30 10:00" -p err --no-pager
# 只看上一次启动以来的日志,重启前后的问题用这个分界
journalctl -u <服务名> -b --no-pager | tail -n 200
# 按关键字再缩一圈(journalctl 自带 --grep,不用先管道给 grep 再丢上下文)
journalctl -u <服务名> --since "1 hour ago" --grep "timeout|oom|failed" --no-pager
-p是级别:emerg、alert、crit、err、warning、notice、info、debug。先从err起步,确认没漏再放宽到warning,一上来就看info只会被正常日志淹没。--since支持相对时间(1 hour ago、yesterday)和绝对时间,先定时间窗,再定服务,最后定级别,三个维度一缩,几十万行也能落到几十行。- 文本文件日志没有这些维度,就靠
grep+ 时间戳:先grep出异常行,再按时间前后翻上下文,别只看异常那一行本身。
一个常见误区:查不到就以为没记。先确认两件事:服务是不是走 systemd(不是的话 journal 里本来就没有它),以及日志级别是不是被应用自己调成了只记 error——级别以上的日志没写进来,事后是翻不出来的。
三、journal 的治理:先定上限,再谈清理
journal 默认的存储方式决定了它能活多久。先看当前配置,别直接上手删:
# 当前 journal 的存储与上限
grep -v "^#" /etc/systemd/journald.conf | grep -v "^$"
journalctl --disk-usage
关键的几个配置项,都在 /etc/systemd/journald.conf 里,改完要重启 systemd-journald 才生效:
[Journal]
# persistent 落盘保存,重启后还在;volatile 只放内存,重启就丢;auto 是有 /var/log/journal 目录才落盘
Storage=persistent
# journal 总量上限:超过就按时间从旧到新删,别等磁盘报警才动手
SystemMaxUse=1G
# 单个 journal 文件上限
SystemMaxFileSize=100M
# 给磁盘留的余量:journal 再多也不能把磁盘吃到这个数以下
SystemKeepFree=2G
# 最长保留时间:超过的旧日志自动清理
MaxRetentionSec=30day
SystemMaxUse和MaxRetentionSec是两道不同的闸:一个管总量,一个管时间。只设总量不设时间,低频服务的一年前日志可能还占着地方;只设时间不设总量,突发刷屏一天就能把上限顶穿。两个都设,才是“平时不操心”。- 手动清理不要直接
rm /var/log/journal/*。journal 的正确清理方式是先轮转、再按量或按时间回收:
# 先把当前正在写的文件封存,再清理,避免删到正在写的文件
journalctl --rotate
# 只保留最近 500M
journalctl --vacuum-size=500M
# 只保留最近 14 天
journalctl --vacuum-time=14d
# 只保留最近 5 个文件
journalctl --vacuum-files=5
vacuum是按时间从旧到新删,删完就找不回来了。动手之前先确认:最近一次故障的时间窗还在保留期内没有;不确定的时候,先把那段时间的日志导出来存档再清:
journalctl -u <服务名> --since "2026-10-29" --until "2026-10-30" > /tmp/<服务名>-2026-10-29.log
四、文本日志的治理:logrotate 不是“删文件”,是“换文件”
应用自写的文件日志靠 logrotate 管。先看它现在是怎么配的,再改:
# 系统全局配置与各应用的独立配置
cat /etc/logrotate.conf
ls /etc/logrotate.d/
cat /etc/logrotate.d/<应用名>
一份常见的应用日志配置,长这样:
/var/log/<应用名>/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
dateext
maxsize 100M
sharedscripts
postrotate
systemctl reload <服务名> >/dev/null 2>&1 || true
endscript
}
daily+rotate 7:每天切一次,留 7 份;dateext让切出来的文件名带日期,找某天的日志不用按序号猜。compress+delaycompress:压缩旧日志省空间,但最新切出来的那一份先不压——正在查的日志压成.gz还得先解,纯属添乱。maxsize 100M:没到一天、但文件已经 100M 了也先切,别让单个文件长到 grep 都卡。missingok+notifempty:日志文件还没生成、或是空文件的时候别报错,轮转脚本静默跳过。
最关键、也最容易配错的,是切分后怎么让应用写新文件,有两条路,只能选一条:
# 路 A:让应用重新打开日志文件(推荐,前提是应用支持 reload)
postrotate
systemctl reload <服务名> >/dev/null 2>&1 || true
endscript
# 路 B:应用不支持 reload 时,才用 copytruncate
# 把旧文件内容拷走再截断,原文件句柄不变,应用不用重启也不用 reload
copytruncate
- 路 A 是正道:reload 后应用打开新文件,旧文件彻底归档。但前提是应用真的支持 reload,不支持的服务 reload 等于没 reload,日志还会继续写旧文件。
- 路 B 是兜底:
copytruncate在拷贝和截断之间有个极短的窗口,那几行日志可能丢,而且大文件拷贝截断那一下会卡一拍。能用路 A 就别用路 B。 - 最忌讳的是直接
rm掉正在写的文件:应用还握着旧文件的句柄,磁盘空间不会释放(这就是 10 月 24 日那篇讲的“删了文件空间没回来”),新日志还继续往那个看不见的旧文件里写,表面上文件没了,磁盘照样满。
五、轮转没生效:先查它到底跑没跑
配好了轮转却没切分,先别怀疑配置,先查轮转本身跑没跑:
# logrotate 是定时任务还是 systemd timer
systemctl status logrotate.timer --no-pager
ls -l /etc/cron.daily/logrotate
# 用调试模式跑一次,看它对某个文件到底会怎么处理,不真正切分
logrotate -d /etc/logrotate.d/<应用名> 2>&1 | head -n 100
# 看上次轮转的状态记录,确认每个文件上次切分是什么时候
cat /var/lib/logrotate/logrotate.status | grep <应用名>
logrotate -d是调试模式,只打印判断过程不真正动手,配错了先在这里看明白,别直接拿生产日志试。- 常见的不生效原因就三个:配置文件语法错了(少个
}、路径写错了)、文件权限不对(logrotate 以 root 跑,但su指定的用户组不对会直接跳过)、定时任务本身没跑(timer 被停了、cron 服务没起)。 - 还有一类是“看着没切,其实是条件没到”:
daily是按天算的,rotate 7的意思是留 7 份,刚配好的第一天本来就不会立刻切出 7 份来。
六、保留多久:按用途定,别一刀切
日志不是留得越久越好,也不是越短越好,按用途分三档就够了:
- 排障用(系统与应用日志):保留 14 到 30 天。绝大多数故障的复现和定位都在这个窗口里,再久的日志查的概率极低,占的空间却一直在涨。
- 审计与安全用(登录、sudo、防火墙):保留 90 天或按合规要求。
secure、auth.log这类日志是事后追溯的证据,别跟普通应用日志一个保留期。 - 业务关键链路:按业务要求单独定,可能是 180 天,也可能要求归档到对象存储而不是留在本机。本机只留近期热数据,冷数据归档出去,别让本机磁盘替归档系统扛着。
定好之后,把规则写进配置而不是记在脑子里:journal 的上限进 journald.conf,文本日志的轮转进 /etc/logrotate.d/,保留期进同一份配置。规则只存在于某次手动清理命令里,下次换人、换机器,立刻就没人知道了。
七、排查清单(收藏版)
- 先算账:
journalctl --disk-usage和du -sh /var/log/*,确认是哪一路在长。 - 查日志先缩圈:服务 + 时间窗 + 级别,三维定下来再翻内容。
- journal 定上限:
SystemMaxUse+MaxRetentionSec两道闸都设,清理用journalctl --rotate+--vacuum-*,别直接rm。 - 文本日志走 logrotate:
daily+rotate+compress+dateext+maxsize,切分后优先reload,不支持 reload 才用copytruncate。 - 轮转没生效:先
logrotate -d调试、再查 timer/cron 和logrotate.status,别直接拿生产日志试。 - 保留期按用途分档:排障 14–30 天,审计按合规,业务冷数据归档出本机。
- 清理前先导出故障时间窗的日志存档,删完找不回来,现场没了死因就永远查不出来了。
日志治理的目标不是“磁盘永远不满”,而是“出问题时能立刻找到证据,平时又不用天天盯着它”。上限、轮转、保留期三条规则写进配置里,日志就从一个定时炸弹,变成一个随取随用的工具。
- 点赞
- 收藏
- 关注作者
评论(0)