从零到自动化运维的完整指南
📑 目录导读
- 为什么需要日志压缩归档? – 问题分析与价值
- 脚本设计核心原则 – 可靠、高效、可维护
- 实战代码:Shell脚本实现 – 逐步拆解与注释
- 进阶优化:Python版本 – 更灵活、更健壮
- 常见问题与问答(FAQ) – 避开新手坑
- SEO优化与最佳实践 – 提升脚本的可移植性
为什么需要日志压缩归档?
在服务器运维中,日志文件会无限增长,耗尽磁盘空间,导致服务异常,传统手动清理低效且易出错。过期日志压缩归档脚本能自动识别超过指定天数的日志文件,将其压缩为.gz或.tar.gz格式,并转移到指定存储目录(或直接删除),从而释放空间、保留记录、满足合规需求。

核心价值:
- 降低存储成本:压缩比可达10:1
- 提升磁盘I/O:减少碎片文件
- 自动化运维:避免人工遗忘
脚本设计核心原则
| 原则 | 说明 |
|---|---|
| 幂等性 | 多次执行结果一致,不重复压缩 |
| 错误处理 | 文件锁、权限检查、磁盘空间预检 |
| 可配置性 | 通过变量定义路径、保留天数、压缩格式 |
| 日志审计 | 记录每次执行结果,便于回溯 |
| 安全优先 | 避免误删正在写入的日志,使用lsof检查 |
实战代码:Shell脚本实现(核心精华)
以下脚本基于bash,兼容Linux/Unix,已伪原创整合多篇技术文章的最佳写法:
#!/bin/bash
# 过期日志压缩归档脚本 v2.3
# 适用于Nginx、Tomcat、应用自定义日志
# ========== 配置区 ==========
LOG_DIR="/var/log/myapp" # 日志根目录
ARCHIVE_DIR="/var/log/archive" # 归档存储路径
RETENTION_DAYS=7 # 保留天数(文件修改时间)
LOG_PATTERN="*.log" # 匹配模式
COMPRESS_CMD="gzip" # 可选: bzip2, xz
DELETE_ORIGINAL="true" # 压缩后是否删除源文件
EXEC_LOG="/var/log/cleanup.log" # 脚本本身日志
# ============================
# 函数:带时间戳的日志
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$EXEC_LOG"
}
# 前置检查
[ -d "$LOG_DIR" ] || { log "ERROR: $LOG_DIR 不存在"; exit 1; }
[ -d "$ARCHIVE_DIR" ] || mkdir -p "$ARCHIVE_DIR"
# 查找过期文件(修改时间超过RETENTION_DAYS天)
expired_files=$(find "$LOG_DIR" -type f -name "$LOG_PATTERN" -mtime +$RETENTION_DAYS)
if [ -z "$expired_files" ]; then
log "INFO: 无过期日志文件需处理"
exit 0
fi
# 遍历并处理每个文件
for file in $expired_files; do
# 检查文件是否正在被进程写入(安全机制)
if lsof "$file" > /dev/null 2>&1; then
log "SKIP: $file 正在被使用,跳过"
continue
fi
# 生成压缩文件名
base_name=$(basename "$file")
timestamp=$(date -r "$file" +%Y%m%d_%H%M%S)
archived_name="${base_name}_${timestamp}.gz"
log "处理: $file"
# 执行压缩(保留源文件与否由配置决定)
if [ "$DELETE_ORIGINAL" = "true" ]; then
$COMPRESS_CMD -c "$file" > "${ARCHIVE_DIR}/${archived_name}" && rm -f "$file"
else
$COMPRESS_CMD -c "$file" > "${ARCHIVE_DIR}/${archived_name}"
fi
# 验证压缩文件是否创建成功
if [ -f "${ARCHIVE_DIR}/${archived_name}" ]; then
log "SUCCESS: 已归档为 ${archived_name}"
else
log "ERROR: 归档失败 ${file}"
fi
done
log "INFO: 本轮清理结束"
关键点解析:
-mtime +7:代表文件修改时间在7天前,而非创建时间lsof检查:防止压缩正在写入的日志导致数据损坏- 时间戳命名:避免同名文件被覆盖,便于恢复
进阶优化:Python版本
当需要处理多目录、自定义规则或复杂日志轮转时,Python更灵活,以下核心片段:
import os, gzip, shutil, time
from pathlib import Path
from datetime import datetime, timedelta
LOG_DIR = Path("/var/log/myapp")
ARCHIVE_DIR = Path("/var/log/archive")
DAYS = 7
now = time.time()
for file_path in LOG_DIR.rglob("*.log"):
if file_path.is_file():
# 检查文件修改时间
if (now - file_path.stat().st_mtime) > DAYS * 86400:
# 避免处理正在写入的文件(可扩展为flock检测)
dst = ARCHIVE_DIR / f"{file_path.stem}_{file_path.stat().st_mtime:.0f}.gz"
with open(file_path, 'rb') as f_in:
with gzip.open(dst, 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
os.remove(file_path)
优缺点对比:
- Shell:轻量、系统自带、适合简单场景
- Python:跨平台、易扩展、可集成邮件告警
常见问题与问答(FAQ)
Q1:如果日志被进程持续写入,脚本会压缩到一半吗?
A:不会,脚本中使用lsof检测文件句柄,若文件已被打开,则跳过,生产环境建议使用logrotate工具(系统级方案),但本脚本适用于自定义场景。
Q2:压缩后原文件删除,但发现归档文件损坏怎么办?
A:遵守“先压缩验证,后删除原文件”原则,上述Shell脚本写入前检验新文件是否存在,但更严谨的做法是:在删除原文件前,解压归档文件验证完整性(可加入gunzip -t检查),或者保留原文件(DELETE_ORIGINAL="false"),每周手动检查一次。
Q3:脚本如何定时执行?
A:使用crontab添加定时任务:
0 2 * * * /opt/scripts/cleanup.sh # 每天凌晨2点执行
Q4:磁盘空间不足导致压缩失败怎么办?
A:脚本应增加磁盘检查逻辑(df -h ${ARCHIVE_DIR}),若可用空间低于阈值(如1GB)则发送告警邮件,并暂停删除操作。
Q5:多个服务器如何统一管理?
A:可将脚本部署到Git仓库,通过Ansible、SaltStack等配置管理工具分发;或使用集中式日志服务器,本地仅保留短期日志。
SEO优化与最佳实践
- 关键词布局包含“过期日志压缩归档脚本”,正文自然融入“日志清理”、“磁盘空间自动化”、“logrotate替代方案”等长尾词。
- 结构化数据:使用清晰的小标题、列表、问答形式(符合Google Featured Snippet偏好)。
- 可复制性:提供完整代码块(勿带行号),方便读者直接复用。
- 避坑建议:
- 避免使用绝对路径硬编码,建议通过环境变量或配置文件读取
- 正确处理文件名中的空格(使用
find -print0配合xargs -0) - 大文件(>1GB)建议使用
pigz(并行gzip)提高效率
- 检测工具:执行前先用
-n参数(dry-run)模拟输出,确认不会误删。
最终建议:优先评估系统自带的logrotate,若需求复杂(如多层目录、自定义后缀)再采用此脚本方案,每季度审查一次脚本的保留天数设置,避免重要日志被过早清理。
📌 延伸阅读:结合Zabbix或Prometheus监控日志目录容量,当磁盘占用超过80%时自动触发本脚本,实现智能运维闭环。