如何写日志按天分割脚本

wen 实用脚本 30

本文目录导读:

如何写日志按天分割脚本

  1. Linux Shell 脚本方式
  2. Python 脚本方式
  3. Java (Logback) 配置方式
  4. Docker 日志轮转
  5. Node.js (Winston) 配置
  6. 使用建议

Linux Shell 脚本方式

使用 logrotate(推荐)

# 创建日志轮转配置文件
sudo tee /etc/logrotate.d/myapp << 'EOF'
/var/log/myapp/*.log {
    daily                    # 每天轮转
    rotate 30               # 保留30天
    compress                # 压缩旧日志
    delaycompress          # 延迟压缩
    missingok              # 如果日志丢失,不报错
    notifempty             # 如果日志为空,不轮转
    create 644 www-data www-data  # 创建新日志文件的权限
    dateext                # 使用日期作为后缀
    dateformat -%Y%m%d    # 日期格式
    copytruncate          # 先复制再清空原文件
    postrotate
        # 重启应用(如果有必要)
        /usr/bin/systemctl reload myapp 2>/dev/null || true
    endscript
}
EOF

手动 Shell 脚本

#!/bin/bash
# 日志按天分割脚本 - log_splitter.sh
LOG_DIR="/var/log/myapp"
LOG_FILE="app.log"
DATE_SUFFIX=$(date +%Y%m%d)
YESTERDAY_SUFFIX=$(date -d "yesterday" +%Y%m%d)
MAX_KEEP_DAYS=30
GZIP_DAYS=7  # 超过7天的日志压缩
# 创建日志目录
mkdir -p "$LOG_DIR"
# 函数:分割当前日志
split_log() {
    local current_log="$LOG_DIR/$LOG_FILE"
    local archive_log="$LOG_DIR/${LOG_FILE}.${DATE_SUFFIX}"
    if [ -f "$current_log" ]; then
        # 复制当前日志到归档文件
        cp "$current_log" "$archive_log"
        # 清空当前日志(不删除文件)
        : > "$current_log"
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 日志已分割: $archive_log"
    fi
}
# 函数:压缩旧日志
compress_old_logs() {
    local cutoff_date=$(date -d "$GZIP_DAYS days ago" +%Y%m%d)
    find "$LOG_DIR" -name "${LOG_FILE}.[0-9]*" -type f | while read log_file; do
        local file_date=$(echo "$log_file" | grep -oP '\d{8}$')
        if [ -n "$file_date" ] && [ "$file_date" -le "$cutoff_date" ]; then
            if [[ ! "$log_file" =~ \.gz$ ]]; then
                gzip "$log_file"
                echo "[$(date +'%Y-%m-%d %H:%M:%S')] 已压缩: ${log_file}.gz"
            fi
        fi
    done
}
# 函数:清理过期日志
cleanup_old_logs() {
    local cutoff_date=$(date -d "$MAX_KEEP_DAYS days ago" +%Y%m%d)
    find "$LOG_DIR" -name "${LOG_FILE}.*" -type f | while read log_file; do
        local file_date=""
        # 提取日期
        if [[ "$log_file" =~ [0-9]{8} ]]; then
            file_date=$(echo "$log_file" | grep -oP '\d{8}')
        fi
        if [ -n "$file_date" ] && [ "$file_date" -le "$cutoff_date" ]; then
            rm -f "$log_file"
            echo "[$(date +'%Y-%m-%d %H:%M:%S')] 已删除过期日志: $log_file"
        fi
    done
}
# 主逻辑
main() {
    echo "=== 日志分割开始 ==="
    split_log
    compress_old_logs
    cleanup_old_logs
    echo "=== 日志分割完成 ==="
}
# 执行主逻辑
main
# 添加定时任务(每天0点执行)
# crontab -e
# 0 0 * * * /path/to/log_splitter.sh

Python 脚本方式

简单的日志旋转

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import gzip
import shutil
import logging
from datetime import datetime, timedelta
from logging.handlers import TimedRotatingFileHandler
class DailyLogRotator:
    """日志按天轮转处理"""
    def __init__(self, log_dir, log_name, max_days=30):
        self.log_dir = log_dir
        self.log_name = log_name
        self.max_days = max_days
        # 确保日志目录存在
        os.makedirs(log_dir, exist_ok=True)
    def rotate_log(self):
        """轮转日志文件"""
        current_log = os.path.join(self.log_dir, self.log_name)
        if not os.path.exists(current_log):
            print(f"日志文件不存在: {current_log}")
            return
        # 生成新的日志文件名
        today = datetime.now().strftime("%Y%m%d")
        archive_log = os.path.join(self.log_dir, f"{self.log_name}.{today}")
        try:
            # 复制当前日志
            shutil.copy2(current_log, archive_log)
            # 清空当前日志
            with open(current_log, 'w') as f:
                f.truncate(0)
            print(f"日志已轮转: {archive_log}")
        except Exception as e:
            print(f"日志轮转失败: {e}")
    def compress_old_logs(self, days_old=7):
        """压缩旧日志"""
        cutoff_date = datetime.now() - timedelta(days=days_old)
        for filename in os.listdir(self.log_dir):
            if filename.startswith(self.log_name + ".") and not filename.endswith('.gz'):
                filepath = os.path.join(self.log_dir, filename)
                # 提取日期
                date_str = filename.split('.')[-1]
                try:
                    file_date = datetime.strptime(date_str, "%Y%m%d")
                    if file_date < cutoff_date:
                        # 压缩文件
                        with open(filepath, 'rb') as f_in:
                            with gzip.open(f"{filepath}.gz", 'wb') as f_out:
                                shutil.copyfileobj(f_in, f_out)
                        # 删除原文件
                        os.remove(filepath)
                        print(f"已压缩: {filename}")
                except ValueError:
                    continue  # 跳过不符合日期格式的文件
    def cleanup_old_logs(self):
        """清理过期日志"""
        cutoff_date = datetime.now() - timedelta(days=self.max_days)
        for filename in os.listdir(self.log_dir):
            if filename.startswith(self.log_name + "."):
                filepath = os.path.join(self.log_dir, filename)
                # 提取日期
                date_str = filename.split('.')[-1].replace('.gz', '')
                try:
                    file_date = datetime.strptime(date_str, "%Y%m%d")
                    if file_date < cutoff_date:
                        os.remove(filepath)
                        print(f"已删除过期日志: {filename}")
                except ValueError:
                    continue
# 使用Python日志模块的TimedRotatingFileHandler
def setup_daily_logging(log_dir, log_name):
    """配置按天轮转的日志"""
    import logging.handlers
    # 创建日志目录
    os.makedirs(log_dir, exist_ok=True)
    # 日志文件路径
    log_file = os.path.join(log_dir, log_name)
    # 创建日志记录器
    logger = logging.getLogger("MyApp")
    logger.setLevel(logging.INFO)
    # 创建按天轮转的文件处理器
    handler = TimedRotatingFileHandler(
        log_file,
        when="midnight",  # 每天午夜轮转
        interval=1,       # 间隔1天
        backupCount=30,   # 保留30天
        encoding="utf-8"
    )
    # 设置日志格式
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )
    handler.setFormatter(formatter)
    # 添加处理器
    logger.addHandler(handler)
    return logger
if __name__ == "__main__":
    # 使用示例
    rotator = DailyLogRotator("/var/log/myapp", "app.log")
    rotator.rotate_log()
    rotator.compress_old_logs()
    rotator.cleanup_old_logs()

Java (Logback) 配置方式

<!-- logback.xml -->
<configuration>
    <!-- 按天轮转的日志配置 -->
    <appender name="DAILY_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/var/log/myapp/app.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 按天轮转,保留日期格式 -->
            <fileNamePattern>/var/log/myapp/app.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 保留30天 -->
            <maxHistory>30</maxHistory>
            <!-- 总日志大小限制(可选) -->
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="DAILY_LOG" />
    </root>
</configuration>

Docker 日志轮转

# docker-compose.yml
version: '3.8'
services:
  myapp:
    image: myapp:latest
    logging:
      driver: "json-file"
      options:
        max-size: "10m"     # 单个日志文件最大10MB
        max-file: "3"       # 最多保留3个文件
        compress: "true"    # 压缩旧日志

Node.js (Winston) 配置

// logger.js
const winston = require('winston');
const DailyRotateFile = require('winston-daily-rotate-file');
// 配置按天轮转
const dailyRotateTransport = new DailyRotateFile({
    filename: '/var/log/myapp/app-%DATE%.log',
    datePattern: 'YYYY-MM-DD',
    maxSize: '20m',          // 单个文件最大20MB
    maxFiles: '30d',         // 保留30天
    zippedArchive: true,     // 压缩归档
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json()
    )
});
const logger = winston.createLogger({
    level: 'info',
    transports: [
        dailyRotateTransport,
        new winston.transports.Console()
    ]
});
module.exports = logger;

使用建议

  1. 自动化:设置cron定时任务

    # 每天0点执行
    crontab -e
    0 0 * * * /path/to/log_splitter.sh
  2. 监控:监控磁盘使用情况

    # 查看日志目录大小
    du -sh /var/log/myapp/
    # 设置磁盘告警阈值
    df -h | grep /var/log
  3. 安全性:设置适当的权限

    # 设置日志目录权限
    chmod 755 /var/log/myapp
    chown -R www-data:www-data /var/log/myapp

选择哪种方式取决于你的具体需求和环境,对于大多数场景,我推荐使用 logrotate(Linux)或 TimedRotatingFileHandler(Python/Java),因为它们更成熟可靠。

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