Skip to content

config_classes

The 'secret sauce' of the logging module.

These classes serve as configuration containers for various logging objects, like formatters, handlers, and loggers. Each class inherits from a "base" configuration, which has a .get_configdict() method. So for each formatter, handler, or logger, you can use .get_configdict() to return a dict representation of the class's configuration, which is compatible with the logging dictConfig.

These dicts must be added to the configuration using the .assemble_configdict() method in logging_utils(). The classes exist to aid in creating formatters, handlers, and loggers for a logging configuration by presenting all available options.

FileHandlerConfig dataclass

Bases: BaseHandlerConfig

Define a logging FileHandler.

Parameters:

Name Type Description Default
filename str

The name of the file to log messages to.

'app.log'
Source code in src/red_logging/config_classes/handlers/_handlers.py
@dataclass
class FileHandlerConfig(BaseHandlerConfig):
    """Define a logging FileHandler.

    Params:
        filename (str): The name of the file to log messages to.
    """

    filename: str | None = field(default="app.log")

    def get_configdict(self) -> dict[str, dict[str, str]]:
        """Return a dict representation of the handler described by this class."""
        handler_dict: dict[str, dict[str, str]] = {
            self.name: {
                "class": self.get_handler_class(),
                "level": self.level,
                "formatter": self.formatter,
                "filename": self.filename,
            }
        }
        return handler_dict

    def get_handler_class(self) -> str:
        """Return the logging handler class this class represents.

        Returns:
            (str): `logging.FileHandler`.

        """
        return "logging.FileHandler"

get_configdict()

Return a dict representation of the handler described by this class.

Source code in src/red_logging/config_classes/handlers/_handlers.py
def get_configdict(self) -> dict[str, dict[str, str]]:
    """Return a dict representation of the handler described by this class."""
    handler_dict: dict[str, dict[str, str]] = {
        self.name: {
            "class": self.get_handler_class(),
            "level": self.level,
            "formatter": self.formatter,
            "filename": self.filename,
        }
    }
    return handler_dict

get_handler_class()

Return the logging handler class this class represents.

Returns:

Type Description
str

logging.FileHandler.

Source code in src/red_logging/config_classes/handlers/_handlers.py
def get_handler_class(self) -> str:
    """Return the logging handler class this class represents.

    Returns:
        (str): `logging.FileHandler`.

    """
    return "logging.FileHandler"

FormatterConfig dataclass

Bases: BaseLoggingConfig

Define a logging formatter.

Parameters:

Name Type Description Default
name str

The name of the formatter.

None
fmt str

The string formatting to use for log messages.

MESSAGE_FMT_STANDARD
datefmt str

The string formatting to use for log message timestamps.

DATE_FMT_STANDARD
style str

The string substitution style to use for log formats. Default is %, which means formats need to be written like %(asctime)s %(levelname)s %(message)s. If you change this style, make sure the fmt you pass uses the correct formatting style.

'%'
validate bool

When True, the configuration dict this formatter returns will be validated by the logging module.

True
Source code in src/red_logging/config_classes/formatters/_formatters.py
@dataclass
class FormatterConfig(BaseLoggingConfig):
    """Define a logging formatter.

    Params:
        name (str): The name of the formatter.
        fmt (str): The string formatting to use for log messages.
        datefmt (str): The string formatting to use for log message timestamps.
        style (str): The string substitution style to use for log formats. Default is `%`, which
            means formats need to be written like `%(asctime)s %(levelname)s %(message)s`. If
            you change this style, make sure the `fmt` you pass uses the correct formatting style.
        validate (bool): When `True`, the configuration dict this formatter returns will be validated by the logging module.

    """

    name: str = None
    fmt: str = MESSAGE_FMT_STANDARD
    datefmt: str = DATE_FMT_STANDARD
    style: str = "%"
    validate: bool = True

    def get_configdict(self) -> dict[str, dict[str, str]]:
        """Return a dict representation of the formatter described by this class."""
        formatter_dict: dict[str, dict[str, str]] = {self.name: {"format": self.fmt}}
        if self.datefmt:
            formatter_dict[self.name]["datefmt"] = self.datefmt
        if self.style:
            formatter_dict[self.name]["style"] = self.style
        formatter_dict[self.name]["validate"] = self.validate

        return formatter_dict

get_configdict()

Return a dict representation of the formatter described by this class.

Source code in src/red_logging/config_classes/formatters/_formatters.py
def get_configdict(self) -> dict[str, dict[str, str]]:
    """Return a dict representation of the formatter described by this class."""
    formatter_dict: dict[str, dict[str, str]] = {self.name: {"format": self.fmt}}
    if self.datefmt:
        formatter_dict[self.name]["datefmt"] = self.datefmt
    if self.style:
        formatter_dict[self.name]["style"] = self.style
    formatter_dict[self.name]["validate"] = self.validate

    return formatter_dict

LoggerConfig dataclass

Bases: BaseLoggingConfig

Define a logging Logger.

Parameters:

Name Type Description Default
name str

The name of the logger.

required
level str

The level of log messages this logger should show (NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL).

required
handlers list[str]

List of handler names this logger should use. These handlers must exist in the logging dictConfig.

required
propagate bool

If True, messages will be propagated up/down to the root logger.

False
Source code in src/red_logging/config_classes/loggers/_loggers.py
@dataclass
class LoggerConfig(BaseLoggingConfig):
    """Define a logging Logger.

    Params:
        name (str): The name of the logger.
        level (str): The level of log messages this logger should show (NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL).
        handlers (list[str]): List of handler names this logger should use. These handlers must exist in the logging dictConfig.
        propagate (bool): If `True`, messages will be propagated up/down to the root logger.
    """

    name: str
    level: str
    handlers: list[str]
    propagate: bool = False

    def get_configdict(self) -> dict:
        """Return a dict representation of the logger described by this class."""
        logger_dict: dict[str, dict[str, t.Any]] = {
            self.name: {
                "level": self.level,
                "handlers": self.handlers,
                "propagate": self.propagate,
            }
        }
        return logger_dict

get_configdict()

Return a dict representation of the logger described by this class.

Source code in src/red_logging/config_classes/loggers/_loggers.py
def get_configdict(self) -> dict:
    """Return a dict representation of the logger described by this class."""
    logger_dict: dict[str, dict[str, t.Any]] = {
        self.name: {
            "level": self.level,
            "handlers": self.handlers,
            "propagate": self.propagate,
        }
    }
    return logger_dict

LoggerFactory

Generate loggers based on LoggerFactory's config.

Source code in src/red_logging/config_classes/loggers/_factory.py
class LoggerFactory:
    """Generate loggers based on LoggerFactory's config."""

    _LOG: logging.Logger | None = None

    @staticmethod
    def __create_logger(
        name: str,
        log_level: str,
        handlers: dict[str, dict],
        formatters: dict[str, dict],
        loggers: dict[str, dict],
    ) -> logging.Logger:
        """Create a logger cnofig from inputs.

        Params:
            name (str): The name of the logger.
            log_level (str): The log levels to show (NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL).
            handlers (dict[str, dict[str, Any]]): A dict describing the handlers for this logger config.
            formatters (dict[str, dict[str, Any]]): A dict describing the formatters for this logger config.
            loggers (dict[str, dict[str, Any]]): A dict describing the loggers for this logger config.
        """
        log_level = log_level.upper()

        # Configure logging using dictConfig
        logging_config = {
            "version": 1,
            "handlers": handlers,
            "formatters": formatters,
            "loggers": loggers,
            "root": {
                "level": log_level,
                "handlers": list(handlers.keys()),
            },
        }

        try:
            logging.config.dictConfig(logging_config)
        except Exception as exc:
            msg = Exception(f"Unhandled exception configuring logger. Details: {exc}")
            # log.error(msg)

            raise msg

        # Get or create logger
        LoggerFactory._LOG = logging.getLogger(name)

        return LoggerFactory._LOG

    @staticmethod
    def get_logger(
        name: str,
        log_level: str,
        handlers: dict[str, dict],
        formatters: dict[str, dict],
        loggers: dict[str, dict],
    ) -> logging.Logger:
        """Initialize a logger.

        Params:
            name (str): The name of the logger.
            log_level (str): The log levels to show (NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL).
            handlers (dict[str, dict[str, Any]]): A dict describing the handlers for this logger config.
            formatters (dict[str, dict[str, Any]]): A dict describing the formatters for this logger config.
            loggers (dict[str, dict[str, Any]]): A dict describing the loggers for this logger config.
        """
        logger = LoggerFactory.__create_logger(
            name=name,
            log_level=log_level,
            handlers=handlers,
            formatters=formatters,
            loggers=loggers,
        )

        return logger

get_logger(name, log_level, handlers, formatters, loggers) staticmethod

Initialize a logger.

Parameters:

Name Type Description Default
name str

The name of the logger.

required
log_level str

The log levels to show (NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL).

required
handlers dict[str, dict[str, Any]]

A dict describing the handlers for this logger config.

required
formatters dict[str, dict[str, Any]]

A dict describing the formatters for this logger config.

required
loggers dict[str, dict[str, Any]]

A dict describing the loggers for this logger config.

required
Source code in src/red_logging/config_classes/loggers/_factory.py
@staticmethod
def get_logger(
    name: str,
    log_level: str,
    handlers: dict[str, dict],
    formatters: dict[str, dict],
    loggers: dict[str, dict],
) -> logging.Logger:
    """Initialize a logger.

    Params:
        name (str): The name of the logger.
        log_level (str): The log levels to show (NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL).
        handlers (dict[str, dict[str, Any]]): A dict describing the handlers for this logger config.
        formatters (dict[str, dict[str, Any]]): A dict describing the formatters for this logger config.
        loggers (dict[str, dict[str, Any]]): A dict describing the loggers for this logger config.
    """
    logger = LoggerFactory.__create_logger(
        name=name,
        log_level=log_level,
        handlers=handlers,
        formatters=formatters,
        loggers=loggers,
    )

    return logger

RotatingFileHandlerConfig dataclass

Bases: BaseHandlerConfig

Define a logging RotatingFileHandler.

Parameters:

Name Type Description Default
filename str | None

The name/path of the file to log messages to.

'app.log'
maxBytes int

The maximum size of the file (in bytes) before a new file is rotated.

0
backupCount int

Number of rotated log files to keep.

0
Source code in src/red_logging/config_classes/handlers/_handlers.py
@dataclass
class RotatingFileHandlerConfig(BaseHandlerConfig):
    """Define a logging RotatingFileHandler.

    Params:
        filename (str | None): The name/path of the file to log messages to.
        maxBytes (int): The maximum size of the file (in bytes) before a new file is rotated.
        backupCount (int): Number of rotated log files to keep.

    """

    filename: str | None = field(default="app.log")
    maxBytes: int = 0
    backupCount: int = 0

    def get_configdict(self) -> dict[str, dict[str, t.Any]]:
        """Return a dict representation of the handler described by this class."""
        handler_dict: dict[str, dict[str, t.Any]] = {
            self.name: {
                "class": self.get_handler_class(),
                "level": self.level,
                "formatter": self.formatter,
                "filename": f"{self.filename}",
                "maxBytes": self.maxBytes,
                "backupCount": self.backupCount,
            }
        }
        return handler_dict

    def get_handler_class(self) -> str:
        """Return the logging handler class this class represents.

        Returns:
            (str): `logging.RotatingFileHandler`.

        """
        return "logging.handlers.RotatingFileHandler"

get_configdict()

Return a dict representation of the handler described by this class.

Source code in src/red_logging/config_classes/handlers/_handlers.py
def get_configdict(self) -> dict[str, dict[str, t.Any]]:
    """Return a dict representation of the handler described by this class."""
    handler_dict: dict[str, dict[str, t.Any]] = {
        self.name: {
            "class": self.get_handler_class(),
            "level": self.level,
            "formatter": self.formatter,
            "filename": f"{self.filename}",
            "maxBytes": self.maxBytes,
            "backupCount": self.backupCount,
        }
    }
    return handler_dict

get_handler_class()

Return the logging handler class this class represents.

Returns:

Type Description
str

logging.RotatingFileHandler.

Source code in src/red_logging/config_classes/handlers/_handlers.py
def get_handler_class(self) -> str:
    """Return the logging handler class this class represents.

    Returns:
        (str): `logging.RotatingFileHandler`.

    """
    return "logging.handlers.RotatingFileHandler"

StreamHandlerConfig dataclass

Bases: BaseHandlerConfig

Define a logging StreamHandler.

Parameters:

Name Type Description Default
stream Any

The stream this handler controls, i.e. ext://sys.stdout, ext://sys.stderr, etc.

'ext://sys.stdout'
Source code in src/red_logging/config_classes/handlers/_handlers.py
@dataclass
class StreamHandlerConfig(BaseHandlerConfig):
    """Define a logging StreamHandler.

    Params:
        stream (Any): The stream this handler controls, i.e. `ext://sys.stdout`, `ext://sys.stderr`, etc.
    """

    level: str = "DEBUG"
    stream: t.Any | None = "ext://sys.stdout"

    def get_configdict(self) -> dict[str, dict[str, str]]:
        """Return a dict representation of the handler described by this class."""
        handler_dict: dict[str, dict[str, str]] = {
            self.name: {
                "class": self.get_handler_class(),
                "level": self.level,
                "formatter": self.formatter,
                "stream": self.stream,
            }
        }
        if self.filters:
            handler_dict["filters"] = self.filters
        return handler_dict

    def get_handler_class(self) -> str:
        """Return the logging handler class this class represents.

        Returns:
            (str): `logging.StreamHandler`.

        """
        return "logging.StreamHandler"

get_configdict()

Return a dict representation of the handler described by this class.

Source code in src/red_logging/config_classes/handlers/_handlers.py
def get_configdict(self) -> dict[str, dict[str, str]]:
    """Return a dict representation of the handler described by this class."""
    handler_dict: dict[str, dict[str, str]] = {
        self.name: {
            "class": self.get_handler_class(),
            "level": self.level,
            "formatter": self.formatter,
            "stream": self.stream,
        }
    }
    if self.filters:
        handler_dict["filters"] = self.filters
    return handler_dict

get_handler_class()

Return the logging handler class this class represents.

Returns:

Type Description
str

logging.StreamHandler.

Source code in src/red_logging/config_classes/handlers/_handlers.py
def get_handler_class(self) -> str:
    """Return the logging handler class this class represents.

    Returns:
        (str): `logging.StreamHandler`.

    """
    return "logging.StreamHandler"

get_red_logging_console_handler(name='red_logging_console', level='DEBUG', formatter='red_logging', filters=None)

Return an initialized StreamHandlerConfig for the red_logging library.

Parameters:

Name Type Description Default
name str

The name of the handler, which you will reference in a logger config.

'red_logging_console'
level str

The log level for the handler (NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL).

'DEBUG'
formatter str

The name of the formatter to use. This formatter must exist in the logging dictConfig, and can be generated with a FormatterConfig.

'red_logging'
filters list[str] | None

Optional list of filter function names to apply to the handler.

None

Returns:

Type Description
StreamHandlerConfig

An initialized StreamHandlerConfig class.

Source code in src/red_logging/config_classes/prefab/third_party/prefab_red_logging/_configs.py
def get_red_logging_console_handler(
    name: str = "red_logging_console",
    level: str = "DEBUG",
    formatter: str = "red_logging",
    filters: list[str] | None = None,
) -> StreamHandlerConfig:
    """Return an initialized StreamHandlerConfig for the red_logging library.

    Params:
        name (str): The name of the handler, which you will reference in a logger config.
        level (str): The log level for the handler (NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL).
        formatter (str): The name of the formatter to use. This formatter must exist in the logging dictConfig,
            and can be generated with a FormatterConfig.
        filters (list[str]|None): Optional list of filter function names to apply to the handler.

    Returns:
        (StreamHandlerConfig): An initialized StreamHandlerConfig class.

    """
    try:
        _handler: StreamHandlerConfig = StreamHandlerConfig(
            name=name, level=level.upper(), formatter=formatter, filters=filters
        )

        return _handler

    except Exception as exc:
        msg = Exception(
            f"Unhandled exception getting red_logging StreamHandlerConfig. Details: {exc}"
        )
        log.error(msg)

        raise exc

get_red_logging_formatter(name='red_logging', fmt=red_logging_FMT, datefmt=DATE_FMT_STANDARD)

Return a pre-configured FormatterConfig for the red_logging library.

Parameters:

Name Type Description Default
name str

The name of the formatter, which you will reference in a handler config.

'red_logging'
fmt str

The log message format string.

red_logging_FMT
datefmt str

The format for timestamps in log messages.

DATE_FMT_STANDARD

Returns:

Type Description
FormatterConfig

An initialized FormatterConfig class

Source code in src/red_logging/config_classes/prefab/third_party/prefab_red_logging/_configs.py
def get_red_logging_formatter(
    name: str = "red_logging", fmt: str = red_logging_FMT, datefmt: str = DATE_FMT_STANDARD
) -> FormatterConfig:
    """Return a pre-configured FormatterConfig for the red_logging library.

    Params:
        name (str): The name of the formatter, which you will reference in a handler config.
        fmt (str): The log message format string.
        datefmt (str): The format for timestamps in log messages.

    Returns:
        (FormatterConfig): An initialized FormatterConfig class

    """
    try:
        _formatter: FormatterConfig = get_formatter_config(
            name=name, fmt=fmt, datefmt=datefmt
        )

        return _formatter

    except Exception as exc:
        msg = Exception(
            f"Unhandled exception getting red_logging FormatterConfig. Details: {exc}"
        )
        log.error(msg)

        raise exc

get_red_logging_logger(name='red_logging', handlers=['red_logging_console'], level='WARNING', propagate=False)

Return an initialized LoggerConfig for the red_logging library.

Parameters:

Name Type Description Default
name str

The name of the logger, which you will reference in a logging config dict.

'red_logging'
handlers list[str]

A list of handler names for the logger. These loggers must exist in the dictConfig.

['red_logging_console']
level str

The log level for the handler (NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL).

'WARNING'
propagate bool

If False, logs from this logger will not be propagated down/up to the root logger.

False

Returns:

Type Description
LoggerConfig

An initialized LoggerConfig class.

Source code in src/red_logging/config_classes/prefab/third_party/prefab_red_logging/_configs.py
def get_red_logging_logger(
    name: str = "red_logging",
    handlers: list[str] = ["red_logging_console"],
    level: str = "WARNING",
    propagate: bool = False,
) -> LoggerConfig:
    """Return an initialized LoggerConfig for the red_logging library.

    Params:
        name (str): The name of the logger, which you will reference in a logging config dict.
        handlers (list[str]): A list of handler names for the logger. These loggers must exist in the dictConfig.
        level (str): The log level for the handler (NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL).
        propagate (bool): If `False`, logs from this logger will not be propagated down/up to the root logger.

    Returns:
        (LoggerConfig): An initialized LoggerConfig class.

    """
    try:
        _logger: LoggerConfig = get_logger_config(
            name=name, handlers=handlers, level=level.upper(), propagate=propagate
        )

        return _logger

    except Exception as exc:
        msg = Exception(
            f"Unhandled exception getting red_logging LoggerConfig. Details: {exc}"
        )
        log.error(msg)

        raise exc