Source code for dailylog_lib.logger

"""Logging module for wtftools package."""

import logging
import sys
from types import MappingProxyType

from dailylog_lib.cache import Cache

LABEL = "label"
WARNING = "WARNING"
LOG_LEVELS = MappingProxyType(
    {
        "CRITICAL": logging.CRITICAL,
        "ERROR": logging.ERROR,
        WARNING: logging.WARNING,
        "INFO": logging.INFO,
        "DEBUG": logging.DEBUG,
    },
)


def _label_to_level(level: str) -> int:
    """
    Convert a log label to its corresponding level.

    Parameters
    ----------
    level : str
        Log level label, e.g. "WARNING", "INFO", etc.

    Raises
    ------
    ValueError
        If the log label is a number.

    Returns
    -------
    int
        The corresponding log level, e.g. logging.WARNING, logging.INFO, etc.
    """
    if level.isdigit():
        raise ValueError("Log label cannot be a number.")
    return LOG_LEVELS.get(level.upper(), logging.WARNING)


[docs] def log_label(level: str) -> str: """Return logger level name. Parameters ---------- level : str Level number or name Returns ------- str Level name, Default if not matched, by default "ERROR" """ if level.isdigit(): i_level = int(level) for key, valor in LOG_LEVELS.items(): if i_level == valor: return key else: u_level = level.upper() if u_level in LOG_LEVELS: return u_level return WARNING
[docs] def log_level(level: int | str) -> int: """Return logger level name. Parameters ---------- level : str Level number or name Returns ------- int Level, default logging.WARNING """ if isinstance(level, str): if level.isdigit(): level = int(level) else: return _label_to_level(level) for key, valor in LOG_LEVELS.items(): if level == valor: return level return logging.WARNING
[docs] class Logger(Cache): """Logging class for dailylog-lib package.""" _level: int def __init__(self, **kwargs: bool | int | str) -> None: """ Initialize the Cache class with provided keyword arguments. Parameters ---------- kwargs : dict Keyword arguments that can include: - cache (str): Cache file path, optional. - config (str): Config file path, optional. - debug (bool | int): Debug level, defaults to 0. - level (str | int): Log level, defaults to "WARNING". - test (bool): Test mode flag, defaults to False. - verbose (bool | int): Verbosity level, defaults to 0. This constructor initializes the cache by loading it from a file or creating a new cache if no file exists. """ super().__init__(**kwargs) self._level = log_level(kwargs.get("level", WARNING))
[docs] def log(self, message: str, **kwargs: bool | int | str) -> None: """Log a message with specified parameters, handling suppression and caching. Parameters ---------- message : str The message to log. kwargs : dict Keyword arguments that can include: - caller (str): Caller name, optional. - key (str): Unique key for the cache record, optional. - label (str): Log level label, defaults to "ERROR". - logfn (str): Path to the log file, defaults to the default log if key set. - quiet (bool): If True, suppresses terminal output. - suppress (int): Number of seconds to suppress repeated messages, defaults to CONST_DAY. """ valor = kwargs.get("caller", "") if valor: message = "{0} - {1}".format(valor, message) if "key" in kwargs: self.log_message(str(kwargs.pop("key")), message, **kwargs) else: label = log_label(str(kwargs.get(LABEL, WARNING))) log_fn = str(kwargs.get("logfn", "")) if log_fn: Cache.append_daily(label, message, log_fn) if not kwargs.get("quiet", False): stamp = Cache.t_stamp() sys.stderr.write("{0} {1}: {2}\n".format(stamp, label, message))
[docs] def debug(self, message: str, **kwargs: bool | int | str) -> None: """Log a debug message.""" if self._level <= logging.DEBUG: kwargs[LABEL] = "DEBUG" self.log(message, **kwargs)
[docs] def info(self, message: str, **kwargs: bool | int | str) -> None: # noqa: WPS110 """Log a info message.""" if self._level <= logging.INFO: kwargs[LABEL] = "INFO" self.log(message, **kwargs)
[docs] def warning(self, message: str, **kwargs: bool | int | str) -> None: """Log a warning message.""" if self._level <= logging.WARNING: kwargs[LABEL] = WARNING self.log(message, **kwargs)
[docs] def error(self, message: str, **kwargs: bool | int | str) -> None: """Log a error message.""" if self._level <= logging.ERROR: kwargs[LABEL] = "ERROR" self.log(message, **kwargs)
[docs] def critical(self, message: str, **kwargs: bool | int | str) -> None: """Log a critical message.""" if self._level <= logging.CRITICAL: kwargs[LABEL] = "CRITICAL" self.log(message, **kwargs)