Spaces:
Sleeping
Sleeping
| """Lightweight logger factory for the SDGen application. | |
| This module centralizes logger configuration to ensure consistent formatting, | |
| file rotation, and prevention of duplicate handlers during repeated imports. | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| from logging import Handler, Logger | |
| from logging.handlers import RotatingFileHandler | |
| from sdgen.config import LOGS_ROOT | |
| # Ensure logs directory exists | |
| LOGS_ROOT.mkdir(parents=True, exist_ok=True) | |
| # Cache prevents repeated handler installation for the same logger name | |
| _LOGGER_CACHE: dict[str, Logger] = {} | |
| def _build_handler() -> Handler: | |
| """Return a rotating file handler with unified log formatting. | |
| The handler writes to `app.log` under LOGS_ROOT and uses log rotation | |
| to cap file size and maintain up to 3 backups. | |
| """ | |
| log_file = LOGS_ROOT / "app.log" | |
| handler = RotatingFileHandler( | |
| filename=log_file, | |
| maxBytes=5_000_000, # ~5 MB | |
| backupCount=3, | |
| ) | |
| fmt = "%(asctime)s [%(name)s] [%(levelname)s] %(message)s" | |
| handler.setFormatter(logging.Formatter(fmt)) | |
| return handler | |
| def get_logger(name: str) -> Logger: | |
| """Return a configured logger with rotating file and console handlers. | |
| The returned logger: | |
| - uses INFO level by default | |
| - writes to both stdout and a rotating log file | |
| - does not propagate to root logger | |
| - never duplicates handlers for the same name | |
| Args: | |
| name: Distinct logger name, generally the module name. | |
| Returns: | |
| A configured `logging.Logger` instance. | |
| """ | |
| if name in _LOGGER_CACHE: | |
| return _LOGGER_CACHE[name] | |
| logger = logging.getLogger(name) | |
| logger.setLevel(logging.INFO) | |
| # Guard against accidentally adding handlers multiple times | |
| if not logger.handlers: | |
| logger.addHandler(_build_handler()) | |
| stream = logging.StreamHandler() | |
| stream.setFormatter( | |
| logging.Formatter("%(asctime)s [%(name)s]" + "[%(levelname)s] %(message)s") | |
| ) | |
| logger.addHandler(stream) | |
| logger.propagate = False | |
| _LOGGER_CACHE[name] = logger | |
| return logger | |