File size: 2,127 Bytes
7a1d414 9bc957e 7a1d414 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
"""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
|