""" Cain Error Logging System with Rotation and Severity Levels Features: - RotatingFileHandler with 1MB max size and 3 backup files - Severity levels: DEBUG, INFO, WARNING, ERROR, CRITICAL - Timestamp and severity formatted in log messages - Separate error log file for easier debugging """ import logging import sys from pathlib import Path from logging.handlers import RotatingFileHandler from datetime import datetime # Severity levels mapping SEVERITY_LEVELS = { 'DEBUG': logging.DEBUG, 'INFO': logging.INFO, 'WARNING': logging.WARNING, 'ERROR': logging.ERROR, 'CRITICAL': logging.CRITICAL } # Default log format with timestamp and severity LOG_FORMAT = '%(asctime)s | %(levelname)-8s | %(name)s | %(message)s' DATE_FORMAT = '%Y-%m-%d %H:%M:%S' # Log file paths LOGS_DIR = Path("logs") ERRORS_LOG = LOGS_DIR / "errors.log" def setup_error_logger(log_dir: Path = None, max_bytes: int = 1024*1024, backup_count: int = 3): """ Configure the error logging system with rotating file handler. Args: log_dir: Directory for log files (default: ./logs) max_bytes: Max size per log file before rotation (default: 1MB) backup_count: Number of backup files to keep (default: 3) Returns: logging.Logger: Configured logger instance """ global LOGS_DIR, ERRORS_LOG if log_dir: LOGS_DIR = log_dir ERRORS_LOG = LOGS_DIR / "errors.log" # Ensure logs directory exists LOGS_DIR.mkdir(exist_ok=True) # Create or get logger logger = logging.getLogger("cain_errors") logger.setLevel(logging.DEBUG) # Remove existing handlers to avoid duplicates logger.handlers.clear() # Create rotating file handler for error-specific logs rotating_handler = RotatingFileHandler( ERRORS_LOG, maxBytes=max_bytes, backupCount=backup_count, encoding='utf-8' ) rotating_handler.setLevel(logging.DEBUG) # Create formatter with timestamp and severity formatter = logging.Formatter(LOG_FORMAT, DATE_FORMAT) rotating_handler.setFormatter(formatter) # Add handler to logger logger.addHandler(rotating_handler) # Also add console handler for visibility console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(logging.INFO) console_handler.setFormatter(formatter) logger.addHandler(console_handler) return logger def log_error(logger: logging.Logger, severity: str, message: str, **kwargs): """ Log an error with specified severity level. Args: logger: Logger instance severity: One of: DEBUG, INFO, WARNING, ERROR, CRITICAL message: Log message **kwargs: Additional context to include in message """ severity_upper = severity.upper() if severity_upper not in SEVERITY_LEVELS: logger.warning(f"Invalid severity '{severity}', defaulting to ERROR") severity_upper = 'ERROR' # Add extra context if provided if kwargs: context = ' | '.join(f"{k}={v}" for k, v in kwargs.items()) message = f"{message} | {context}" log_func = getattr(logger, severity_upper.lower()) log_func(message) # Create default error logger instance error_logger = setup_error_logger()