logrotate原生不支持hourly轮转及%y%m%d%h小时级命名,需通过cron每小时调用daily+dateext+dateformat方案或完全脚本化实现。

Logrotate 本身不支持直接使用 %Y%m%d%H 这类小时级时间格式进行日志轮转命名,因为它的 dateformat 仅在启用 dateext 且配合 daily(或更短周期)+ hourly(需 patch 或新版支持)时才生效,而标准 Logrotate(截至 v3.21)**原生不支持 hourly 轮转模式**。要实现按小时精确命名(如 app.log-2024052014),必须绕过默认限制,采用“强制每日轮转 + 外部触发”或“脚本接管”的方式。
确认 Logrotate 版本与 hourly 支持情况
运行 logrotate --version 查看版本。v3.19+ 部分发行版(如较新 Debian/Ubuntu)已合并社区补丁支持 hourly 指令,但 CentOS/RHEL 8/9 默认仍不支持。即使支持 hourly,dateformat "%Y%m%d%H" 也仅在 dateext 开启时生效,且轮转时机由 cron 控制——必须确保 cron 每小时执行一次 logrotate,而非默认每天一次。
- 检查是否识别
hourly:logrotate -d /etc/logrotate.conf 2>&1 | grep -i hourly,若无输出或报错,则不支持 - 若不支持,不要强行写
hourly,会导致配置加载失败
方案一:cron 驱动 + daily + dateformat(推荐,兼容性强)
放弃 hourly 指令,改用 daily + 每小时通过 cron 显式调用 logrotate,并利用 dateext 和 dateformat 实现小时级后缀。关键在于:每次运行都生成带当前小时的时间戳,且避免重复轮转。
- 配置中必须包含:
daily、dateext、dateformat -%Y%m%d%H、nodateext不可出现 - 添加
maxage 168(保留7天)或rotate 168控制数量,防止无限增长 - 在 crontab 中每小时执行:
0 * * * * /usr/sbin/logrotate /etc/logrotate.d/myapp - 为防同一小时内多次触发,可在配置中加
ifempty或脚本判断文件大小,但更稳妥的是确保 cron 精确每小时一次
方案二:完全脚本化归档(最灵活,彻底可控)
当需要严格按小时切分、且日志实时写入(如 systemd-journald 输出或 tail -F 场景),建议跳过 logrotate 的轮转逻辑,用 shell 脚本 + cron 每小时执行重命名:
- 假设原始日志为
/var/log/myapp/current.log,每小时将其移动为/var/log/myapp/myapp.log-2024052014 - 脚本示例:
#!/bin/bash<br> LOG_DIR="/var/log/myapp"<br> SRC="$LOG_DIR/current.log"<br> DST="$LOG_DIR/myapp.log-$(date +\%Y\%m\%d\%H)"<br> [ -s "$SRC" ] && mv "$SRC" "$DST"<br> touch "$SRC" # 创建新空文件供应用继续写入<br> # 可选:gzip "$DST"
- 配合
0 * * * * /path/to/archive-hourly.sh即可
注意事项与常见陷阱
无论采用哪种方式,以下几点极易出错:
-
dateformat中的%必须转义(在配置文件里写成\%Y\%m\%d\%H),否则 logrotate 会解析失败 - 使用
copytruncate时,小时归档可能丢失最后一小段日志(因截断发生在重命名前),高可靠场景应改用应用自身支持 reopen 或 signal 机制 - 多个进程写同一日志时,简单 mv 可能导致丢失;建议用
logger+systemd-cat或统一接入 rsyslog/filebeat 做集中切分 - 测试务必用
logrotate -vf /path/to/config观察实际行为,注意 stdout 中的 “renaming” 和 “compressing” 步骤是否含预期时间戳











