from __future__ import annotations import logging import os from logging.handlers import RotatingFileHandler from app.core.config import settings from app.core.log_context import get_job_id, get_job_log_id def setup_logging() -> None: logger = logging.getLogger() if getattr(logger, "_connecthub_configured", False): return # 为每条日志注入“当前任务上下文”,供 per-run 日志隔离过滤使用。 # 仅安装一次(跨所有 logger 生效)。 if not getattr(logging, "_connecthub_record_factory_installed", False): old_factory = logging.getLogRecordFactory() def _record_factory(*args, **kwargs): # type: ignore[no-untyped-def] record = old_factory(*args, **kwargs) try: setattr(record, "connecthub_job_id", get_job_id()) setattr(record, "connecthub_job_log_id", get_job_log_id()) except Exception: # best-effort:任何问题都不能影响日志系统 setattr(record, "connecthub_job_id", None) setattr(record, "connecthub_job_log_id", None) return record logging.setLogRecordFactory(_record_factory) setattr(logging, "_connecthub_record_factory_installed", True) logger.setLevel(logging.INFO) formatter = logging.Formatter( fmt="%(asctime)s %(levelname)s %(name)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) sh = logging.StreamHandler() sh.setFormatter(formatter) logger.addHandler(sh) if settings.log_dir: os.makedirs(settings.log_dir, exist_ok=True) fh = RotatingFileHandler( os.path.join(settings.log_dir, "connecthub.log"), maxBytes=10 * 1024 * 1024, backupCount=5, ) fh.setFormatter(formatter) logger.addHandler(fh) setattr(logger, "_connecthub_configured", True)