Spaces:
Sleeping
Sleeping
# src/utils/logger.py | |
import logging | |
import sys | |
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler | |
from pathlib import Path | |
from datetime import datetime | |
from typing import Optional | |
from ..config.settings import Settings | |
class CustomFormatter(logging.Formatter): | |
"""Custom formatter with color coding for different log levels""" | |
COLORS = { | |
'DEBUG': '\033[0;36m', # Cyan | |
'INFO': '\033[0;32m', # Green | |
'WARNING': '\033[0;33m', # Yellow | |
'ERROR': '\033[0;31m', # Red | |
'CRITICAL': '\033[0;37;41m' # White on Red | |
} | |
RESET = '\033[0m' | |
def format(self, record): | |
# Add color to log level if on console | |
if hasattr(self, 'use_color') and self.use_color: | |
record.levelname = f"{self.COLORS.get(record.levelname, '')}{record.levelname}{self.RESET}" | |
return super().format(record) | |
def setup_logger( | |
name: str, | |
log_level: Optional[str] = None, | |
log_file: Optional[str] = None | |
) -> logging.Logger: | |
""" | |
Set up logger with both file and console handlers | |
Args: | |
name: Logger name | |
log_level: Optional override for log level | |
log_file: Optional override for log file path | |
Returns: | |
Configured logger instance | |
""" | |
try: | |
# Create logger | |
logger = logging.getLogger(name) | |
logger.setLevel(log_level or Settings.LOG_LEVEL) | |
# Avoid adding handlers if they already exist | |
if logger.handlers: | |
return logger | |
# Create formatters | |
file_formatter = logging.Formatter( | |
'%(asctime)s - %(name)s - [%(levelname)s] - %(message)s' | |
) | |
console_formatter = CustomFormatter( | |
'%(asctime)s - %(name)s - [%(levelname)s] - %(message)s' | |
) | |
console_formatter.use_color = True | |
# Create and configure file handler | |
log_file = log_file or Settings.LOG_FILE | |
log_dir = Path(log_file).parent | |
log_dir.mkdir(parents=True, exist_ok=True) | |
# Rotating file handler (size-based) | |
file_handler = RotatingFileHandler( | |
log_file, | |
maxBytes=10 * 1024 * 1024, # 10MB | |
backupCount=5 | |
) | |
file_handler.setFormatter(file_formatter) | |
# Time-based rotating handler for daily logs | |
daily_handler = TimedRotatingFileHandler( | |
str(log_dir / f"daily_{datetime.now():%Y-%m-%d}.log"), | |
when="midnight", | |
interval=1, | |
backupCount=30 | |
) | |
daily_handler.setFormatter(file_formatter) | |
# Console handler | |
console_handler = logging.StreamHandler(sys.stdout) | |
console_handler.setFormatter(console_formatter) | |
# Add handlers | |
logger.addHandler(file_handler) | |
logger.addHandler(daily_handler) | |
logger.addHandler(console_handler) | |
return logger | |
except Exception as e: | |
# Fallback to basic logging if setup fails | |
basic_logger = logging.getLogger(name) | |
basic_logger.setLevel(logging.INFO) | |
basic_logger.addHandler(logging.StreamHandler(sys.stdout)) | |
basic_logger.error(f"Error setting up logger: {str(e)}") | |
return basic_logger# Logging configuration implementation | |