Source code for webapp.utils.super_logger

"""
This module provides a easy-to-use class for logging any messages in a systematic manner, using
the built-in 'logging' module and colorama for colored logging. May support connecting to online
logging services such as sentry.io

This is how the different log level colors appear on the terminal/command prompt.

.. image:: images/logger_colors.png

Example:

.. code-block:: python

    logger = SuperLogger.instance()
    logger.debug('CAMERA', 'Camera initialized')
    logger.critical('CORE', 'The robot is feeling emotions!')
"""

import logging
import colorama
from colorama import Fore, Back, Style

[docs]class SuperLogger: """ This class is for managing logging of messages that are scattered throughout the web app. It's handled via a Logger instance, and it's default log level is 'INFO'. :param bool use_color: ``True`` enables the use specific colors for outputting text to the terminal. ``False`` makes the text colors behave as they would normally. """ def __init__(self, use_color=False): self._logger = None self._use_color = use_color @property def use_color(self): """If set to true, then enable colored logging support.""" return self._use_color @use_color.setter def use_color(self, val): self._use_color = val if self._use_color: colorama.init(autoreset=True) else: colorama.deinit()
[docs] def init_logger(self, _logger): """Initialize the logger with an instance of a `logging.Logger` and sets the log level to INFO""" if not isinstance(_logger, logging.Logger): raise TypeError(f"Error: Provided app instance is of type {type(_logger)}, not 'logging.Logger'") self._logger = _logger # create a console stream handler ch = logging.StreamHandler() # modify the formatting of the logs formatter = logging.Formatter( fmt='[%(asctime)s] %(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p' ) ch.setFormatter(formatter) # add the handler to the logger self._logger.addHandler(ch) # set the default logging level to 'INFO' self.set_log_level('INFO')
@property def initialized(self): """Return true only if `SuperLogger.init_logger` was successfully called.""" return isinstance(self._logger, logging.Logger)
[docs] def set_log_level(self, level): """ Set the logger's log level for which any levels below that will be ignored. For example, if the log level is set to 'INFO', all 'DEBUG' messages are ignored. Here's a list of the built-in log levels in descending order: * ``CRITICAL`` * ``ERROR`` * ``WARNING`` * ``INFO`` * ``DEBUG`` * ``NOTSET`` Note that exceptions will always be logged regardless of the log level. """ self._logger.setLevel(level)
[docs] def debug(self, tag, msg): """ Prints a message in the 'debug' channel. This should be used for detailed logging of the internals of a specific module or script such as the number of bytes sent via the camera module or how much time was taken to handle an HTTP request. """ if self.initialized: msg = f'[{tag}]: {msg}' if self._use_color: msg = Style.BRIGHT + Fore.GREEN + Back.BLACK + msg + Style.RESET_ALL self._logger.debug(msg)
[docs] def info(self, tag, msg): """ Prints a message in the 'info' channel. This should be used for general events or notes that the user should know but it isn't a priority, such as what's the port and host address of the Flask server or which web page did someone just access. """ if self.initialized: msg = f'[{tag}]: {msg}' if self._use_color: msg = Style.BRIGHT + Fore.CYAN + Back.BLACK + msg + Style.RESET_ALL self._logger.info(msg)
[docs] def warning(self, tag, msg): """ Prints a message in the 'warning' channel. This should be used when an event in the web app has happened that the user should pay attention to, such as a missing config file or if a sensor isn't configured correctly (that won't greatly affect the performance of said sensor). """ if self.initialized: msg = f'[{tag}]: {msg}' if self._use_color: msg = Style.BRIGHT + Fore.YELLOW + Back.BLACK + msg + Style.RESET_ALL self._logger.warning(msg)
[docs] def error(self, tag, msg): """ Prints a message in the 'error' channel. This should be used when an error has occurred that could make the web app unstable, such as a missing sensor attached, or if a 500 server error occurred internally. """ if self.initialized: msg = f'[{tag}]: {msg}' if self._use_color: msg = Style.BRIGHT + Fore.RED + Back.BLACK + msg + Style.RESET_ALL self._logger.error(msg)
[docs] def critical(self, tag, msg): """ Prints a message in the 'critical' channel. This should be used when a critical event has occurred that user **must** pay attention to it, such as if the camera module or web app crashed. """ if self.initialized: msg = f'[{tag}]: {msg}' if self._use_color: msg = Style.BRIGHT + Fore.MAGENTA + Back.BLACK + msg + Style.RESET_ALL self._logger.critical(msg)
# create logger with 'webapp' logger_inst = logging.getLogger('webapp') # provide a default SuperLogger instance logger = SuperLogger(use_color=True) logger.init_logger(logger_inst) if __name__ == "__main__": logger.set_log_level('DEBUG') logger.debug('SuperLogger', 'This is a debug message') logger.info('SuperLogger', 'This is an info message') logger.warning('SuperLogger', 'This is a warning message') logger.error('SuperLogger', 'This is a error message') logger.critical('SuperLogger', 'This is a critical message')