日志轮转与自动清理脚本
自动轮转应用日志,压缩历史日志,清理过期日志,支持按大小/时间轮转,防止磁盘占满
详细内容
#!/bin/bash
# ==========================================
# 日志轮转与自动清理脚本
# 用途:自动轮转应用日志,压缩历史日志,清理过期日志
# 使用方法:bash log_rotate.sh
# 定时任务:0 0 * * * /path/to/log_rotate.sh
# ==========================================
# 配置
LOG_DIRS="${LOG_DIRS:-/var/log/nginx /var/log/mysql /opt/app/logs}"
LOG_PATTERNS="${LOG_PATTERNS:-*.log}"
MAX_LOG_SIZE="${MAX_LOG_SIZE:-100M}"
ROTATE_COUNT="${ROTATE_COUNT:-7}"
COMPRESS="${COMPRESS:-true}"
DELETE_OLD="${DELETE_OLD:-true}"
DRY_RUN="${DRY_RUN:-false}"
echo "========== 日志轮转开始 =========="
echo "执行时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "日志目录: $LOG_DIRS"
echo "最大日志大小: $MAX_LOG_SIZE"
echo "保留份数: $ROTATE_COUNT"
echo "压缩: $COMPRESS"
echo "删除过期: $DELETE_OLD"
echo "试运行: $DRY_RUN"
echo ""
# 统计
TOTAL_LOGS=0
ROTATED_LOGS=0
COMPRESSED_LOGS=0
DELETED_LOGS=0
FREED_SPACE=0
# 转换大小为字节
convert_to_bytes() {
local size=$1
local num=${size%[KMG]}
local unit=${size: -1}
case $unit in
K) echo $((num * 1024)) ;;
M) echo $((num * 1024 * 1024)) ;;
G) echo $((num * 1024 * 1024 * 1024)) ;;
*) echo $num ;;
esac
}
MAX_SIZE_BYTES=$(convert_to_bytes "$MAX_LOG_SIZE")
# 轮转单个日志文件
rotate_log() {
local log_file=$1
if [ ! -f "$log_file" ]; then
return
fi
TOTAL_LOGS=$((TOTAL_LOGS + 1))
local file_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
# 检查是否需要轮转
if [ "$file_size" -lt "$MAX_SIZE_BYTES" ]; then
return
fi
echo " 轮转: $log_file ($(du -h "$log_file" | cut -f1))"
if [ "$DRY_RUN" = "true" ]; then
echo " [试运行] 将轮转此文件"
ROTATED_LOGS=$((ROTATED_LOGS + 1))
return
fi
# 删除最旧的日志
if [ "$DELETE_OLD" = "true" ]; then
local oldest="${log_file}.${ROTATE_COUNT}.gz"
if [ -f "$oldest" ]; then
local oldest_size=$(stat -c%s "$oldest" 2>/dev/null || echo 0)
rm -f "$oldest"
DELETED_LOGS=$((DELETED_LOGS + 1))
FREED_SPACE=$((FREED_SPACE + oldest_size))
echo " 删除最旧: $oldest"
fi
fi
# 轮转历史日志
for i in $(seq $((ROTATE_COUNT - 1)) -1 1); do
local src="${log_file}.${i}.gz"
local dst="${log_file}.$((i + 1)).gz"
if [ -f "$src" ]; then
mv "$src" "$dst"
fi
done
# 轮转当前日志
local rotated="${log_file}.1"
mv "$log_file" "$rotated"
touch "$log_file"
chmod 644 "$log_file" 2>/dev/null
# 压缩
if [ "$COMPRESS" = "true" ]; then
gzip -f "$rotated"
COMPRESSED_LOGS=$((COMPRESSED_LOGS + 1))
echo " 压缩: ${rotated}.gz"
fi
ROTATED_LOGS=$((ROTATED_LOGS + 1))
}
# 清理过期日志(按时间)
cleanup_old_logs() {
local dir=$1
local days=${2:-30}
if [ ! -d "$dir" ]; then
return
fi
echo " 清理 $dir 中超过 ${days} 天的日志..."
local old_logs=$(find "$dir" -type f \( -name "*.log" -o -name "*.log.*" -o -name "*.gz" \) -mtime +$days 2>/dev/null)
if [ -n "$old_logs" ]; then
for log in $old_logs; do
local log_size=$(stat -c%s "$log" 2>/dev/null || echo 0)
if [ "$DRY_RUN" = "true" ]; then
echo " [试运行] 将删除: $log"
else
rm -f "$log"
echo " 删除: $log"
fi
DELETED_LOGS=$((DELETED_LOGS + 1))
FREED_SPACE=$((FREED_SPACE + log_size))
done
else
echo " 无过期日志"
fi
}
# 主处理
for log_dir in $LOG_DIRS; do
echo "【处理目录: $log_dir】"
if [ ! -d "$log_dir" ]; then
echo " ⚠️ 目录不存在,跳过"
echo ""
continue
fi
# 轮转日志
for pattern in $LOG_PATTERNS; do
find "$log_dir" -maxdepth 2 -type f -name "$pattern" 2>/dev/null | while read log_file; do
rotate_log "$log_file"
done
done
# 清理过期日志
cleanup_old_logs "$log_dir" 30
echo ""
done
# 汇总
echo "========== 处理汇总 =========="
echo " 扫描日志数: $TOTAL_LOGS"
echo " 轮转日志数: $ROTATED_LOGS"
echo " 压缩日志数: $COMPRESSED_LOGS"
echo " 删除日志数: $DELETED_LOGS"
echo " 释放空间: $(echo "scale=2; $FREED_SPACE / 1024 / 1024" | bc) MB"
echo ""
# 磁盘使用情况
echo "【磁盘使用情况】"
for log_dir in $LOG_DIRS; do
if [ -d "$log_dir" ]; then
echo " $log_dir: $(du -sh "$log_dir" | cut -f1)"
fi
done
echo ""
echo "========== 处理完成 =========="
echo "提示: 可将此脚本加入crontab定时执行,例如每天凌晨执行"
echo " 0 0 * * * /path/to/log_rotate.sh"
适配环境
适配系统:CentOS 7+,Ubuntu 18.04+,Debian 10+
依赖环境:bash 4.0+
参数说明
[{"name": "LOG_DIRS", "label": "\u65e5\u5fd7\u76ee\u5f55(\u7a7a\u683c\u5206\u9694)", "default": "/var/log/nginx /var/log/mysql"}, {"name": "MAX_LOG_SIZE", "label": "\u6700\u5927\u65e5\u5fd7\u5927\u5c0f", "default": "100M"}, {"name": "ROTATE_COUNT", "label": "\u4fdd\u7559\u4efd\u6570", "default": "7"}, {"name": "DRY_RUN", "label": "\u8bd5\u8fd0\u884c(true/false)", "default": "false"}]