""" 日志工具模块 使用Python标准库logging,兼容Python 3.8.6 """ import logging import sys from pathlib import Path from datetime import datetime from config.settings import LOG_LEVEL, LOG_FORMAT, LOG_DIR def get_log_filename(base_name: str = 'crawler') -> Path: """ 根据当前月份生成日志文件名 Args: base_name: 日志文件基础名称 Returns: 日志文件路径,格式为: base_name-yyyy-mm.log """ current_date = datetime.now() filename = f"{base_name}-{current_date.strftime('%Y-%m')}.log" return LOG_DIR / filename class MonthlyRotatingFileHandler(logging.FileHandler): """ 按月轮转的日志处理器 文件名格式为: base_name-yyyy-mm.log 当月份变化时,自动切换到新的日志文件 """ def __init__(self, base_name: str = 'crawler', encoding: str = 'utf-8', delay: bool = False): """ 初始化按月轮转的日志处理器 Args: base_name: 日志文件基础名称 encoding: 文件编码 delay: 是否延迟打开文件 """ self.base_name = base_name self.current_month = None self.log_dir = LOG_DIR self.log_dir.mkdir(parents=True, exist_ok=True) # 获取当前月份的日志文件 log_file = get_log_filename(base_name) self.current_month = datetime.now().strftime('%Y-%m') super().__init__(str(log_file), mode='a', encoding=encoding, delay=delay) def emit(self, record): """ 发送日志记录 在发送前检查月份是否变化,如果变化则切换到新的日志文件 """ current_month = datetime.now().strftime('%Y-%m') # 如果月份变化,切换到新的日志文件 if current_month != self.current_month: self.do_rollover() self.current_month = current_month super().emit(record) def do_rollover(self): """ 执行日志轮转 关闭当前文件,打开新月份的日志文件 """ if self.stream: self.stream.close() self.stream = None # 生成新月份的日志文件名 new_log_file = get_log_filename(self.base_name) self.baseFilename = str(new_log_file) # 打开新的日志文件 if not self.delay: self.stream = self._open() def setup_logger(name: str = 'crawler', level: str = LOG_LEVEL) -> logging.Logger: """ 配置并返回logger实例 Args: name: logger名称 level: 日志级别 Returns: logging.Logger实例 """ logger = logging.getLogger(name) logger.setLevel(getattr(logging, level.upper(), logging.INFO)) # 避免重复添加handler if logger.handlers: return logger # 控制台输出 console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(getattr(logging, level.upper(), logging.INFO)) console_formatter = logging.Formatter(LOG_FORMAT) console_handler.setFormatter(console_formatter) logger.addHandler(console_handler) # 文件输出 - 按月轮转,文件名格式为: crawler-yyyy-mm.log file_handler = MonthlyRotatingFileHandler( base_name=name, encoding='utf-8', delay=False ) file_handler.setLevel(logging.INFO) file_formatter = logging.Formatter(LOG_FORMAT) file_handler.setFormatter(file_formatter) logger.addHandler(file_handler) return logger # 创建默认logger logger = setup_logger()