aidevelopementtoolkit.logging_utils.logger

ColorFormatter

Bases: Formatter

Format log records with ANSI-colored levels and severity spacing.

The level name is wrapped in an ANSI color code. Records at INFO, WARNING, ERROR, and CRITICAL levels are prefixed with a newline.

Source code in aidevelopementtoolkit/logging_utils/logger.py
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
class ColorFormatter(logging.Formatter):
    """Format log records with ANSI-colored levels and severity spacing.

    The level name is wrapped in an ANSI color code. Records at INFO,
    WARNING, ERROR, and CRITICAL levels are prefixed with a newline.
    """

    COLORS = {
        "DEBUG": "\033[36m", # Cyan
        "INFO": "\033[33m", # Yellow
        "WARNING": "\033[38;5;208m", # Orange
        "ERROR": "\033[31m", # Red
        "CRITICAL": "\033[41m", # Red background
    }

    BOLD = "\033[1m"
    RESET = "\033[0m"

    def format(self, record):
        levelname = record.levelname
        color = self.COLORS.get(levelname, self.RESET)
        error_type = getattr(record, "passed_error_type", None)
        label = f"{error_type}" if error_type else levelname

        # Bold and color
        record.levelname = f"{self.BOLD}{color}[{label}]{self.RESET}"

        # Let the parent formatter build the final line
        formatted = super().format(record)

        # Add newline BEFORE the date for INFO and ERROR
        if levelname in ("INFO", "ERROR", "CRITICAL", "WARNING"):
            formatted = f"\n{formatted}"

        return formatted

CustomLogger

Bases: Logger

A standard logger that can raise an exception after logging an error.

All methods retain :class:logging.Logger behavior except for :meth:error, which optionally accepts an exception class as its first positional argument after the message.

Source code in aidevelopementtoolkit/logging_utils/logger.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
class CustomLogger(logging.Logger):
    """A standard logger that can raise an exception after logging an error.

    All methods retain :class:`logging.Logger` behavior except for
    :meth:`error`, which optionally accepts an exception class as its first
    positional argument after the message.
    """

    def error(self, msg, *args, **kwargs):
        """Log an error message and optionally raise an exception.

        Parameters
        ----------
        msg : object
            Message to log. If formatting arguments are supplied, the message
            is formatted using the standard logging `%`-style convention.
        *args : object
            Formatting arguments, optionally preceded by an exception class.
            If the first positional argument is an exception class, it is
            removed from the formatting arguments and raised after the message
            is logged.
        **kwargs : object
            Keyword arguments forwarded to :meth:`logging.Logger.error`.

        Examples
        --------
        Log an error without raising:

        >>> logger.error("Unable to load the model")

        Log an error and then raise an exception:

        >>> logger.error("Checkpoint not found", FileNotFoundError)
        Traceback (most recent call last):
        ...
        FileNotFoundError: Checkpoint not found
        """
        exception_type = None

        # Detect: logger.error("message", FileNotFoundError)
        if args and isinstance(args[0], type):
            if issubclass(args[0], BaseException):
                exception_type = args[0]
                args = args[1:]

        if exception_type is not None:
            traceback.print_stack()
            extra = dict(kwargs.get("extra") or {})
            extra["passed_error_type"] = exception_type.__name__
            kwargs["extra"] = extra

        # Log using the standard logging implementation
        super().error(msg, *args, **kwargs)

        sys.exit(1)

error(msg, *args, **kwargs)

Log an error message and optionally raise an exception.

Parameters:
  • msg (object) –

    Message to log. If formatting arguments are supplied, the message is formatted using the standard logging %-style convention.

  • *args (object, default: () ) –

    Formatting arguments, optionally preceded by an exception class. If the first positional argument is an exception class, it is removed from the formatting arguments and raised after the message is logged.

  • **kwargs (object, default: {} ) –

    Keyword arguments forwarded to :meth:logging.Logger.error.

Examples:

Log an error without raising:

>>> logger.error("Unable to load the model")

Log an error and then raise an exception:

>>> logger.error("Checkpoint not found", FileNotFoundError)
Traceback (most recent call last):
...
FileNotFoundError: Checkpoint not found
Source code in aidevelopementtoolkit/logging_utils/logger.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
def error(self, msg, *args, **kwargs):
    """Log an error message and optionally raise an exception.

    Parameters
    ----------
    msg : object
        Message to log. If formatting arguments are supplied, the message
        is formatted using the standard logging `%`-style convention.
    *args : object
        Formatting arguments, optionally preceded by an exception class.
        If the first positional argument is an exception class, it is
        removed from the formatting arguments and raised after the message
        is logged.
    **kwargs : object
        Keyword arguments forwarded to :meth:`logging.Logger.error`.

    Examples
    --------
    Log an error without raising:

    >>> logger.error("Unable to load the model")

    Log an error and then raise an exception:

    >>> logger.error("Checkpoint not found", FileNotFoundError)
    Traceback (most recent call last):
    ...
    FileNotFoundError: Checkpoint not found
    """
    exception_type = None

    # Detect: logger.error("message", FileNotFoundError)
    if args and isinstance(args[0], type):
        if issubclass(args[0], BaseException):
            exception_type = args[0]
            args = args[1:]

    if exception_type is not None:
        traceback.print_stack()
        extra = dict(kwargs.get("extra") or {})
        extra["passed_error_type"] = exception_type.__name__
        kwargs["extra"] = extra

    # Log using the standard logging implementation
    super().error(msg, *args, **kwargs)

    sys.exit(1)

get_formatted_logger(name: Optional[str] = 'Main', level: Literal['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'] = 'INFO') -> logging.Logger

This function returns a logger instance with the specified name and the given loglevel.

Parameters:
  • name (Optional[str], default: "Main" ) –

    Name of the logger. When None is provided, the root logger is returned.

  • level (Literal['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], default: "INFO" ) –

    Level to which the logger will be initialized. This level is ignored if the logger already exists and has a level set.

Returns:
  • Logger –

    A logger instance.

Examples:

>>> logger = get_formatted_logger(name="test_logger", level="DEBUG")
>>> logger.info("Model training completed!")
Source code in aidevelopementtoolkit/logging_utils/logger.py
 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
def get_formatted_logger(
        name: Optional[str] = "Main", 
        level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "INFO",
    ) -> logging.Logger:
    """This function returns a logger instance with the specified name and the
    given loglevel.

    Parameters
    ----------
    name : Optional[str], default="Main"
        Name of the logger. When `None` is provided, the root logger is returned.

    level : Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], default="INFO"
        Level to which the logger will be initialized. **This level is ignored 
        if the logger already exists and has a level set**.

    Returns
    -------
    logging.Logger
        A logger instance.

    Examples
    --------
    >>> logger = get_formatted_logger(name="test_logger", level="DEBUG")
    >>> logger.info("Model training completed!")
    """

    # Set logger class
    logging.setLoggerClass(CustomLogger)

    # Set logger
    logger = logging.getLogger(name)

    # If the logger already has handlers, we don't want to add another one.
    if logger.handlers:
        return logger

    handler = logging.StreamHandler()

    # Set formatter
    formatter = ColorFormatter(
        "%(name)s %(asctime)s %(levelname)s %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S"
    )
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    # Set log level
    logger.setLevel(getattr(logging, level))

    return logger