#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 统一日志配置模块 提供标准化的日志配置 """ import os import sys import logging import logging.handlers from pathlib import Path from typing import Optional # 日志格式 CONSOLE_FORMAT = "%(asctime)s | %(levelname)-8s | %(name)s | %(message)s" FILE_FORMAT = "%(asctime)s | %(levelname)-8s | %(name)s | %(filename)s:%(lineno)d | %(message)s" DATE_FORMAT = "%Y-%m-%d %H:%M:%S" def setup_logging( level: str = "INFO", log_dir: Optional[str] = None, log_file: str = "app.log", max_bytes: int = 10 * 1024 * 1024, # 10MB backup_count: int = 5, console: bool = True, file: bool = True ) -> None: """ 配置全局日志 Args: level: 日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL) log_dir: 日志目录 (默认: logs/) log_file: 日志文件名 max_bytes: 单个日志文件最大大小 backup_count: 保留的日志文件数量 console: 是否输出到控制台 file: 是否输出到文件 """ # 确定日志目录 if log_dir is None: log_dir = os.environ.get("LOG_DIR", "logs") log_path = Path(log_dir) log_path.mkdir(parents=True, exist_ok=True) # 获取根日志器 root_logger = logging.getLogger() root_logger.setLevel(getattr(logging, level.upper(), logging.INFO)) # 清除现有处理器 root_logger.handlers.clear() # 控制台处理器 if console: console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(logging.DEBUG) console_handler.setFormatter(logging.Formatter(CONSOLE_FORMAT, DATE_FORMAT)) root_logger.addHandler(console_handler) # 文件处理器 (滚动) if file: file_handler = logging.handlers.RotatingFileHandler( log_path / log_file, maxBytes=max_bytes, backupCount=backup_count, encoding='utf-8' ) file_handler.setLevel(logging.DEBUG) file_handler.setFormatter(logging.Formatter(FILE_FORMAT, DATE_FORMAT)) root_logger.addHandler(file_handler) # 错误日志单独文件 error_handler = logging.handlers.RotatingFileHandler( log_path / "error.log", maxBytes=max_bytes, backupCount=backup_count, encoding='utf-8' ) error_handler.setLevel(logging.ERROR) error_handler.setFormatter(logging.Formatter(FILE_FORMAT, DATE_FORMAT)) root_logger.addHandler(error_handler) # 设置第三方库日志级别 logging.getLogger("urllib3").setLevel(logging.WARNING) logging.getLogger("httpx").setLevel(logging.WARNING) logging.getLogger("httpcore").setLevel(logging.WARNING) logging.getLogger("asyncio").setLevel(logging.WARNING) logging.info(f"日志配置完成: level={level}, dir={log_dir}") def get_logger(name: str) -> logging.Logger: """ 获取命名日志器 Args: name: 日志器名称 Returns: Logger 实例 """ return logging.getLogger(name) # 便捷函数 def init_logging_from_env(): """从环境变量初始化日志配置""" setup_logging( level=os.environ.get("LOG_LEVEL", "INFO"), log_dir=os.environ.get("LOG_DIR", "logs"), console=os.environ.get("LOG_CONSOLE", "true").lower() == "true", file=os.environ.get("LOG_FILE", "true").lower() == "true" )