|
| 1 | +""" |
| 2 | +改进的日志配置 - 解决QueryGPT日志文件暴涨问题 |
| 3 | +包含日志轮转、大小限制和性能优化 |
| 4 | +""" |
| 5 | +import logging |
| 6 | +import logging.handlers |
| 7 | +import os |
| 8 | +from pathlib import Path |
| 9 | + |
| 10 | +def setup_logging(app_name="querygpt", log_dir=None): |
| 11 | + """设置日志系统,包含轮转和大小限制""" |
| 12 | + |
| 13 | + # 确定日志目录 |
| 14 | + if log_dir is None: |
| 15 | + log_dir = Path(__file__).parent.parent / "logs" |
| 16 | + else: |
| 17 | + log_dir = Path(log_dir) |
| 18 | + |
| 19 | + # 创建日志目录 |
| 20 | + log_dir.mkdir(exist_ok=True) |
| 21 | + |
| 22 | + # 日志文件路径 |
| 23 | + log_file = log_dir / f"{app_name}.log" |
| 24 | + |
| 25 | + # 创建格式化器 |
| 26 | + formatter = logging.Formatter( |
| 27 | + '%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s' |
| 28 | + ) |
| 29 | + |
| 30 | + # 创建轮转文件处理器(每个文件最大10MB,保留5个备份) |
| 31 | + file_handler = logging.handlers.RotatingFileHandler( |
| 32 | + log_file, |
| 33 | + maxBytes=10*1024*1024, # 10MB |
| 34 | + backupCount=5, |
| 35 | + encoding='utf-8' |
| 36 | + ) |
| 37 | + file_handler.setFormatter(formatter) |
| 38 | + file_handler.setLevel(logging.INFO) # 文件只记录INFO及以上 |
| 39 | + |
| 40 | + # 创建控制台处理器 |
| 41 | + console_handler = logging.StreamHandler() |
| 42 | + console_handler.setFormatter(formatter) |
| 43 | + console_handler.setLevel(logging.WARNING) # 控制台只显示WARNING及以上 |
| 44 | + |
| 45 | + # 配置根日志器 |
| 46 | + root_logger = logging.getLogger() |
| 47 | + root_logger.setLevel(logging.INFO) |
| 48 | + |
| 49 | + # 清除现有处理器 |
| 50 | + root_logger.handlers.clear() |
| 51 | + |
| 52 | + # 添加处理器 |
| 53 | + root_logger.addHandler(file_handler) |
| 54 | + root_logger.addHandler(console_handler) |
| 55 | + |
| 56 | + # 降低第三方库的日志级别(这些是造成日志暴涨的主要原因) |
| 57 | + third_party_loggers = [ |
| 58 | + 'urllib3', |
| 59 | + 'werkzeug', |
| 60 | + 'litellm', |
| 61 | + 'httpx', |
| 62 | + 'openai', |
| 63 | + 'httpcore', |
| 64 | + 'requests', |
| 65 | + 'transformers', |
| 66 | + 'tensorflow', |
| 67 | + 'torch', |
| 68 | + 'sqlalchemy', |
| 69 | + 'alembic', |
| 70 | + 'PIL', |
| 71 | + 'matplotlib', |
| 72 | + 'numpy', |
| 73 | + 'pandas', |
| 74 | + 'selenium', |
| 75 | + 'uvicorn', |
| 76 | + 'fastapi' |
| 77 | + ] |
| 78 | + |
| 79 | + for logger_name in third_party_loggers: |
| 80 | + logging.getLogger(logger_name).setLevel(logging.WARNING) |
| 81 | + |
| 82 | + # 特别处理LiteLLM(这个库的日志特别多) |
| 83 | + logging.getLogger('LiteLLM').setLevel(logging.ERROR) |
| 84 | + logging.getLogger('litellm.utils').setLevel(logging.ERROR) |
| 85 | + logging.getLogger('litellm.litellm_core_utils').setLevel(logging.ERROR) |
| 86 | + logging.getLogger('litellm.proxy').setLevel(logging.ERROR) |
| 87 | + |
| 88 | + return root_logger |
| 89 | + |
| 90 | +def clean_old_logs(log_dir=None, days=7): |
| 91 | + """清理旧日志文件""" |
| 92 | + if log_dir is None: |
| 93 | + log_dir = Path(__file__).parent.parent / "logs" |
| 94 | + else: |
| 95 | + log_dir = Path(log_dir) |
| 96 | + |
| 97 | + if not log_dir.exists(): |
| 98 | + return |
| 99 | + |
| 100 | + from datetime import datetime, timedelta |
| 101 | + |
| 102 | + cutoff_time = datetime.now() - timedelta(days=days) |
| 103 | + |
| 104 | + for log_file in log_dir.glob("*.log*"): |
| 105 | + try: |
| 106 | + mtime = datetime.fromtimestamp(log_file.stat().st_mtime) |
| 107 | + if mtime < cutoff_time: |
| 108 | + log_file.unlink() |
| 109 | + print(f"删除旧日志: {log_file}") |
| 110 | + except Exception as e: |
| 111 | + print(f"无法删除 {log_file}: {e}") |
| 112 | + |
| 113 | +def setup_request_logging(): |
| 114 | + """设置请求日志的特殊处理""" |
| 115 | + import logging |
| 116 | + |
| 117 | + class RequestFilter(logging.Filter): |
| 118 | + """过滤器:减少请求日志的冗余信息""" |
| 119 | + def filter(self, record): |
| 120 | + # 过滤掉某些不必要的日志 |
| 121 | + if record.name == 'werkzeug': |
| 122 | + # 只保留错误和警告 |
| 123 | + return record.levelno >= logging.WARNING |
| 124 | + |
| 125 | + # 过滤掉健康检查的日志 |
| 126 | + if hasattr(record, 'getMessage'): |
| 127 | + msg = record.getMessage() |
| 128 | + if '/health' in msg or '/ping' in msg: |
| 129 | + return False |
| 130 | + |
| 131 | + return True |
| 132 | + |
| 133 | + # 添加过滤器到根日志器 |
| 134 | + for handler in logging.getLogger().handlers: |
| 135 | + handler.addFilter(RequestFilter()) |
0 commit comments