Module mbed_tools_lib.logging

Helpers for logging errors according to severity of the exception.

Expand source code
#
# Copyright (C) 2020 Arm Mbed. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
"""Helpers for logging errors according to severity of the exception."""
from typing import Type, Optional, cast
from types import TracebackType
import logging
from mbed_tools_lib.exceptions import ToolsError

LOGGING_FORMAT = "%(levelname)s: %(message)s"

VERBOSITY_HELP = {
    logging.CRITICAL: "-v",
    logging.ERROR: "-v",
    logging.WARNING: "-vv",
    logging.INFO: "-vvv",
    logging.DEBUG: "--traceback",
}


def _exception_message(err: BaseException, log_level: int, traceback: bool) -> str:
    """Generate a user facing message with help on how to get more information from the logs."""
    error_msg = str(err)
    if log_level != logging.DEBUG or not traceback:
        cli_option = VERBOSITY_HELP.get(log_level, "-v")
        error_msg += f"\n\nMore information may be available by using the command line option '{cli_option}'."
    return error_msg


class MbedToolsHandler:
    """Context Manager to catch Mbed Tools exceptions and generate a helpful user facing message."""

    def __init__(self, logger: logging.Logger, traceback: bool = False):
        """Keep track of the logger to use and whether or not a traceback should be generated."""
        self._logger = logger
        self._traceback = traceback

    def __enter__(self) -> "MbedToolsHandler":
        """Return the Context Manager."""
        return self

    def __exit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_value: Optional[BaseException],
        exc_traceback: Optional[TracebackType],
    ) -> bool:
        """Handle any raised exceptions, suppressing Tools errors and generating an error message instead."""
        if exc_type and issubclass(exc_type, ToolsError):
            error_msg = _exception_message(cast(BaseException, exc_value), logging.root.level, self._traceback)
            self._logger.error(error_msg, exc_info=self._traceback)
            # Do not propagate exceptions derived from ToolsError
            return True

        # Propagate all other exceptions
        return False


def log_exception(logger: logging.Logger, exception: Exception, show_traceback: bool = False) -> None:
    """Logs an exception in both normal and verbose forms.

    Args:
        logger: logger
        exception: exception to log
        show_traceback: show the full traceback.
    """
    logger.error(exception, exc_info=show_traceback)


def set_log_level(verbose_count: int) -> None:
    """Sets the log level.

    Args:
        verbose_count: number of `-v` flags used
    """
    if verbose_count > 2:
        log_level = logging.DEBUG
    elif verbose_count == 2:
        log_level = logging.INFO
    elif verbose_count == 1:
        log_level = logging.WARNING
    else:
        log_level = logging.ERROR
    logging.basicConfig(level=log_level, format=LOGGING_FORMAT)

Functions

def log_exception(logger: logging.Logger, exception: Exception, show_traceback: bool = False) -> NoneType

Logs an exception in both normal and verbose forms.

Args

logger
logger
exception
exception to log
show_traceback
show the full traceback.
Expand source code
def log_exception(logger: logging.Logger, exception: Exception, show_traceback: bool = False) -> None:
    """Logs an exception in both normal and verbose forms.

    Args:
        logger: logger
        exception: exception to log
        show_traceback: show the full traceback.
    """
    logger.error(exception, exc_info=show_traceback)
def set_log_level(verbose_count: int) -> NoneType

Sets the log level.

Args

verbose_count
number of -v flags used
Expand source code
def set_log_level(verbose_count: int) -> None:
    """Sets the log level.

    Args:
        verbose_count: number of `-v` flags used
    """
    if verbose_count > 2:
        log_level = logging.DEBUG
    elif verbose_count == 2:
        log_level = logging.INFO
    elif verbose_count == 1:
        log_level = logging.WARNING
    else:
        log_level = logging.ERROR
    logging.basicConfig(level=log_level, format=LOGGING_FORMAT)

Classes

class MbedToolsHandler (logger: logging.Logger, traceback: bool = False)

Context Manager to catch Mbed Tools exceptions and generate a helpful user facing message.

Keep track of the logger to use and whether or not a traceback should be generated.

Expand source code
class MbedToolsHandler:
    """Context Manager to catch Mbed Tools exceptions and generate a helpful user facing message."""

    def __init__(self, logger: logging.Logger, traceback: bool = False):
        """Keep track of the logger to use and whether or not a traceback should be generated."""
        self._logger = logger
        self._traceback = traceback

    def __enter__(self) -> "MbedToolsHandler":
        """Return the Context Manager."""
        return self

    def __exit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_value: Optional[BaseException],
        exc_traceback: Optional[TracebackType],
    ) -> bool:
        """Handle any raised exceptions, suppressing Tools errors and generating an error message instead."""
        if exc_type and issubclass(exc_type, ToolsError):
            error_msg = _exception_message(cast(BaseException, exc_value), logging.root.level, self._traceback)
            self._logger.error(error_msg, exc_info=self._traceback)
            # Do not propagate exceptions derived from ToolsError
            return True

        # Propagate all other exceptions
        return False