本文目录导读:

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;
使用建议
-
自动化:设置cron定时任务
# 每天0点执行 crontab -e 0 0 * * * /path/to/log_splitter.sh
-
监控:监控磁盘使用情况
# 查看日志目录大小 du -sh /var/log/myapp/ # 设置磁盘告警阈值 df -h | grep /var/log
-
安全性:设置适当的权限
# 设置日志目录权限 chmod 755 /var/log/myapp chown -R www-data:www-data /var/log/myapp
选择哪种方式取决于你的具体需求和环境,对于大多数场景,我推荐使用 logrotate(Linux)或 TimedRotatingFileHandler(Python/Java),因为它们更成熟可靠。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播