logrotate中size和daily是“或”关系,任一满足即触发轮转:size提供实时弹性响应,daily作为保底节奏;二者共存但不协同,且size优先级高于daily。

logrotate 配置中 size 和 daily 同时生效的逻辑是什么
logrotate 默认不支持「日志大小超限或时间到期任一满足就切割」,而是按配置顺序优先级执行:如果同时声明 daily 和 size,logrotate 会先检查是否满足 size 条件(当日任意时刻只要文件 ≥ 指定值就触发),再检查 daily(仅在每天首次运行且未因 size 触发过时才判断日期)。也就是说,size 是即时触发的,daily 是兜底机制。
常见误解是以为两者是“或”关系且独立轮询——实际 logrotate 每次运行只做一次判断,不会因为没到时间就不看大小,也不会因为没超大小就跳过日期检查。
-
size单位必须带后缀:100M合法,100MB或104857600不合法 - 若同时启用
daily和size,需确保dateext开启,否则同一天内多次因 size 触发切割会导致文件名冲突(如app.log.1被反复覆盖) - logrotate 默认每天只运行一次(通过 cron 调用),所以「时间阈值」本质是「最近一次运行距今是否满 24 小时」,不是严格按 00:00 切割
如何让 logrotate 真正实现「任一条件满足即切割」
原生 logrotate 不提供 OR 语义,但可通过组合配置 + 外部脚本绕过限制。核心思路是:禁用内置时间判断,改用 shell 脚本主动检查两个条件,并调用 logrotate 的 --force 或指定配置片段。
例如,在 crontab 中每 30 分钟执行一次检查脚本:
#!/bin/bash LOGFILE="/var/log/app/app.log" THRESHOLD_SIZE=50000000 # 50MB THRESHOLD_AGE=86400 # 24h <p>if [ $(stat -c "%s" "$LOGFILE" 2>/dev/null || echo 0) -ge $THRESHOLD_SIZE ] || \ [ $(find "$LOGFILE" -mmin +1440 2>/dev/null | wc -l) -eq 1 ]; then /usr/sbin/logrotate -f /etc/logrotate.d/app-force fi</p>
- 注意
stat -c "%s"在部分 Alpine 等精简系统中不可用,可换为du -b "$LOGFILE" | cut -f1 -
find ... -mmin +1440判断修改时间是否超过 1440 分钟,比date计算更可靠(避免时区/夏令时干扰) -
/etc/logrotate.d/app-force应去掉所有时间相关指令(如daily、weekly),只保留rotate、compress、copytruncate等动作指令
systemd-journald 是否能替代?它对双阈值的支持怎样
systemd-journald 本身不管理外部日志文件,但如果你的日志由 systemd 服务输出(即用 journalctl 查看),它原生支持按大小和时间双重滚动:SystemMaxUse=、MaxFileSec=、MaxRetentionSec= 可共存,且行为是「任一触发即清理旧条目」。
不过这仅适用于 journal 日志,不能直接切割 /var/log/app/*.log 这类传统文件。若想统一管理,需将应用日志重定向进 journal(如用 logger 或 stdout 输出),再禁用应用自身文件写入。
-
MaxFileSec=1day控制单个 journal 文件最长存活时间,MaxRetentionSec=30day控制整体日志保留上限,二者叠加效果接近双阈值 - journal 文件实际大小还受
SystemMaxUse=和SystemMaxFileSize=限制,它们之间是 AND 关系(必须同时满足才清理) - journalctl 查询时无法像 logrotate 那样自动按业务维度切分文件,归档和压缩需额外脚本配合
容易被忽略的权限与原子性问题
无论用 logrotate 还是自定义脚本,当应用持续写入日志时,切割操作可能破坏原子性:mv 或 copytruncate 若未同步,会导致部分日志丢失或重复。
- 务必在 logrotate 配置中启用
copytruncate(而非仅create),尤其对无法重开文件句柄的老旧进程 - 若使用
postrotate脚本通知服务 reload,注意信号发送时机:应在copytruncate完成后,且要加 sleep 100ms 避免 race condition - logrotate 运行用户(通常是 root)必须对日志目录有读写权,但某些容器环境里
/var/log/app属于非 root 用户,此时需用su指令切换上下文,不能只靠create参数设权限
真正麻烦的从来不是配两个参数,而是确认日志写入方是否支持 copytruncate、确认 cron 时间精度是否够用、以及验证切割后第一条新日志是否真的从头开始写——这些都得实测,光看配置没用。


















