log9er.logger

  1import os
  2import logging
  3from logging.handlers import RotatingFileHandler, SysLogHandler
  4
  5
  6class Logger(object):
  7    """A basic logger supporting stderr, syslog, and rotating local file logging.
  8
  9    Attributes:
 10        debug (bool): If True, traceback is logged when `exception=True`.
 11        logger (logging.Logger | None): The underlying logger instance, if already provided
 12            or created in `__init__`.
 13    """
 14
 15    debug : bool = False
 16    logger : logging.Logger | None = None
 17
 18    # Default rotating file handler settings
 19    max_bytes : int = 10485760
 20    backup_count : int = 5
 21
 22    level_map : dict[str, int] = {
 23        "DEBUG": logging.DEBUG,
 24        "INFO": logging.INFO,
 25        "WARNING": logging.WARNING,
 26        "ERROR": logging.ERROR,
 27        "CRITICAL": logging.CRITICAL,
 28    }
 29
 30    def __init__(
 31            self,
 32            name : str = "",
 33            log : str = "syslog",
 34            level : int | str = logging.INFO,
 35            debug : bool = False,
 36            propagate : bool = False,
 37            max_bytes : int | None = None,
 38            backup_count : int | None = None,
 39            logger : logging.Logger | None = None
 40    ):
 41        """Initializes the Logger.
 42
 43        The `Logger` class provides a flexible interface for logging messages to various
 44        backends (such as syslog, file-based logging, or stderr) with customizable
 45        log levels. If an existing `logging.Logger` instance is provided, all other
 46        initialization parameters (except `debug`) are ignored.
 47
 48        Args:
 49            name (str): The name to assign to the logger instance. Required unless an
 50                external `logger` is provided.
 51            log (str): The log output destination. For example, `"syslog"` or a file path.
 52                If `"stderr"`, logs go to standard output.
 53            level (int | str): The default logging level. Can be a string
 54                (e.g., `"INFO"`) or an integer constant from the `logging` module
 55                (e.g., `logging.INFO`).
 56            debug (bool): If True, enable traceback logging when `exception=True`.
 57            propagate (bool): Whether log records should propagate to the root logger.
 58                If True, the root logger also processes these messages (default: False).
 59            max_bytes (int | None): If provided, and if `log` is a file path, use as the
 60                `maxBytes` for the `RotatingFileHandler` (default: 10485760).
 61            backup_count (int | None): If provided, and if `log` is a file path, use as
 62                the `backup_count` for the `RotatingFileHandler` (default: 5).
 63            logger (logging.Logger | None): If provided, use this logger instance directly
 64                and ignore other arguments (except `debug`).
 65
 66        Raises:
 67            TypeError: If `logger` is provided but is not an instance of `logging.Logger`.
 68            ValueError: If `level` is an invalid log level string.
 69            FileNotFoundError: If `log` is a file path and its directory does not exist.
 70            OSError: If `log="syslog"` but `/dev/log` is not available on this system.
 71        """
 72
 73        self.debug = debug
 74
 75        # Logger provided? Then ignore other arguments
 76        if logger is not None:
 77            if not isinstance(logger, logging.Logger):
 78                raise TypeError(
 79                    f"'logger' must be a 'logging.Logger' instance, not {type(logger)}"
 80                )
 81
 82            self.logger = logger
 83            return
 84
 85        # No logger provided, so 'name' is required
 86        if not name:
 87            raise ValueError("'name' is required unless an external 'logger' is provided")
 88
 89        # Otherwise create a new logger from args
 90        if isinstance(max_bytes, int):
 91            self.max_bytes = max_bytes
 92        if isinstance(backup_count, int):
 93            self.backup_count = backup_count
 94
 95        self._init_logger(name, log, level, propagate)
 96
 97    def _init_logger(
 98        self,
 99        name: str,
100        log: str,
101        level: int | str,
102        propagate: bool
103    ) -> None:
104        """
105        Internal helper to create and configure a new logger.
106        Raises FileNotFoundError, OSError, or ValueError if invalid arguments.
107        """
108
109        # If log is a file path, ensure the directory exists
110        if log not in ["stderr", "syslog"]:
111            dirpath = os.path.dirname(log)
112            if not os.path.isdir(dirpath):
113                raise FileNotFoundError(f"Log file directory not found: {dirpath}")
114
115        # Check syslog support
116        if log == "syslog" and not os.path.exists("/dev/log"):
117            raise OSError("This system does not support 'syslog' logging.")
118
119        # If level is a string, map it to a logging.* constant
120        if isinstance(level, str):
121            level = level.upper()
122            if level not in self.level_map:
123                raise ValueError(f"Invalid log level '{level}'")
124            level = self.level_map[level]
125
126        # Logger already has handlers? Then let sleeping dogs lie
127        logger = logging.getLogger(name)
128        if logger.hasHandlers():
129            self.logger = logger
130            return
131
132        # OK safe to make the logger, now...
133        logger.propagate = propagate
134        logger.setLevel(level)
135
136        datefmt = "%b %d %H:%M:%S"
137        msgfmt = "%(asctime)s %(name)s[%(process)s]: [%(levelname)s] %(message)s"
138
139        # Select a formatter
140        if log == "stderr":
141            formatter = ErrorColorFormatter(fmt=msgfmt, datefmt=datefmt)
142        else:
143            formatter = logging.Formatter(msgfmt, datefmt=datefmt)
144
145        # Select a handler
146        if log == "stderr":
147            handler = logging.StreamHandler()
148        elif log == "syslog":
149            handler = SysLogHandler(address="/dev/log")
150        else:
151            # Rotating file
152            handler = RotatingFileHandler(
153                log, maxBytes=self.max_bytes, backupCount=self.max_bytes
154            )
155
156        handler.setFormatter(formatter)
157        logger.addHandler(handler)
158
159        self.logger = logger
160
161    def log(
162        self,
163        *msgs : str,
164        level : int | str = logging.INFO,
165        exception : bool = False,
166        prefix : str | None = None
167    ) -> None:
168        """Logs one or more messages at the specified level.
169
170        If multiple messages are passed, they are joined with a newline+tab ("\n\t").
171        If `exception=True`, the messages are prefixed with "Exception:" and a traceback
172        is logged if `debug=True`. If a `prefix` string is provided, it is inserted in
173        square brackets before the message text.
174
175        Args:
176            *msgs (str): One or more strings to log, e.g. `"Hello"`, `"World"`.
177            level (int | str): The log level (e.g., `logging.INFO` or `"INFO"`). Defaults
178                to `logging.INFO`.
179            exception (bool): If True, prefix with "Exception:" and log a traceback if
180                `self.debug` is also True.
181            prefix (str | None): Optional prefix label. If provided, the log message is
182                prefixed with e.g. `"[myfunction] message"`.
183
184        Returns:
185            None
186        """
187
188        # Convert and join all msgs
189        msg = "\n\t".join([str(m) for m in msgs])
190
191        if exception:
192            msg = f"Exception: {msg}"
193
194        if prefix:
195            msg = f"[{prefix}] {msg}"
196
197        # If level is a string, map it to a logging.* constant
198        if not isinstance(level, int) and not isinstance(level, str):
199            raise ValueError(f"Invalid log level '{level}'. Must be `logging` level constant or string.")
200
201        if isinstance(level, str):
202            level = level.upper()
203            if level not in self.level_map:
204                raise ValueError(f"Invalid log level '{level}'")
205            level = self.level_map[level]
206
207        # If we're dealing with an exception and debug is enabled, log with traceback
208        if exception and self.debug:
209            # logger.exception() always logs at ERROR level + traceback
210            self.logger.exception(msg)
211            return
212
213        # Otherwise, if exception=True but debug=False, just log as ERROR without traceback
214        if exception:
215            level = logging.ERROR
216
217        # Log normally at the resolved level
218        if level == logging.DEBUG:
219            self.logger.debug(msg)
220        elif level == logging.INFO:
221            self.logger.info(msg)
222        elif level == logging.WARNING:
223            self.logger.warning(msg)
224        elif level == logging.ERROR:
225            self.logger.error(msg)
226        elif level == logging.FATAL:
227            self.logger.fatal(msg)
228        else:
229            self.logger.log(level, msg)
230
231
232class ErrorColorFormatter(logging.Formatter):
233    """A custom formatter that applies bold red color for ERROR or CRITICAL messages.
234
235    Attributes:
236        BOLD_RED (str): The ANSI escape sequence for bold red text.
237        RESET (str): The ANSI escape sequence to reset color.
238    """
239
240    BOLD_RED = "\x1b[1;31m"
241    RESET = "\x1b[0m"
242
243    def format(self, record: logging.LogRecord) -> str:
244        """Formats a log record.
245
246        If the level is ERROR or CRITICAL, the message is colored in bold red.
247
248        Args:
249            record (logging.LogRecord): The record to format.
250
251        Returns:
252            str: The formatted log message, colored if needed.
253        """
254
255        log_msg = super().format(record)
256        if record.levelno >= logging.ERROR:
257            return f"{self.BOLD_RED}{log_msg}{self.RESET}"
258        return log_msg
class Logger:
  7class Logger(object):
  8    """A basic logger supporting stderr, syslog, and rotating local file logging.
  9
 10    Attributes:
 11        debug (bool): If True, traceback is logged when `exception=True`.
 12        logger (logging.Logger | None): The underlying logger instance, if already provided
 13            or created in `__init__`.
 14    """
 15
 16    debug : bool = False
 17    logger : logging.Logger | None = None
 18
 19    # Default rotating file handler settings
 20    max_bytes : int = 10485760
 21    backup_count : int = 5
 22
 23    level_map : dict[str, int] = {
 24        "DEBUG": logging.DEBUG,
 25        "INFO": logging.INFO,
 26        "WARNING": logging.WARNING,
 27        "ERROR": logging.ERROR,
 28        "CRITICAL": logging.CRITICAL,
 29    }
 30
 31    def __init__(
 32            self,
 33            name : str = "",
 34            log : str = "syslog",
 35            level : int | str = logging.INFO,
 36            debug : bool = False,
 37            propagate : bool = False,
 38            max_bytes : int | None = None,
 39            backup_count : int | None = None,
 40            logger : logging.Logger | None = None
 41    ):
 42        """Initializes the Logger.
 43
 44        The `Logger` class provides a flexible interface for logging messages to various
 45        backends (such as syslog, file-based logging, or stderr) with customizable
 46        log levels. If an existing `logging.Logger` instance is provided, all other
 47        initialization parameters (except `debug`) are ignored.
 48
 49        Args:
 50            name (str): The name to assign to the logger instance. Required unless an
 51                external `logger` is provided.
 52            log (str): The log output destination. For example, `"syslog"` or a file path.
 53                If `"stderr"`, logs go to standard output.
 54            level (int | str): The default logging level. Can be a string
 55                (e.g., `"INFO"`) or an integer constant from the `logging` module
 56                (e.g., `logging.INFO`).
 57            debug (bool): If True, enable traceback logging when `exception=True`.
 58            propagate (bool): Whether log records should propagate to the root logger.
 59                If True, the root logger also processes these messages (default: False).
 60            max_bytes (int | None): If provided, and if `log` is a file path, use as the
 61                `maxBytes` for the `RotatingFileHandler` (default: 10485760).
 62            backup_count (int | None): If provided, and if `log` is a file path, use as
 63                the `backup_count` for the `RotatingFileHandler` (default: 5).
 64            logger (logging.Logger | None): If provided, use this logger instance directly
 65                and ignore other arguments (except `debug`).
 66
 67        Raises:
 68            TypeError: If `logger` is provided but is not an instance of `logging.Logger`.
 69            ValueError: If `level` is an invalid log level string.
 70            FileNotFoundError: If `log` is a file path and its directory does not exist.
 71            OSError: If `log="syslog"` but `/dev/log` is not available on this system.
 72        """
 73
 74        self.debug = debug
 75
 76        # Logger provided? Then ignore other arguments
 77        if logger is not None:
 78            if not isinstance(logger, logging.Logger):
 79                raise TypeError(
 80                    f"'logger' must be a 'logging.Logger' instance, not {type(logger)}"
 81                )
 82
 83            self.logger = logger
 84            return
 85
 86        # No logger provided, so 'name' is required
 87        if not name:
 88            raise ValueError("'name' is required unless an external 'logger' is provided")
 89
 90        # Otherwise create a new logger from args
 91        if isinstance(max_bytes, int):
 92            self.max_bytes = max_bytes
 93        if isinstance(backup_count, int):
 94            self.backup_count = backup_count
 95
 96        self._init_logger(name, log, level, propagate)
 97
 98    def _init_logger(
 99        self,
100        name: str,
101        log: str,
102        level: int | str,
103        propagate: bool
104    ) -> None:
105        """
106        Internal helper to create and configure a new logger.
107        Raises FileNotFoundError, OSError, or ValueError if invalid arguments.
108        """
109
110        # If log is a file path, ensure the directory exists
111        if log not in ["stderr", "syslog"]:
112            dirpath = os.path.dirname(log)
113            if not os.path.isdir(dirpath):
114                raise FileNotFoundError(f"Log file directory not found: {dirpath}")
115
116        # Check syslog support
117        if log == "syslog" and not os.path.exists("/dev/log"):
118            raise OSError("This system does not support 'syslog' logging.")
119
120        # If level is a string, map it to a logging.* constant
121        if isinstance(level, str):
122            level = level.upper()
123            if level not in self.level_map:
124                raise ValueError(f"Invalid log level '{level}'")
125            level = self.level_map[level]
126
127        # Logger already has handlers? Then let sleeping dogs lie
128        logger = logging.getLogger(name)
129        if logger.hasHandlers():
130            self.logger = logger
131            return
132
133        # OK safe to make the logger, now...
134        logger.propagate = propagate
135        logger.setLevel(level)
136
137        datefmt = "%b %d %H:%M:%S"
138        msgfmt = "%(asctime)s %(name)s[%(process)s]: [%(levelname)s] %(message)s"
139
140        # Select a formatter
141        if log == "stderr":
142            formatter = ErrorColorFormatter(fmt=msgfmt, datefmt=datefmt)
143        else:
144            formatter = logging.Formatter(msgfmt, datefmt=datefmt)
145
146        # Select a handler
147        if log == "stderr":
148            handler = logging.StreamHandler()
149        elif log == "syslog":
150            handler = SysLogHandler(address="/dev/log")
151        else:
152            # Rotating file
153            handler = RotatingFileHandler(
154                log, maxBytes=self.max_bytes, backupCount=self.max_bytes
155            )
156
157        handler.setFormatter(formatter)
158        logger.addHandler(handler)
159
160        self.logger = logger
161
162    def log(
163        self,
164        *msgs : str,
165        level : int | str = logging.INFO,
166        exception : bool = False,
167        prefix : str | None = None
168    ) -> None:
169        """Logs one or more messages at the specified level.
170
171        If multiple messages are passed, they are joined with a newline+tab ("\n\t").
172        If `exception=True`, the messages are prefixed with "Exception:" and a traceback
173        is logged if `debug=True`. If a `prefix` string is provided, it is inserted in
174        square brackets before the message text.
175
176        Args:
177            *msgs (str): One or more strings to log, e.g. `"Hello"`, `"World"`.
178            level (int | str): The log level (e.g., `logging.INFO` or `"INFO"`). Defaults
179                to `logging.INFO`.
180            exception (bool): If True, prefix with "Exception:" and log a traceback if
181                `self.debug` is also True.
182            prefix (str | None): Optional prefix label. If provided, the log message is
183                prefixed with e.g. `"[myfunction] message"`.
184
185        Returns:
186            None
187        """
188
189        # Convert and join all msgs
190        msg = "\n\t".join([str(m) for m in msgs])
191
192        if exception:
193            msg = f"Exception: {msg}"
194
195        if prefix:
196            msg = f"[{prefix}] {msg}"
197
198        # If level is a string, map it to a logging.* constant
199        if not isinstance(level, int) and not isinstance(level, str):
200            raise ValueError(f"Invalid log level '{level}'. Must be `logging` level constant or string.")
201
202        if isinstance(level, str):
203            level = level.upper()
204            if level not in self.level_map:
205                raise ValueError(f"Invalid log level '{level}'")
206            level = self.level_map[level]
207
208        # If we're dealing with an exception and debug is enabled, log with traceback
209        if exception and self.debug:
210            # logger.exception() always logs at ERROR level + traceback
211            self.logger.exception(msg)
212            return
213
214        # Otherwise, if exception=True but debug=False, just log as ERROR without traceback
215        if exception:
216            level = logging.ERROR
217
218        # Log normally at the resolved level
219        if level == logging.DEBUG:
220            self.logger.debug(msg)
221        elif level == logging.INFO:
222            self.logger.info(msg)
223        elif level == logging.WARNING:
224            self.logger.warning(msg)
225        elif level == logging.ERROR:
226            self.logger.error(msg)
227        elif level == logging.FATAL:
228            self.logger.fatal(msg)
229        else:
230            self.logger.log(level, msg)

A basic logger supporting stderr, syslog, and rotating local file logging.

Attributes:
  • debug (bool): If True, traceback is logged when exception=True.
  • logger (logging.Logger | None): The underlying logger instance, if already provided or created in __init__.
Logger( name: str = '', log: str = 'syslog', level: int | str = 20, debug: bool = False, propagate: bool = False, max_bytes: int | None = None, backup_count: int | None = None, logger: logging.Logger | None = None)
31    def __init__(
32            self,
33            name : str = "",
34            log : str = "syslog",
35            level : int | str = logging.INFO,
36            debug : bool = False,
37            propagate : bool = False,
38            max_bytes : int | None = None,
39            backup_count : int | None = None,
40            logger : logging.Logger | None = None
41    ):
42        """Initializes the Logger.
43
44        The `Logger` class provides a flexible interface for logging messages to various
45        backends (such as syslog, file-based logging, or stderr) with customizable
46        log levels. If an existing `logging.Logger` instance is provided, all other
47        initialization parameters (except `debug`) are ignored.
48
49        Args:
50            name (str): The name to assign to the logger instance. Required unless an
51                external `logger` is provided.
52            log (str): The log output destination. For example, `"syslog"` or a file path.
53                If `"stderr"`, logs go to standard output.
54            level (int | str): The default logging level. Can be a string
55                (e.g., `"INFO"`) or an integer constant from the `logging` module
56                (e.g., `logging.INFO`).
57            debug (bool): If True, enable traceback logging when `exception=True`.
58            propagate (bool): Whether log records should propagate to the root logger.
59                If True, the root logger also processes these messages (default: False).
60            max_bytes (int | None): If provided, and if `log` is a file path, use as the
61                `maxBytes` for the `RotatingFileHandler` (default: 10485760).
62            backup_count (int | None): If provided, and if `log` is a file path, use as
63                the `backup_count` for the `RotatingFileHandler` (default: 5).
64            logger (logging.Logger | None): If provided, use this logger instance directly
65                and ignore other arguments (except `debug`).
66
67        Raises:
68            TypeError: If `logger` is provided but is not an instance of `logging.Logger`.
69            ValueError: If `level` is an invalid log level string.
70            FileNotFoundError: If `log` is a file path and its directory does not exist.
71            OSError: If `log="syslog"` but `/dev/log` is not available on this system.
72        """
73
74        self.debug = debug
75
76        # Logger provided? Then ignore other arguments
77        if logger is not None:
78            if not isinstance(logger, logging.Logger):
79                raise TypeError(
80                    f"'logger' must be a 'logging.Logger' instance, not {type(logger)}"
81                )
82
83            self.logger = logger
84            return
85
86        # No logger provided, so 'name' is required
87        if not name:
88            raise ValueError("'name' is required unless an external 'logger' is provided")
89
90        # Otherwise create a new logger from args
91        if isinstance(max_bytes, int):
92            self.max_bytes = max_bytes
93        if isinstance(backup_count, int):
94            self.backup_count = backup_count
95
96        self._init_logger(name, log, level, propagate)

Initializes the Logger.

The Logger class provides a flexible interface for logging messages to various backends (such as syslog, file-based logging, or stderr) with customizable log levels. If an existing logging.Logger instance is provided, all other initialization parameters (except debug) are ignored.

Arguments:
  • name (str): The name to assign to the logger instance. Required unless an external logger is provided.
  • log (str): The log output destination. For example, "syslog" or a file path. If "stderr", logs go to standard output.
  • level (int | str): The default logging level. Can be a string (e.g., "INFO") or an integer constant from the logging module (e.g., logging.INFO).
  • debug (bool): If True, enable traceback logging when exception=True.
  • propagate (bool): Whether log records should propagate to the root logger. If True, the root logger also processes these messages (default: False).
  • max_bytes (int | None): If provided, and if log is a file path, use as the maxBytes for the RotatingFileHandler (default: 10485760).
  • backup_count (int | None): If provided, and if log is a file path, use as the backup_count for the RotatingFileHandler (default: 5).
  • logger (logging.Logger | None): If provided, use this logger instance directly and ignore other arguments (except debug).
Raises:
  • TypeError: If logger is provided but is not an instance of logging.Logger.
  • ValueError: If level is an invalid log level string.
  • FileNotFoundError: If log is a file path and its directory does not exist.
  • OSError: If log="syslog" but /dev/log is not available on this system.
debug: bool = False
logger: logging.Logger | None = None
max_bytes: int = 10485760
backup_count: int = 5
level_map: dict[str, int] = {'DEBUG': 10, 'INFO': 20, 'WARNING': 30, 'ERROR': 40, 'CRITICAL': 50}
def log( self, *msgs: str, level: int | str = 20, exception: bool = False, prefix: str | None = None) -> None:
162    def log(
163        self,
164        *msgs : str,
165        level : int | str = logging.INFO,
166        exception : bool = False,
167        prefix : str | None = None
168    ) -> None:
169        """Logs one or more messages at the specified level.
170
171        If multiple messages are passed, they are joined with a newline+tab ("\n\t").
172        If `exception=True`, the messages are prefixed with "Exception:" and a traceback
173        is logged if `debug=True`. If a `prefix` string is provided, it is inserted in
174        square brackets before the message text.
175
176        Args:
177            *msgs (str): One or more strings to log, e.g. `"Hello"`, `"World"`.
178            level (int | str): The log level (e.g., `logging.INFO` or `"INFO"`). Defaults
179                to `logging.INFO`.
180            exception (bool): If True, prefix with "Exception:" and log a traceback if
181                `self.debug` is also True.
182            prefix (str | None): Optional prefix label. If provided, the log message is
183                prefixed with e.g. `"[myfunction] message"`.
184
185        Returns:
186            None
187        """
188
189        # Convert and join all msgs
190        msg = "\n\t".join([str(m) for m in msgs])
191
192        if exception:
193            msg = f"Exception: {msg}"
194
195        if prefix:
196            msg = f"[{prefix}] {msg}"
197
198        # If level is a string, map it to a logging.* constant
199        if not isinstance(level, int) and not isinstance(level, str):
200            raise ValueError(f"Invalid log level '{level}'. Must be `logging` level constant or string.")
201
202        if isinstance(level, str):
203            level = level.upper()
204            if level not in self.level_map:
205                raise ValueError(f"Invalid log level '{level}'")
206            level = self.level_map[level]
207
208        # If we're dealing with an exception and debug is enabled, log with traceback
209        if exception and self.debug:
210            # logger.exception() always logs at ERROR level + traceback
211            self.logger.exception(msg)
212            return
213
214        # Otherwise, if exception=True but debug=False, just log as ERROR without traceback
215        if exception:
216            level = logging.ERROR
217
218        # Log normally at the resolved level
219        if level == logging.DEBUG:
220            self.logger.debug(msg)
221        elif level == logging.INFO:
222            self.logger.info(msg)
223        elif level == logging.WARNING:
224            self.logger.warning(msg)
225        elif level == logging.ERROR:
226            self.logger.error(msg)
227        elif level == logging.FATAL:
228            self.logger.fatal(msg)
229        else:
230            self.logger.log(level, msg)

Logs one or more messages at the specified level.

If multiple messages are passed, they are joined with a newline+tab (" "). If exception=True, the messages are prefixed with "Exception:" and a traceback is logged if debug=True. If a prefix string is provided, it is inserted in square brackets before the message text.

Arguments:
  • *msgs (str): One or more strings to log, e.g. "Hello", "World".
  • level (int | str): The log level (e.g., logging.INFO or "INFO"). Defaults to logging.INFO.
  • exception (bool): If True, prefix with "Exception:" and log a traceback if self.debug is also True.
  • prefix (str | None): Optional prefix label. If provided, the log message is prefixed with e.g. "[myfunction] message".
Returns:

None

class ErrorColorFormatter(logging.Formatter):
233class ErrorColorFormatter(logging.Formatter):
234    """A custom formatter that applies bold red color for ERROR or CRITICAL messages.
235
236    Attributes:
237        BOLD_RED (str): The ANSI escape sequence for bold red text.
238        RESET (str): The ANSI escape sequence to reset color.
239    """
240
241    BOLD_RED = "\x1b[1;31m"
242    RESET = "\x1b[0m"
243
244    def format(self, record: logging.LogRecord) -> str:
245        """Formats a log record.
246
247        If the level is ERROR or CRITICAL, the message is colored in bold red.
248
249        Args:
250            record (logging.LogRecord): The record to format.
251
252        Returns:
253            str: The formatted log message, colored if needed.
254        """
255
256        log_msg = super().format(record)
257        if record.levelno >= logging.ERROR:
258            return f"{self.BOLD_RED}{log_msg}{self.RESET}"
259        return log_msg

A custom formatter that applies bold red color for ERROR or CRITICAL messages.

Attributes:
  • BOLD_RED (str): The ANSI escape sequence for bold red text.
  • RESET (str): The ANSI escape sequence to reset color.
BOLD_RED = '\x1b[1;31m'
RESET = '\x1b[0m'
def format(self, record: logging.LogRecord) -> str:
244    def format(self, record: logging.LogRecord) -> str:
245        """Formats a log record.
246
247        If the level is ERROR or CRITICAL, the message is colored in bold red.
248
249        Args:
250            record (logging.LogRecord): The record to format.
251
252        Returns:
253            str: The formatted log message, colored if needed.
254        """
255
256        log_msg = super().format(record)
257        if record.levelno >= logging.ERROR:
258            return f"{self.BOLD_RED}{log_msg}{self.RESET}"
259        return log_msg

Formats a log record.

If the level is ERROR or CRITICAL, the message is colored in bold red.

Arguments:
  • record (logging.LogRecord): The record to format.
Returns:

str: The formatted log message, colored if needed.