如何用脚本自动分割日志文件?一篇指南解决日志管理难题
目录导读
- 日志分割的必要性:为什么不能忽视这个细节?
- 核心方法:三种主流脚本方案对比(Shell/Python/Logrotate)
- 实战演示:从零编写一个自动日志分割脚本
- 常见问题解答:分割后日志丢失?时间戳错误?一次说清
- 最佳实践:结合定时任务与监控告警
日志分割的必要性:为什么不能忽视这个细节?
在服务器运维中,日志文件会无节制增长,一个每天产生500MB日志的Java应用,一个月后单个文件可能超过15GB,这会导致:

- 磁盘空间耗尽:日志填满分区,服务突然崩溃
- 检索效率极低:用
grep搜索15GB文件需要数十分钟 - 备份困难:单文件过大会导致传输中断或备份失败
通过脚本自动分割日志,你可以:
- 按时间(每天/每小时)切割
- 按大小(100MB/1GB)切割
- 保留最近N份,自动删除旧日志
核心方法:三种主流脚本方案对比
以下是经过搜索引擎去伪存真后,业界最常用的三种方案:
Shell + logrotate(Linux标配,推荐)
logrotate 是系统自带工具,一条配置即可生效。
优点:成熟稳定、支持压缩、日期后缀
缺点:需系统权限,Windows不可用
配置示例(/etc/logrotate.d/myapp):
/var/log/myapp/*.log {
daily
rotate 30
compress
dateext
postrotate
systemctl restart myapp 2>/dev/null || true
endscript
}
Python脚本(灵活可控)
适合需要自定义逻辑的场景,如按业务关键字分割。
核心代码:
import os, shutil, datetime
log_file = '/var/log/app.log'
max_size = 100 * 1024 * 1024 # 100MB
backup_dir = '/backup/logs'
def rotate_log():
if os.path.getsize(log_file) > max_size:
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
shutil.move(log_file, f"{backup_dir}/app_{timestamp}.log")
open(log_file, 'w').close()
# 可结合cron每小时执行
简易Shell分割脚本(无需额外依赖)
#!/bin/bash
LOG_PATH="/var/log/nginx/access.log"
SIZE=500000000 # 500MB
if [ -f "$LOG_PATH" ] && [ $(stat -c%s "$LOG_PATH") -gt $SIZE ]; then
mv "$LOG_PATH" "${LOG_PATH}_$(date +%Y%m%d_%H%M%S)"
# 通知进程重新打开文件(如Nginx:kill -USR1 `cat /var/run/nginx.pid`)
kill -USR1 $(cat /var/run/nginx.pid)
fi
实战演示:从零编写一个自动日志分割脚本
目标:每周一凌晨3点分割,保留最近4周的日志,文件名带日期后缀。
步骤1:创建脚本文件
vim /opt/scripts/auto_split_logs.sh
步骤2:写入以下代码(已结合搜索引擎常见错误修正)
#!/bin/bash
LOG_DIR="/var/log/myproject"
RETENTION_WEEKS=4
DATE_SUFFIX=$(date +%Y%m%d)
for logfile in ${LOG_DIR}/*.log; do
if [ -f "$logfile" ]; then
# 防止重复分割(如果昨天已经分割过则跳过)
if [[ ! "$logfile" =~ ${DATE_SUFFIX} ]]; then
mv "$logfile" "${logfile}_${DATE_SUFFIX}"
# 通知服务重新打开日志(此处假设是tomcat)
kill -USR1 $(cat /var/run/tomcat.pid 2>/dev/null) 2>/dev/null
fi
fi
done
# 删除超过4周的旧日志
find ${LOG_DIR} -name "*.log_*" -type f -mtime +$((7*RETENTION_WEEKS)) -delete
步骤3:添加定时任务
crontab -e # 添加:每周一3点执行 0 3 * * 1 /bin/bash /opt/scripts/auto_split_logs.sh
关键验证点
- 执行后检查分割效果:
ls -lh /var/log/myproject/ - 确认旧日志被删除:
find /var/log/myproject/ -name "*.log_*" -mtime +28 - 服务进程是否重新打开日志:查看
/var/log/messages有无错误
常见问题解答
Q1:分割后新日志不写入?
A:常见原因是进程仍持有旧文件句柄,需要向进程发送USR1或HUP信号重启日志接口,例如Nginx:kill -USR1 $(cat /var/run/nginx.pid)。
Q2:按大小分割时,文件恰好落在边界怎么办?
A:建议使用大于上限的阈值,比如目标100MB,设置阈值为120MB,分割后生成的文件略小于100MB。
Q3:Windows环境如何实现?
A:可用PowerShell脚本,配合Task Scheduler,核心命令:Move-Item C:\logs\app.log "C:\logs\app_$(Get-Date -Format yyyyMMdd).log",然后重启服务进程。
Q4:日志内容被截断或丢失?
A:确保使用mv而非cp+rm,因为mv是原子操作,同时分割前确认应用已配置日志立即刷新(如flush),避免缓冲区滞留。
最佳实践:结合定时任务与监控告警
- 使用
logrotate原生功能:它已集成压缩(compress)、邮件告警(mail)、旧日志删除(rotate)。 - 监控分割失败:在脚本中加上退出码检查,通过Prometheus或Zabbix发告警。
if [ $? -ne 0 ]; then echo "分割失败:$(date)" | mail -s "[ALERT]日志分割异常" admin@example.com fi - 测试环境先行:先在测试服务器跑一个月,观察磁盘I/O和进程稳定性。
- 留空日志文件:分割后务必创建空文件(
touch或> file),否则某些服务(如Syslog)会报错。
通过本文的脚本方案,你可以快速实现自动化日志分割,避免因单文件过大导致的运维事故,建议优先采用系统自带的logrotate,只有需要复杂逻辑时才自写脚本,如果在生产环境部署,请先在测试环境验证信号处理和文件句柄释放逻辑。