File size: 3,275 Bytes
30a95a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
"""
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()