| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 | from __future__ import annotationsimport osimport loggingfrom pathlib import Pathfrom logging.handlers import RotatingFileHandlerfrom typing import Optional_CONFIGURED = Falsedef _project_root() -> Path:    # Resolve repo root from this file location: app/core/logger.py -> repo/app/core    return Path(__file__).resolve().parents[2]def configure_logging(level: Optional[str] = None, log_dir: Optional[str] = None) -> None:    global _CONFIGURED    if _CONFIGURED:        return    # Determine log level    level_name = (level or os.getenv("LOG_LEVEL") or "INFO").upper()    log_level = getattr(logging, level_name, logging.INFO)    # Determine logs directory    base_dir = Path(log_dir) if log_dir else _project_root() / "logs"    base_dir.mkdir(parents=True, exist_ok=True)    # Root logger configuration    root = logging.getLogger()    root.setLevel(log_level)    fmt = logging.Formatter(        fmt="%(asctime)s [%(levelname)s] %(name)s - %(message)s",        datefmt="%Y-%m-%d %H:%M:%S",    )    file_handler = RotatingFileHandler(base_dir / "app.log", maxBytes=1_000_000, backupCount=3)    file_handler.setFormatter(fmt)    file_handler.setLevel(log_level)    root.addHandler(file_handler)    # Stream warnings+ to stderr for container visibility    stream = logging.StreamHandler()    stream.setLevel(logging.WARNING)    stream.setFormatter(fmt)    root.addHandler(stream)    _CONFIGURED = Truedef get_logger(name: Optional[str] = None) -> logging.Logger:    if not _CONFIGURED:        configure_logging()    return logging.getLogger(name or "app")
 |