Module ambianic.logger

Logging functionalities wrapper

Expand source code
"""Logging functionalities wrapper"""
import logging
import logging.handlers
import os
import pathlib

DEFAULT_FILE_LOG_LEVEL = logging.INFO
DEFAULT_CONSOLE_LOG_LEVEL = logging.WARN

log = logging.getLogger(__name__)


def _get_log_level(log_level, default_log_level):
    numeric_level = default_log_level
    if log_level:
        try:
            numeric_level = getattr(logging, log_level.upper(), default_log_level)
        except AttributeError as e:
            log.warning("Invalid log level: %s . Error: %s", log_level, e)
            log.warning("Defaulting log level to %s", default_log_level)
    fmt = None
    if numeric_level <= logging.INFO:
        format_cfg = (
            "%(asctime)s %(levelname)-4s "
            "%(pathname)s.%(funcName)s(%(lineno)d): %(message)s"
        )
        datefmt_cfg = "%Y-%m-%d %H:%M:%S"
        fmt = logging.Formatter(fmt=format_cfg, datefmt=datefmt_cfg, style="%")
    else:
        fmt = logging.Formatter()

    return numeric_level, fmt


def configure(config=None):
    if config is None:
        config = {}

    log_level = config.get("level", None)

    console_log_level = config.get("console_level", log_level)

    numeric_level, fmt = _get_log_level(
        log_level, default_log_level=DEFAULT_FILE_LOG_LEVEL
    )

    root_logger = logging.getLogger()
    # remove any other handlers that may be assigned previously
    # and could cause unexpected log collisions
    root_logger.handlers = []
    # add a console handler that only shows errors and warnings
    ch = logging.StreamHandler()

    console_numeric_level, console_fmt = _get_log_level(
        console_log_level, default_log_level=DEFAULT_CONSOLE_LOG_LEVEL
    )
    ch.setLevel(console_numeric_level)
    # add formatter to ch
    ch.setFormatter(console_fmt)
    # add ch to logger
    root_logger.addHandler(ch)
    # add a file handler if configured
    log_filename = config.get("file", None)
    if log_filename:
        log_directory = os.path.dirname(log_filename)
        with pathlib.Path(log_directory) as log_dir:
            log_dir.mkdir(parents=True, exist_ok=True)
            print(f"Log messages directed to {log_filename}")
        handler = logging.handlers.RotatingFileHandler(
            log_filename,
            # each log file will be up to 10MB in size
            maxBytes=100 * 1024 * 1024,
            # 20 backup files will be kept. Older will be erased.
            backupCount=20,
        )
        handler.setFormatter(fmt)
        root_logger.addHandler(handler)
    root_logger.setLevel(numeric_level)
    effective_level = log.getEffectiveLevel()
    assert numeric_level == effective_level
    log.info("Logging configured with level %s", logging.getLevelName(effective_level))

Functions

def configure(config=None)
Expand source code
def configure(config=None):
    if config is None:
        config = {}

    log_level = config.get("level", None)

    console_log_level = config.get("console_level", log_level)

    numeric_level, fmt = _get_log_level(
        log_level, default_log_level=DEFAULT_FILE_LOG_LEVEL
    )

    root_logger = logging.getLogger()
    # remove any other handlers that may be assigned previously
    # and could cause unexpected log collisions
    root_logger.handlers = []
    # add a console handler that only shows errors and warnings
    ch = logging.StreamHandler()

    console_numeric_level, console_fmt = _get_log_level(
        console_log_level, default_log_level=DEFAULT_CONSOLE_LOG_LEVEL
    )
    ch.setLevel(console_numeric_level)
    # add formatter to ch
    ch.setFormatter(console_fmt)
    # add ch to logger
    root_logger.addHandler(ch)
    # add a file handler if configured
    log_filename = config.get("file", None)
    if log_filename:
        log_directory = os.path.dirname(log_filename)
        with pathlib.Path(log_directory) as log_dir:
            log_dir.mkdir(parents=True, exist_ok=True)
            print(f"Log messages directed to {log_filename}")
        handler = logging.handlers.RotatingFileHandler(
            log_filename,
            # each log file will be up to 10MB in size
            maxBytes=100 * 1024 * 1024,
            # 20 backup files will be kept. Older will be erased.
            backupCount=20,
        )
        handler.setFormatter(fmt)
        root_logger.addHandler(handler)
    root_logger.setLevel(numeric_level)
    effective_level = log.getEffectiveLevel()
    assert numeric_level == effective_level
    log.info("Logging configured with level %s", logging.getLevelName(effective_level))