如何写过期日志压缩归档脚本

wen 实用脚本 30

从零到自动化运维的完整指南

📑 目录导读

  1. 为什么需要日志压缩归档? – 问题分析与价值
  2. 脚本设计核心原则 – 可靠、高效、可维护
  3. 实战代码:Shell脚本实现 – 逐步拆解与注释
  4. 进阶优化:Python版本 – 更灵活、更健壮
  5. 常见问题与问答(FAQ) – 避开新手坑
  6. 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优化与最佳实践

  1. 关键词布局包含“过期日志压缩归档脚本”,正文自然融入“日志清理”、“磁盘空间自动化”、“logrotate替代方案”等长尾词。
  2. 结构化数据:使用清晰的小标题、列表、问答形式(符合Google Featured Snippet偏好)。
  3. 可复制性:提供完整代码块(勿带行号),方便读者直接复用。
  4. 避坑建议
    • 避免使用绝对路径硬编码,建议通过环境变量或配置文件读取
    • 正确处理文件名中的空格(使用find -print0配合xargs -0
    • 大文件(>1GB)建议使用pigz(并行gzip)提高效率
  5. 检测工具:执行前先用-n参数(dry-run)模拟输出,确认不会误删。

最终建议:优先评估系统自带的logrotate,若需求复杂(如多层目录、自定义后缀)再采用此脚本方案,每季度审查一次脚本的保留天数设置,避免重要日志被过早清理。


📌 延伸阅读:结合Zabbix或Prometheus监控日志目录容量,当磁盘占用超过80%时自动触发本脚本,实现智能运维闭环。

抱歉,评论功能暂时关闭!