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")