| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- import os
- import logging
- from datetime import datetime, timedelta
- from logging.handlers import RotatingFileHandler
- from foundation.infrastructure.tracing.trace_context import trace_filter
- def _get_week_range(dt: datetime) -> tuple:
- """获取 dt 所在周的周一和周日日期"""
- monday = dt - timedelta(days=dt.weekday())
- sunday = monday + timedelta(days=6)
- return monday, sunday
- def _get_week_dir_name(dt: datetime) -> str:
- """生成周目录名: 2026-W19_0505-0511"""
- monday, sunday = _get_week_range(dt)
- iso_cal = dt.isocalendar()
- week_num = iso_cal[1]
- return f"{monday.year}-W{week_num:02d}_{monday.strftime('%m%d')}-{sunday.strftime('%m%d')}"
- class WeeklyRotatingFileHandler(logging.Handler):
- """按周创建目录、按天创建日志文件的 Handler"""
- def __init__(self, base_dir: str, module_name: str, level_name: str,
- file_max_mb: int = 10, backup_count: int = 5):
- super().__init__()
- self.base_dir = base_dir
- self.module_name = module_name
- self.level_name = level_name
- self.file_max_bytes = file_max_mb * 1024 * 1024
- self.backup_count = backup_count
- self._current_week_dir = None
- self._current_date_str = None
- self._current_handler = None
- def _resolve_handler(self) -> RotatingFileHandler:
- now = datetime.now()
- week_dir = _get_week_dir_name(now)
- date_str = now.strftime('%m%d')
- if week_dir != self._current_week_dir or date_str != self._current_date_str:
- if self._current_handler:
- self._current_handler.close()
- self._current_week_dir = week_dir
- self._current_date_str = date_str
- dir_path = os.path.join(self.base_dir, week_dir)
- os.makedirs(dir_path, exist_ok=True)
- filename = os.path.join(
- dir_path,
- f"{date_str}_{self.module_name}_{self.level_name}.log"
- )
- self._current_handler = RotatingFileHandler(
- filename=filename,
- mode='a',
- maxBytes=self.file_max_bytes,
- backupCount=self.backup_count,
- encoding='utf-8',
- delay=True
- )
- self._current_handler.setFormatter(self.formatter)
- self._current_handler.addFilter(trace_filter)
- return self._current_handler
- def emit(self, record):
- try:
- handler = self._resolve_handler()
- if handler:
- handler.emit(record)
- except Exception:
- self.handleError(record)
- def create_weekly_file_handlers(module_name: str, base_dir: str,
- file_max_mb: int = 10, backup_count: int = 5) -> list:
- """为模块创建按周组织的日志 Handler 列表"""
- level_map = {
- 'debug': logging.DEBUG,
- 'info': logging.INFO,
- 'warning': logging.WARNING,
- 'error': logging.ERROR,
- 'critical': logging.CRITICAL,
- }
- handlers = []
- for level_name, level_value in level_map.items():
- h = WeeklyRotatingFileHandler(
- base_dir=base_dir,
- module_name=module_name,
- level_name=level_name,
- file_max_mb=file_max_mb,
- backup_count=backup_count,
- )
- h.setLevel(level_value)
- h.addFilter(lambda record, lvl=level_value: record.levelno >= lvl)
- handlers.append(h)
- return handlers
|