Skip to content

typerdrive Logging modules

typerdrive.logging.attach

Provide a decorator that attaches logging functionality to a typer command function.

Attributes

Classes

Functions

attach_logging

attach_logging(
    verbose: bool = False,
) -> Callable[
    [ContextFunction[P, T]], ContextFunction[P, T]
]

Attach a logging functinoality to the decorated typer command function.

Parameters:

Name Type Description Default
verbose bool

A verbose flag passed along to the LoggingManager

False
Source code in src/typerdrive/logging/attach.py
def attach_logging(verbose: bool = False) -> Callable[[ContextFunction[P, T]], ContextFunction[P, T]]:
    """
    Attach a logging functinoality  to the decorated `typer` command function.

    Parameters:
        verbose: A `verbose` flag passed along to the `LoggingManager`
    """
    def _decorate(func: ContextFunction[P, T]) -> ContextFunction[P, T]:
        manager_param_key: str | None = None
        for key in func.__annotations__.keys():
            if func.__annotations__[key] is LoggingManager:
                func.__annotations__[key] = Annotated[LoggingManager | None, CloakingDevice]
                manager_param_key = key

        @wraps(func)
        def wrapper(ctx: typer.Context, *args: P.args, **kwargs: P.kwargs) -> T:
            manager: LoggingManager = LoggingManager(verbose=verbose)
            to_context(ctx, "logging_manager", manager)

            logger.debug("Logging attached to typer context")

            if manager_param_key:
                kwargs[manager_param_key] = manager

            return func(ctx, *args, **kwargs)

        return wrapper

    return _decorate

get_logging_manager

get_logging_manager(ctx: Context) -> LoggingManager

Retrieve the LoggingManager from the TyperdriveContext.

Source code in src/typerdrive/logging/attach.py
def get_logging_manager(ctx: typer.Context) -> LoggingManager:
    """
    Retrieve the `LoggingManager` from the `TyperdriveContext`.
    """
    with LoggingError.handle_errors("Logging is not bound to the context. Use the @attach_logging() decorator"):
        mgr: Any = from_context(ctx, "logging_manager")
    return LoggingError.ensure_type(
        mgr,
        LoggingManager,
        "Item in user context at `logging_manager` was not a LoggingManager",
    )

typerdrive.logging.commands

Provide commands that can be added to a typer app to manage logs.

Classes

Functions

add_audit

add_audit(cli: Typer)

Add the audit command to the given typer app.

Source code in src/typerdrive/logging/commands.py
def add_audit(cli: typer.Typer):
    """
    Add the `audit` command to the given `typer` app.
    """
    cli.command()(audit)

add_clear

add_clear(cli: Typer)

Add the clear command to the given typer app.

Source code in src/typerdrive/logging/commands.py
def add_clear(cli: typer.Typer):
    """
    Add the `clear` command to the given `typer` app.
    """
    cli.command()(clear)

add_logs_subcommand

add_logs_subcommand(cli: Typer)

Add all logs commands to the given app.

Source code in src/typerdrive/logging/commands.py
def add_logs_subcommand(cli: typer.Typer):
    """
    Add all `logs` commands to the given app.
    """
    logs_cli = typer.Typer(help="Manage logs for the app")

    for cmd in [add_clear, add_show, add_audit]:
        cmd(logs_cli)

    cli.add_typer(logs_cli, name="logs")

add_show

add_show(cli: Typer)

Add the show command to the given typer app.

Source code in src/typerdrive/logging/commands.py
def add_show(cli: typer.Typer):
    """
    Add the `show` command to the given `typer` app.
    """
    cli.command()(show)

audit

audit(ctx: Context, manager: LoggingManager)

Show the log files retained for the app.

Source code in src/typerdrive/logging/commands.py
@handle_errors("Failed to audit log dir", handle_exc_class=LoggingError)
@attach_logging()
def audit(ctx: typer.Context, manager: LoggingManager):  # pyright: ignore[reportUnusedParameter]
    """
    Show the log files retained for the app.
    """
    manager.audit()

clear

clear(ctx: Context, manager: LoggingManager)

Clear all the log files.

Source code in src/typerdrive/logging/commands.py
@handle_errors("Failed to clear log dir", handle_exc_class=LoggingError)
@attach_logging()
def clear(ctx: typer.Context, manager: LoggingManager):  # pyright: ignore[reportUnusedParameter]
    """
    Clear all the log files.
    """
    typer.confirm("Are you sure you want to clear all log files from the log directory?", abort=True)
    manager.clear()

show

show(ctx: Context, manager: LoggingManager)

Show the current log.

Source code in src/typerdrive/logging/commands.py
@handle_errors("Failed to show log", handle_exc_class=LoggingError)
@attach_logging()
def show(ctx: typer.Context, manager: LoggingManager):  # pyright: ignore[reportUnusedParameter]
    """
    Show the current log.
    """
    manager.show()

typerdrive.logging.exceptions

Provide exceptions specific to the logging feature of typerdrive.

Classes

LoggingError

Bases: TyperdriveError

The base exception for logging errors.

Source code in src/typerdrive/logging/exceptions.py
class LoggingError(TyperdriveError):
    """
    The base exception for logging errors.
    """
    exit_code: ExitCode = ExitCode.GENERAL_ERROR
Attributes
exit_code class-attribute instance-attribute
exit_code: ExitCode = GENERAL_ERROR

typerdrive.logging.manager

Provide a class for managing the typerdrive logging feature.

Classes

LoggingManager

Manage logs for the typerdrive app.

Source code in src/typerdrive/logging/manager.py
class LoggingManager:
    """
    Manage logs for the `typerdrive` app.
    """

    log_dir: Path
    """ The directory where the logs are stored. """

    log_file: Path
    """ The filename for the log file. """

    def __init__(self, *, verbose: bool = False):
        config: TyperdriveConfig = get_typerdrive_config()

        self.log_dir = config.log_dir
        self.log_file = config.log_dir / config.log_file_name

        handlers: list[dict[str, Any]] = [
            dict(
                sink=str(self.log_file),
                level="DEBUG",
                rotation=config.log_file_rotation,
                retention=config.log_file_retention,
                compression=config.log_file_compression,
            ),
        ]
        if verbose:
            handlers.append(
                dict(
                    sink=sys.stdout,
                    level="DEBUG",
                    format="<green>{time:HH:mm:ss}</green> | <level>{level}</level> | <level>{message}</level>"
                ),
            )

        # Having a hell of a time getting the typing right for `configure()`
        logger.configure(handlers=handlers)  # type: ignore[arg-type]  # pyright: ignore[reportArgumentType]
        logger.enable("typerdrive")

    def show(self):
        """
        Show the current log file.
        """
        console = Console()
        with console.pager(styles=True):
            console.print(self.log_file.read_text())

    def audit(self):
        """
        Show the directory containing the log files.
        """
        show_directory(self.log_dir, subject="Current log files")

    def clear(self):
        """
        Remove all log files.
        """
        clear_directory(self.log_dir)
Attributes
log_dir instance-attribute
log_dir: Path = log_dir

The directory where the logs are stored.

log_file instance-attribute
log_file: Path = log_dir / log_file_name

The filename for the log file.

Functions
__init__
__init__(*, verbose: bool = False)
Source code in src/typerdrive/logging/manager.py
def __init__(self, *, verbose: bool = False):
    config: TyperdriveConfig = get_typerdrive_config()

    self.log_dir = config.log_dir
    self.log_file = config.log_dir / config.log_file_name

    handlers: list[dict[str, Any]] = [
        dict(
            sink=str(self.log_file),
            level="DEBUG",
            rotation=config.log_file_rotation,
            retention=config.log_file_retention,
            compression=config.log_file_compression,
        ),
    ]
    if verbose:
        handlers.append(
            dict(
                sink=sys.stdout,
                level="DEBUG",
                format="<green>{time:HH:mm:ss}</green> | <level>{level}</level> | <level>{message}</level>"
            ),
        )

    # Having a hell of a time getting the typing right for `configure()`
    logger.configure(handlers=handlers)  # type: ignore[arg-type]  # pyright: ignore[reportArgumentType]
    logger.enable("typerdrive")
audit
audit()

Show the directory containing the log files.

Source code in src/typerdrive/logging/manager.py
def audit(self):
    """
    Show the directory containing the log files.
    """
    show_directory(self.log_dir, subject="Current log files")
clear
clear()

Remove all log files.

Source code in src/typerdrive/logging/manager.py
def clear(self):
    """
    Remove all log files.
    """
    clear_directory(self.log_dir)
show
show()

Show the current log file.

Source code in src/typerdrive/logging/manager.py
def show(self):
    """
    Show the current log file.
    """
    console = Console()
    with console.pager(styles=True):
        console.print(self.log_file.read_text())

Functions

typerdrive.logging.utilities

Provide utility functions useful for logging.

Functions

log_error

log_error(params: DoExceptParams)

Log details of an error handled by the @handle_errors decorator.

Parameters:

Name Type Description Default
params DoExceptParams

An instance of DoExceptParams that carries the error details. See the py-byuzz docs for more context.

required
Source code in src/typerdrive/logging/utilities.py
def log_error(params: DoExceptParams):
    """
    Log details of an error handled by the `@handle_errors` decorator.

    Parameters:
        params: An instance of `DoExceptParams` that carries the error details.
                See the [`py-byuzz` docs](https://dusktreader.github.io/py-buzz/reference/#buzz.tools.DoExceptParams)
                for more context.
    """
    logger.error(
        "\n".join(
            [
                strip_rich_style(params.final_message),
                "--------",
                "Traceback:",
                "".join(format_tb(params.trace)),
            ]
        )
    )