自动压缩日志文件的脚本怎么写

wen 实用脚本 1

从零构建高效日志管理方案

目录导读

  1. 为什么需要自动压缩日志文件?
  2. 脚本编写前的环境准备与核心逻辑
  3. 基于Shell的自动压缩脚本实战
  4. 基于Python的跨平台压缩脚本
  5. 定时任务配置与异常处理
  6. 常见问题FAQ

为什么需要自动压缩日志文件?

在服务器运维中,日志文件会持续增长,若不及时处理,可能导致磁盘空间耗尽、服务响应变慢,手动压缩既低效又易遗漏。自动压缩脚本能够按策略(如按天、按大小)压缩旧日志,保留最近活跃日志,同时释放存储资源,根据谷歌SEO相关性原则,本文将提供可直接部署的代码,并覆盖主流操作系统。

自动压缩日志文件的脚本怎么写

关键痛点场景

  • Nginx/Apache访问日志每天增长数GB
  • Java应用日志(如SpringBoot)按日滚动后堆积
  • 数据库慢查询日志长期不清理

脚本编写前的环境准备与核心逻辑

核心设计思路:

检查日志文件 → 判断是否需要压缩 → 执行压缩 → 删除原文件(可选)→ 记录操作日志

必须考虑的变量:

参数 说明 示例值
LOG_DIR 日志存放目录 /var/log/myapp
RETENTION_DAYS 保留多少天未压缩文件 7
MIN_SIZE 触发压缩的最小文件大小 100M
COMPRESS_CMD 压缩命令(gzip/bzip2/xz) gzip

注意:不要直接操作正在写入的日志文件,通常搭配日志轮转工具(logrotate)使用,或仅处理昨日及更早的文件。


基于Shell的自动压缩脚本实战

以下脚本适用于Linux/macOS,兼容bash和zsh:

#!/bin/bash
# 自动压缩N天前的日志文件 v2.1
LOG_DIR="/var/log/myapp"
RETENTION_DAYS=7
COMPRESS_TYPE="gzip"  # 可选: gzip / bzip2 / xz
LOG_ARCHIVE="/root/scripts/log_archive.log"
# 颜色标记
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
compress_file() {
    local file=$1
    case $COMPRESS_TYPE in
        gzip)
            gzip -f "$file"
            ;;
        bzip2)
            bzip2 -z "$file"
            ;;
        xz)
            xz -z "$file"
            ;;
        *)
            echo "不支持的压缩类型" | tee -a "$LOG_ARCHIVE"
            exit 1
            ;;
    esac
}
echo "==============================" >> "$LOG_ARCHIVE"
echo "日志压缩开始: $(date)" >> "$LOG_ARCHIVE"
find "$LOG_DIR" -type f -name "*.log" -mtime +$RETENTION_DAYS | while read file; do
    if [ -f "$file" ] && [ ! -f "${file}.gz" ] && [ ! -f "${file}.bz2" ] && [ ! -f "${file}.xz" ]; then
        echo "正在压缩: $file" | tee -a "$LOG_ARCHIVE"
        compress_file "$file"
        if [ $? -eq 0 ]; then
            echo -e "${GREEN}成功压缩: $file${NC}" >> "$LOG_ARCHIVE"
        else
            echo -e "${RED}压缩失败: $file${NC}" >> "$LOG_ARCHIVE"
        fi
    fi
done
echo "日志压缩结束: $(date)" >> "$LOG_ARCHIVE"

部署步骤

  1. 保存为 compress_logs.sh
  2. 执行 chmod +x compress_logs.sh
  3. 测试运行:./compress_logs.sh
  4. 加入crontab:0 3 * * * /root/scripts/compress_logs.sh

脚本特性解释:

  • 使用 -mtime +7 只处理7天前的文件,避免操作当前日志
  • 三重扩展名检查防止重复压缩
  • 操作日志记录便于审计

基于Python的跨平台压缩脚本

对于Windows/Linux/macOS统一管理,推荐Python脚本:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 智能日志压缩器 v3.0
import os
import gzip
import shutil
import time
from pathlib import Path
from datetime import datetime, timedelta
class LogCompressor:
    def __init__(self, config):
        self.log_dir = Path(config.get('log_dir', '/var/log'))
        self.retention_days = config.get('retention_days', 7)
        self.min_size_mb = config.get('min_size_mb', 50)
        self.dry_run = config.get('dry_run', False)
        self.archive_log = config.get('archive_log', './compressor.log')
        self.total_saved = 0  # 统计节省空间
    def should_compress(self, file_path):
        """判断文件是否需要压缩"""
        # 排除已压缩文件
        if file_path.suffix in ['.gz', '.bz2', '.zip']:
            return False
        # 检查文件修改时间
        mtime = datetime.fromtimestamp(file_path.stat().st_mtime)
        if (datetime.now() - mtime) > timedelta(days=self.retention_days):
            # 检查文件大小
            size_mb = file_path.stat().st_size / (1024 * 1024)
            return size_mb >= self.min_size_mb
        return False
    def compress_file(self, file_path):
        """执行gzip压缩并删除原文件"""
        compressed_path = file_path.with_suffix(file_path.suffix + '.gz')
        original_size = file_path.stat().st_size
        if self.dry_run:
            print(f"[DRY RUN] 将压缩: {file_path}")
            return True
        try:
            with open(file_path, 'rb') as f_in:
                with gzip.open(compressed_path, 'wb', compresslevel=6) as f_out:
                    shutil.copyfileobj(f_in, f_out)
            # 验证压缩文件完整性
            if compressed_path.stat().st_size > 0:
                os.remove(file_path)
                saved = original_size - compressed_path.stat().st_size
                self.total_saved += saved
                self.log_action(f"压缩成功: {file_path} -> {compressed_path} (节省 {saved/1024/1024:.2f} MB)")
                return True
            else:
                self.log_action(f"警告: 压缩为空文件: {file_path}", level='WARN')
                compressed_path.unlink(missing_ok=True)
                return False
        except Exception as e:
            self.log_action(f"压缩失败: {file_path} - {str(e)}", level='ERROR')
            # 清理残损压缩文件
            compressed_path.unlink(missing_ok=True)
            return False
    def log_action(self, message, level='INFO'):
        timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        log_entry = f"[{timestamp}] [{level}] {message}"
        print(log_entry)
        with open(self.archive_log, 'a', encoding='utf-8') as f:
            f.write(log_entry + '\n')
    def run(self):
        self.log_action(f"开始日志压缩任务 (保留天数: {self.retention_days}, 最小大小: {self.min_size_mb}MB)")
        scanned = 0
        compressed = 0
        for log_file in self.log_dir.rglob('*.log*'):
            # 排除压缩文件
            if any(log_file.suffix == ext for ext in ['.gz', '.bz2', '.xz']):
                continue
            scanned += 1
            if self.should_compress(log_file):
                if self.compress_file(log_file):
                    compressed += 1
        self.log_action(f"任务完成: 扫描 {scanned} 个文件, 压缩 {compressed} 个, 总节省 {self.total_saved/1024/1024:.2f} MB")
if __name__ == '__main__':
    config = {
        'log_dir': '/var/log/myapp',
        'retention_days': 7,
        'min_size_mb': 50,
        'dry_run': False,  # 设为True可进行模拟运行
    }
    compressor = LogCompressor(config)
    compressor.run()

Python脚本优势

  • 自动处理编码问题
  • 跨平台兼容(Windows需修改为 log_dir = 'C:/logs'
  • 可扩展为发送邮件通知或对接监控系统

定时任务配置与异常处理

Linux crontab配置示例:

# 每天凌晨3点执行
0 3 * * * /bin/bash /root/scripts/compress_logs.sh >> /var/log/compress_cron.log 2>&1
# 每6小时执行一次(应对高频日志)
0 */6 * * * /usr/bin/python3 /opt/scripts/python_log_compressor.py

Windows任务计划程序:

  1. 打开“任务计划程序”
  2. 创建基本任务 → 触发器选择“每天” → 操作选择“启动程序”
  3. 程序/脚本填写 python.exe,参数填写脚本绝对路径

必须处理的异常情况:

  • 磁盘空间不足:在压缩前检查 df -h,预留至少500MB临时空间
  • 文件被占用:使用 lsoffuser 检查后再压缩
  • 权限不足:确保脚本拥有 r+w 权限,建议使用 sudo crontab -e
  • 压缩中断:添加临时文件机制,使用 .tmp 后缀,完成后重命名

常见问题FAQ

Q1:压缩后应用无法写入日志怎么办?
A:确保脚本只处理“昨日及更早”的日志(使用 -mtime +1),正在写入的文件通常命名为 access.log,轮转后的文件命名如 access.log.2023-12-01,只压缩轮转后的文件。

Q2:如何恢复已压缩的日志?
A:使用对应解压命令。gunzip access.log.2023-12-01.gz,或使用 zcat 直接查看。

Q3:脚本压缩后日志文件丢失怎么回事?
A:检查 set -e 是否启用,该选项会使脚本在第一个错误时退出,建议使用 set -e 前做好备份,或使用Python脚本的异常处理。

Q4:如何不用Gzip改用Zstandard(zstd)压缩?
A:Shell脚本中将 COMPRESS_TYPE 改为 zstd -q;Python脚本需安装 zstandard 库,并修改压缩函数。

Q5:压缩脚本能否与logrotate共存?
A:完全可以,推荐配置:logrotate负责每日轮转和压缩(使用delaycompress),自定义脚本负责清理超期压缩包。


延伸建议

  1. 首次运行前务必在测试环境验证
  2. 保留最近3-7天的未压缩日志用于快速排查问题
  3. 根据磁盘容量调整 RETENTION_DAYS,通常建议保留30-90天压缩日志

通过以上方案,您可以根据实际环境选择Shell或Python实现自动日志压缩,并加入监控和告警机制,构建可靠的生产级日志管理策略。

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