Source code for smartem_backend.log_manager
import logging
import logging.handlers
import sys
from dataclasses import dataclass, field
[docs]
@dataclass
class LogConfig:
    level: int = logging.INFO
    console: bool = True
    file_path: str | None = None
    file_max_size: int = 10_485_760  # 10MB
    file_backup_count: int = 5
    # Formatting
    format_string: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    handlers: list = field(default_factory=list, init=False) 
class LogManager:
    _instances = {}  # Class variable to store singleton instances by name
    @classmethod
    def get_instance(cls, name: str = "app") -> "LogManager":
        if name not in cls._instances:
            cls._instances[name] = cls(name)
        return cls._instances[name]
    def __init__(self, name: str = "app"):
        self.logger = logging.getLogger(name)
        self.logger.setLevel(logging.DEBUG)
        self.handlers = []
        self.name = name
    def configure(self, config: LogConfig) -> logging.Logger:
        # Remove existing handlers and close them properly
        for handler in self.handlers:
            self.logger.removeHandler(handler)
            handler.close()
        self.handlers.clear()
        formatter = logging.Formatter(config.format_string)
        # Console handler
        if config.console:
            console_handler = logging.StreamHandler(sys.stdout)
            console_handler.setLevel(config.level)
            console_handler.setFormatter(formatter)
            self.logger.addHandler(console_handler)
            self.handlers.append(console_handler)
        # File handler with rotation
        if config.file_path:
            file_handler = logging.handlers.RotatingFileHandler(
                config.file_path, maxBytes=config.file_max_size, backupCount=config.file_backup_count
            )
            file_handler.setLevel(config.level)
            file_handler.setFormatter(formatter)
            self.logger.addHandler(file_handler)
            self.handlers.append(file_handler)
        return self.logger
    def close(self):
        """Close all handlers to free resources"""
        for handler in self.handlers:
            self.logger.removeHandler(handler)
            handler.close()
        self.handlers.clear()
# Usage example
if __name__ == "__main__":
    # Initialize log manager
    log_manager = LogManager.get_instance("smartem_backend")
    # Console only
    logger = log_manager.configure(LogConfig(level=logging.INFO, console=True))
    logger.info("Console logging")
    # Console + File
    logger = log_manager.configure(LogConfig(level=logging.DEBUG, console=True, file_path="app.log"))
    logger.debug("Console and file logging")