File size: 3,519 Bytes
843a502
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import sys
import logging
import colorama
from colorama import Fore, Style

# Initialize colorama to work on Windows too
colorama.init()

# Define custom VERBOSE level (between DEBUG-10 and INFO-20)
VERBOSE = 15
logging.addLevelName(VERBOSE, 'VERBOSE')
RESULT = 25
logging.addLevelName(RESULT, 'RESULT')

class ColoredFormatter(logging.Formatter):
    """Custom formatter that adds colors to log messages based on level with fixed width"""
    COLORS = {
        'DEBUG': Fore.CYAN + Style.BRIGHT,
        'VERBOSE': Fore.BLUE + Style.BRIGHT,
        'INFO': Fore.GREEN + Style.BRIGHT,
        'RESULT' : Fore.RESET + Style.BRIGHT,
        'WARNING': Fore.YELLOW + Style.BRIGHT,
        'ERROR': Fore.RED + Style.BRIGHT,
        'CRITICAL': Fore.MAGENTA + Style.BRIGHT
    }
    LEVEL_NAME_WIDTH = 8

    def format(self, record):
        # Save original levelname and message
        orig_levelname = record.levelname
        orig_msg = record.msg

        # Determine the color for the level
        color_code = self.COLORS.get(orig_levelname, '')

        # Calculate padding for levelname
        padding = ' ' * (self.LEVEL_NAME_WIDTH - len(orig_levelname))

        # Apply color to levelname with padding
        record.levelname = f"{color_code}{orig_levelname}{padding}{Style.RESET_ALL}"

        # Apply color to the message as well
        record.msg = f"{color_code}{orig_msg}{Style.RESET_ALL}"

        # Format the message
        result = super().format(record)

        # Restore original values
        record.levelname = orig_levelname
        record.msg = orig_msg
        return result
    
class ColoredLogger(logging.Logger):
    """Custom logger class with verbose method"""
    
    def verbose(self, msg, *args, **kwargs):
        """Log at custom VERBOSE level"""
        if self.isEnabledFor(VERBOSE):
            self._log(VERBOSE, msg, args, **kwargs)
            
    def result(self, msg, *args, **kwargs):
        """Log at custom RESULT level"""
        if self.isEnabledFor(RESULT):
            self._log(RESULT, msg, args, **kwargs)
            
    # logging.Logger.result = custom_logging

def setup_logger(name='colored_logger', level="INFO"):
    """Set up and return a colored logger instance"""
    
    # Register our custom logger class
    logging.setLoggerClass(ColoredLogger)
    
    # Create logger
    logger = logging.getLogger(name)
    
    # Set logger level
    try:
        logger.setLevel(getattr(logging, level.upper()))
    except AttributeError:
        logger.setLevel(logging.INFO)  # Default to INFO if invalid level
    
    # Create console handler
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setLevel(level)
    
    # Create formatter
    formatter = ColoredFormatter(
        # fmt='%(asctime)s - %(levelname)s - %(message)s',
        # datefmt='%Y-%m-%d %H:%M:%S'
        fmt='%(levelname)8s - %(message)s'
    )
    
    # Add formatter to handler
    console_handler.setFormatter(formatter)
    
    # Add handler to logger
    logger.addHandler(console_handler)
    
    return logger

# Example usage
if __name__ == '__main__':
    logger = setup_logger()
    
    # Test all log levels including new VERBOSE level
    logger.debug("This is a debug message")
    logger.verbose("This is a verbose message")  # New verbose level
    logger.info("This is an info message")
    logger.warning("This is a warning message")
    logger.error("This is an error message")
    logger.critical("This is a critical message")