""" Logging utilities for Multimodal RAG System. Structured logging with multiple handlers. """ import logging import sys from datetime import datetime from pathlib import Path from typing import Optional from .config import get_config class ColoredFormatter(logging.Formatter): """Custom formatter with colors for console output.""" COLORS = { 'DEBUG': '\033[36m', # Cyan 'INFO': '\033[32m', # Green 'WARNING': '\033[33m', # Yellow 'ERROR': '\033[31m', # Red 'CRITICAL': '\033[35m', # Magenta 'RESET': '\033[0m' } def format(self, record: logging.LogRecord) -> str: color = self.COLORS.get(record.levelname, self.COLORS['RESET']) reset = self.COLORS['RESET'] record.levelname = f"{color}{record.levelname}{reset}" return super().format(record) def setup_logger( name: str, level: int = logging.INFO, log_file: Optional[str] = None ) -> logging.Logger: """ Set up a logger with console and optional file handlers. Args: name: Logger name level: Logging level log_file: Optional file path for logging Returns: Configured logger instance """ logger = logging.getLogger(name) logger.setLevel(level) # Prevent duplicate handlers if logger.handlers: return logger # Console handler with colors console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(level) console_format = ColoredFormatter( '%(asctime)s | %(levelname)s | %(name)s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) console_handler.setFormatter(console_format) logger.addHandler(console_handler) # File handler (optional) if log_file: config = get_config() log_path = config.paths.logs_dir / log_file file_handler = logging.FileHandler(log_path, encoding='utf-8') file_handler.setLevel(level) file_format = logging.Formatter( '%(asctime)s | %(levelname)s | %(name)s | %(funcName)s:%(lineno)d | %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) file_handler.setFormatter(file_format) logger.addHandler(file_handler) return logger def get_logger(name: str) -> logging.Logger: """ Get or create a logger with the given name. Args: name: Logger name (typically __name__) Returns: Logger instance """ config = get_config() level = logging.DEBUG if config.debug else logging.INFO # Create log filename based on date log_file = f"rag_{datetime.now().strftime('%Y%m%d')}.log" return setup_logger(name, level, log_file) class LoggerMixin: """Mixin class to add logging capability to any class.""" @property def logger(self) -> logging.Logger: if not hasattr(self, '_logger'): self._logger = get_logger(self.__class__.__name__) return self._logger