使用logrotate通过prerotate脚本批量处理Ansible日志的问题
解决Ansible日志按月份合并压缩的logrotate配置问题
核心问题分析
你要处理的是带时间戳的离散日志文件,但logrotate默认逻辑是针对持续写入的单一日志文件。之前的prerotate脚本没生效,大概率是脚本逻辑没匹配到正确的日志文件;移除后显示轮转却找不到压缩文件,是因为logrotate对已不再写入的旧日志,默认只会标记处理,不会自动合并压缩——除非你明确指定合并规则。
正确配置方案
1. 先搞定目录权限
logrotate默认以root身份运行,先确保目录权限没问题:
chown root:root /var/log/ansible /var/log/ansible/archive chmod 755 /var/log/ansible /var/log/ansible/archive
2. 编写专属logrotate配置
创建/etc/logrotate.d/ansible配置文件,内容如下:
/var/log/ansible/ansible-*.log { monthly rotate 0 olddir /var/log/ansible/archive compress delaycompress missingok notifempty prerotate # 把1个月以上的日志按年月分类到归档子目录(假设日志名是ansible-YYYYMMDD.log格式) find /var/log/ansible -name "ansible-*.log" -mtime +30 | while read logfile; do # 从文件名里提取年月部分 log_date=$(echo $logfile | sed -n 's/.*ansible-\([0-9]\{6\}\)[0-9]\{2\}\.log/\1/p') if [ ! -z "$log_date" ]; then mkdir -p /var/log/ansible/archive/$log_date mv $logfile /var/log/ansible/archive/$log_date/ fi done endscript postrotate # 把归档目录里的月度日志合并压缩成单个文件 for month_dir in $(ls -d /var/log/ansible/archive/20* 2>/dev/null | sort); do month=$(basename $month_dir) cat $month_dir/*.log | gzip > /var/log/ansible/archive/ansible-$month.gz rm -f $month_dir/*.log rmdir $month_dir 2>/dev/null done endscript }
3. 关键配置说明
monthly:每月执行一次轮转操作rotate 0:不保留原日志的轮转版本,因为我们已经在prerotate里完成了文件转移compress/delaycompress:延迟压缩,确保文件彻底停止写入后再压缩prerotate:把30天以上的日志按年月创建子目录分类,为后续合并做准备postrotate:将每个月度子目录里的零散日志合并成单个压缩文件,清理原文件和空目录
4. 手动测试验证
执行下面的命令强制运行logrotate,加-v看详细输出,方便排查问题:
logrotate -v -f /etc/logrotate.d/ansible
执行完后去/var/log/ansible/archive目录检查,应该能看到类似ansible-202405.gz的月度压缩文件。
常见坑点排查
- 文件名格式匹配:如果你的日志文件名不是
ansible-YYYYMMDD.log,要调整prerotate里的sed规则,确保能正确提取年月信息 - 权限问题:如果logrotate无法访问日志目录或归档目录,会导致文件移动、压缩失败,务必确认权限设置正确
- 空日志处理:
missingok和notifempty参数能避免因为没有符合条件的日志而报错中断 - 强制测试:日常logrotate会按周期自动执行,测试时一定要加
-f强制触发,不然可能看不到效果
内容的提问来源于stack exchange,提问作者andrew
相关产品推荐
相关产品推荐

