本文目录导读:

Linux Shell 脚本方案
使用 logrotate(推荐)
#!/bin/bash
# 日志切割脚本 - logrotate方式
# 配置 logrotate
cat > /etc/logrotate.d/myapp << 'EOF'
/var/log/myapp/*.log {
daily # 按天切割
rotate 30 # 保留30天
compress # 压缩旧日志
delaycompress # 延迟一天压缩
missingok # 日志缺失不报错
notifempty # 空文件不切割
create 0644 root root # 创建新文件的权限
sharedscripts # 所有日志共享一个脚本
postrotate
# 通知应用程序重新打开日志文件
kill -USR1 `cat /var/run/myapp.pid` 2>/dev/null || true
endscript
}
EOF
# 手动运行测试
logrotate -vf /etc/logrotate.d/myapp
纯 Shell 脚本
#!/bin/bash
# 日志切割脚本 - 手动方式
LOG_DIR="/var/log/myapp"
LOG_FILE="app.log"
DATE_FORMAT=$(date +%Y%m%d)
RETENTION_DAYS=30
# 切割日志函数
rotate_log() {
local log_path="$LOG_DIR/$LOG_FILE"
local backup_path="$LOG_DIR/${LOG_FILE}_${DATE_FORMAT}"
# 检查日志文件是否存在
if [ ! -f "$log_path" ]; then
echo "日志文件不存在: $log_path"
exit 1
fi
# 复制当前日志到备份文件
cp "$log_path" "$backup_path"
# 清空当前日志文件
> "$log_path"
# 压缩旧日志(可选)
gzip "$backup_path" 2>/dev/null || true
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 日志已切割: $backup_path"
}
# 清理过期日志
cleanup_old_logs() {
find "$LOG_DIR" -name "${LOG_FILE}_*" -type f -mtime +$RETENTION_DAYS -delete
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 已清理 $RETENTION_DAYS 天前的旧日志"
}
# 主函数
main() {
# 创建日志目录
mkdir -p "$LOG_DIR"
# 执行切割
rotate_log
# 清理旧日志
cleanup_old_logs
}
main
Python 脚本方案
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import gzip
import shutil
import logging
from datetime import datetime, timedelta
from logging.handlers import TimedRotatingFileHandler
class DailyLogRotator:
"""按天切割日志"""
def __init__(self, log_path, retention_days=30):
self.log_path = log_path
self.retention_days = retention_days
self.logger = None
def setup_logger(self, logger_name='myapp'):
"""设置按天切割的日志记录器"""
handler = TimedRotatingFileHandler(
filename=self.log_path,
when='midnight', # 每天午夜切割
interval=1, # 间隔1天
backupCount=self.retention_days, # 保留天数
encoding='utf-8',
delay=False
)
# 设置日志格式
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
handler.setFormatter(formatter)
# 创建logger
self.logger = logging.getLogger(logger_name)
self.logger.setLevel(logging.INFO)
self.logger.addHandler(handler)
return self.logger
def manual_rotate(self):
"""手动切割日志"""
if not os.path.exists(self.log_path):
print(f"日志文件不存在: {self.log_path}")
return False
# 生成备份文件名
backup_name = f"{self.log_path}.{datetime.now().strftime('%Y%m%d')}"
try:
# 复制并清空原日志
shutil.copy2(self.log_path, backup_name)
with open(self.log_path, 'w') as f:
f.truncate()
# 压缩旧日志
with open(backup_name, 'rb') as f_in:
with gzip.open(f"{backup_name}.gz", 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
# 删除未压缩的备份
os.remove(backup_name)
print(f"日志已切割并压缩: {backup_name}.gz")
return True
except Exception as e:
print(f"日志切割失败: {e}")
return False
def cleanup_old_logs(self):
"""清理过期日志"""
now = datetime.now()
cutoff_date = now - timedelta(days=self.retention_days)
for filename in os.listdir(os.path.dirname(self.log_path)):
if filename.startswith(os.path.basename(self.log_path)):
filepath = os.path.join(os.path.dirname(self.log_path), filename)
# 解析日志中的日期
try:
file_date = datetime.strptime(
filename.split('.')[-2], # 假设格式为 app.log.20240101.gz
'%Y%m%d'
)
if file_date < cutoff_date:
os.remove(filepath)
print(f"已删除过期日志: {filename}")
except (ValueError, IndexError):
continue
def main():
"""主函数"""
# 配置
config = {
'log_path': '/var/log/myapp/app.log',
'retention_days': 30
}
# 创建日志目录
os.makedirs(os.path.dirname(config['log_path']), exist_ok=True)
# 初始化日志切割器
rotator = DailyLogRotator(
log_path=config['log_path'],
retention_days=config['retention_days']
)
# 手动切割
rotator.manual_rotate()
# 清理旧日志
rotator.cleanup_old_logs()
# 设置自动切割的logger(用于应用程序中)
logger = rotator.setup_logger()
# 测试日志
logger.info("系统启动")
logger.info("日志切割完成")
if __name__ == "__main__":
main()
Java 方案(Log4j2)
<!-- log4j2.xml 配置 -->
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<!-- 按天切割的 RollingFile -->
<RollingFile name="RollingFile"
fileName="/var/log/myapp/app.log"
filePattern="/var/log/myapp/app-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Policies>
<!-- 按天切割 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
</Policies>
<!-- 保留30天 -->
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
使用定时任务
crontab 配置
# 每天0点执行日志切割 0 0 * * * /usr/local/bin/rotate_log.sh # 如果需要更精确的时间(比如每天23:59) 59 23 * * * /usr/local/bin/rotate_log.sh # 也可以每半小时执行一次检查 */30 * * * * /usr/local/bin/rotate_log.sh
systemd timer (推荐)
# /etc/systemd/system/log-rotate.service [Unit] Description=Daily Log Rotation Service [Service] Type=oneshot ExecStart=/usr/local/bin/rotate_log.sh User=root [Install] WantedBy=multi-user.target
# /etc/systemd/system/log-rotate.timer [Unit] Description=Run log rotation daily [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target
Docker 容器方案
# Dockerfile
FROM alpine:latest
# 安装 logrotate
RUN apk add --no-cache logrotate bash
# 添加 logrotate 配置
COPY logrotate.conf /etc/logrotate.conf
COPY rotate_log.sh /usr/local/bin/rotate_log.sh
# 创建日志目录
RUN mkdir -p /var/log/myapp && \
chmod +x /usr/local/bin/rotate_log.sh
# 添加定时任务
RUN echo "0 0 * * * /usr/local/bin/rotate_log.sh" >> /var/spool/cron/crontabs/root
CMD ["crond", "-f", "-l", "2"]
使用建议
- 推荐使用 logrotate:系统自带,配置简单,功能强大
- 考虑SIGHUP信号:许多应用(如Nginx)支持重新加载日志
- 压缩旧日志:节省存储空间
- 设置保留天数:避免磁盘占满
- 错误处理:确保日志切割失败时有告警
- 测试环境验证:先在小范围测试
选择哪种方案取决于你的具体需求和技术栈,对于大多数Linux系统,logrotate是最简单可靠的选择。
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播