Skip to content

logger

Logger

Wrapper for python Logger to enable inserting logs in fp loops.

This is also so that we may attach context data for a message.

We can access the actual logger by using inst.

Source code in m/log/logger.py
class Logger:  # noqa: WPS230 - loggers have many attributes
    """Wrapper for python Logger to enable inserting logs in fp loops.

    This is also so that we may attach context data for a message.

    We can access the actual logger by using `inst`.
    """

    # pylint: disable=too-many-instance-attributes
    def __init__(self, name: str):
        """Initialize the Logger.

        Args:
            name: The name of a logger.
        """
        self.inst = logging.getLogger(name)
        self.debug = partial(log_func_wrapper, self.inst.debug)
        self.info = partial(log_func_wrapper, self.inst.info)  # noqa: WPS110
        self.warning = partial(log_func_wrapper, self.inst.warning)
        self.exception = partial(log_func_wrapper, self.inst.exception)
        self.critical = partial(log_func_wrapper, self.inst.critical)
        self.log = partial(log_func_wrapper, self.inst.log)
        self.prompt = partial(
            log_func_wrapper,
            cast(PromptLogger, self.inst).prompt,
        )
        self.error = partial(log_func_wrapper, self.inst.error)

    def open_block(
        self,
        name: str,
        description: str,
        stderr: bool = False,
    ) -> Res[int]:
        """Group log lines.

        Signals the formatter that the next log lines should be placed in a
        group.

        Args:
            name: The name of the block to open.
            description: Not supported.
            stderr: Force message to be displayed in stderr.

        Returns:
            A OneOf containing 0 to make it easier to call in fp for loops.
        """
        func = self.inst.error if stderr else self.inst.info
        func(
            'OPEN_BLOCK',
            extra={'open_block': (name, description)},
            stacklevel=2,
        )
        return Good(0)

    def close_block(
        self,
        name: str,
        stderr: bool = False,
    ) -> Res[int]:
        """Close a group log lines.

        Signals the formatter that the current group of lines should end.

        Args:
            name: The name of the block to close.
            stderr: Force message to be displayed in stderr.

        Returns:
            A OneOf containing 0 to make it easier to call in fp for loops.
        """
        func = self.inst.error if stderr else self.inst.info
        func(
            'CLOSE_BLOCK',
            extra={'close_block': name},
            stacklevel=2,
        )
        return Good(0)

    def error_block(
        self,
        msg: str | Message,
        context: dict | Issue,
    ) -> Res[int]:
        """Display an error block.

        Args:
            msg: The error message to display.
            context: The dict/Issue to display in a block.

        Returns:
            A OneOf containing 0 to make it easier to call in fp for loops.
        """
        self.error(msg)
        self.open_block('error', '', stderr=True)
        self.error('', context)
        self.close_block('error', stderr=True)
        return Good(0)

    def waning_block(
        self,
        msg: str | Message,
        context: dict | Issue,
    ) -> Res[int]:
        """Display a warning block.

        Args:
            msg: The warning message to display.
            context: The dict/Issue to display in a block.

        Returns:
            A OneOf containing 0 to make it easier to call in fp for loops.
        """
        self.warning(msg)
        self.open_block('warning', '', stderr=True)
        self.warning('', context)
        self.close_block('warning', stderr=True)
        return Good(0)

__init__(name)

Initialize the Logger.

Parameters:

Name Type Description Default
name str

The name of a logger.

required
Source code in m/log/logger.py
def __init__(self, name: str):
    """Initialize the Logger.

    Args:
        name: The name of a logger.
    """
    self.inst = logging.getLogger(name)
    self.debug = partial(log_func_wrapper, self.inst.debug)
    self.info = partial(log_func_wrapper, self.inst.info)  # noqa: WPS110
    self.warning = partial(log_func_wrapper, self.inst.warning)
    self.exception = partial(log_func_wrapper, self.inst.exception)
    self.critical = partial(log_func_wrapper, self.inst.critical)
    self.log = partial(log_func_wrapper, self.inst.log)
    self.prompt = partial(
        log_func_wrapper,
        cast(PromptLogger, self.inst).prompt,
    )
    self.error = partial(log_func_wrapper, self.inst.error)

close_block(name, stderr=False)

Close a group log lines.

Signals the formatter that the current group of lines should end.

Parameters:

Name Type Description Default
name str

The name of the block to close.

required
stderr bool

Force message to be displayed in stderr.

False

Returns:

Type Description
Res[int]

A OneOf containing 0 to make it easier to call in fp for loops.

Source code in m/log/logger.py
def close_block(
    self,
    name: str,
    stderr: bool = False,
) -> Res[int]:
    """Close a group log lines.

    Signals the formatter that the current group of lines should end.

    Args:
        name: The name of the block to close.
        stderr: Force message to be displayed in stderr.

    Returns:
        A OneOf containing 0 to make it easier to call in fp for loops.
    """
    func = self.inst.error if stderr else self.inst.info
    func(
        'CLOSE_BLOCK',
        extra={'close_block': name},
        stacklevel=2,
    )
    return Good(0)

error_block(msg, context)

Display an error block.

Parameters:

Name Type Description Default
msg str | Message

The error message to display.

required
context dict | Issue

The dict/Issue to display in a block.

required

Returns:

Type Description
Res[int]

A OneOf containing 0 to make it easier to call in fp for loops.

Source code in m/log/logger.py
def error_block(
    self,
    msg: str | Message,
    context: dict | Issue,
) -> Res[int]:
    """Display an error block.

    Args:
        msg: The error message to display.
        context: The dict/Issue to display in a block.

    Returns:
        A OneOf containing 0 to make it easier to call in fp for loops.
    """
    self.error(msg)
    self.open_block('error', '', stderr=True)
    self.error('', context)
    self.close_block('error', stderr=True)
    return Good(0)

open_block(name, description, stderr=False)

Group log lines.

Signals the formatter that the next log lines should be placed in a group.

Parameters:

Name Type Description Default
name str

The name of the block to open.

required
description str

Not supported.

required
stderr bool

Force message to be displayed in stderr.

False

Returns:

Type Description
Res[int]

A OneOf containing 0 to make it easier to call in fp for loops.

Source code in m/log/logger.py
def open_block(
    self,
    name: str,
    description: str,
    stderr: bool = False,
) -> Res[int]:
    """Group log lines.

    Signals the formatter that the next log lines should be placed in a
    group.

    Args:
        name: The name of the block to open.
        description: Not supported.
        stderr: Force message to be displayed in stderr.

    Returns:
        A OneOf containing 0 to make it easier to call in fp for loops.
    """
    func = self.inst.error if stderr else self.inst.info
    func(
        'OPEN_BLOCK',
        extra={'open_block': (name, description)},
        stacklevel=2,
    )
    return Good(0)

waning_block(msg, context)

Display a warning block.

Parameters:

Name Type Description Default
msg str | Message

The warning message to display.

required
context dict | Issue

The dict/Issue to display in a block.

required

Returns:

Type Description
Res[int]

A OneOf containing 0 to make it easier to call in fp for loops.

Source code in m/log/logger.py
def waning_block(
    self,
    msg: str | Message,
    context: dict | Issue,
) -> Res[int]:
    """Display a warning block.

    Args:
        msg: The warning message to display.
        context: The dict/Issue to display in a block.

    Returns:
        A OneOf containing 0 to make it easier to call in fp for loops.
    """
    self.warning(msg)
    self.open_block('warning', '', stderr=True)
    self.warning('', context)
    self.close_block('warning', stderr=True)
    return Good(0)

PromptLogger

Bases: Logger

Adding a prompt level to the logger.

Source code in m/log/logger.py
class PromptLogger(logging.Logger):
    """Adding a prompt level to the logger."""

    def __init__(self, name: str, level: int = logging.NOTSET):
        """Override the Logger init function.

        Args:
            name: Loggers name.
            level: An optional level.
        """
        super().__init__(name, level)
        logging.addLevelName(PROMPT, 'PROMPT')

    def prompt(self, msg: str, *args: Any, **kwargs: Any) -> None:
        """Log 'msg % args' with severity 'PROMPT'.

        Args:
            msg: The message to log
            args: arguments to use in the message replacement.
            kwargs: The keywords arguments to provide extra information.
        """
        if self.isEnabledFor(PROMPT):
            self._log(PROMPT, msg, args, **kwargs)

__init__(name, level=logging.NOTSET)

Override the Logger init function.

Parameters:

Name Type Description Default
name str

Loggers name.

required
level int

An optional level.

NOTSET
Source code in m/log/logger.py
def __init__(self, name: str, level: int = logging.NOTSET):
    """Override the Logger init function.

    Args:
        name: Loggers name.
        level: An optional level.
    """
    super().__init__(name, level)
    logging.addLevelName(PROMPT, 'PROMPT')

prompt(msg, *args, **kwargs)

Log 'msg % args' with severity 'PROMPT'.

Parameters:

Name Type Description Default
msg str

The message to log

required
args Any

arguments to use in the message replacement.

()
kwargs Any

The keywords arguments to provide extra information.

{}
Source code in m/log/logger.py
def prompt(self, msg: str, *args: Any, **kwargs: Any) -> None:
    """Log 'msg % args' with severity 'PROMPT'.

    Args:
        msg: The message to log
        args: arguments to use in the message replacement.
        kwargs: The keywords arguments to provide extra information.
    """
    if self.isEnabledFor(PROMPT):
        self._log(PROMPT, msg, args, **kwargs)

log_func_wrapper(func, msg, context=None, exit_code=0)

Call a logger function with a message and log data.

Parameters:

Name Type Description Default
func Callable

A logger function (logger.info)

required
msg str | Message

A string or Message containing information about the log.

required
context dict | Issue | None

Data describing the log entry.

None
exit_code int

Used in cli context to force an exit. Default to 0.

0

Returns:

Type Description
Res[int]

A OneOf containing 0 to make it easier to call in fp for loops.

Res[int]

May be overwritten when signaling an error.

Source code in m/log/logger.py
def log_func_wrapper(
    func: Callable,
    msg: str | Message,
    context: dict | Issue | None = None,
    exit_code: int = 0,
) -> Res[int]:
    """Call a logger function with a message and log data.

    Args:
        func: A logger function (logger.info)
        msg: A string or Message containing information about the log.
        context: Data describing the log entry.
        exit_code: Used in cli context to force an exit. Default to 0.

    Returns:
        A OneOf containing 0 to make it easier to call in fp for loops.
        May be overwritten when signaling an error.
    """
    if isinstance(msg, str):
        func(msg, extra={'context': context}, stacklevel=2)
    else:
        func(
            msg.msg,
            extra={'context': context, 'ci_info': msg},
            stacklevel=2,
        )
    return Good(exit_code)