multimodal-rag / src /utils /logging.py
itachi
Initial deployment
a809248
"""
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