Source code for spey.system.logger

"""Logging style for spey"""
import logging
import sys
from contextlib import contextmanager

# pylint: disable=C0103


class ColoredFormatter(logging.Formatter):
    """Coloured logging formatter for spey"""

    def __init__(self, msg):
        logging.Formatter.__init__(self, msg)

    def format(self, record):
        if record.levelno >= 50:  # FATAL
            color = "\x1b[31mSpey - ERROR: "
        elif record.levelno >= 40:  # ERROR
            color = "\x1b[31mSpey - ERROR: "
        elif record.levelno >= 30:  # WARNING
            color = "\x1b[35mSpey - WARNING: "
        elif record.levelno >= 20:  # INFO
            color = "\x1b[0mSpey: "
        elif record.levelno >= 10:  # DEBUG
            color = (
                f"\x1b[36mSpey - DEBUG ({record.module}.{record.funcName}() "
                f"in {record.filename}::L{record.lineno}): "
            )
        else:  # ANYTHING ELSE
            color = "\x1b[0mSpey: "

        record.msg = color + str(record.msg) + "\x1b[0m"
        return logging.Formatter.format(self, record)


def init(LoggerStream=sys.stdout):
    """Initialise logger"""
    rootLogger = logging.getLogger()
    hdlr = logging.StreamHandler()
    fmt = ColoredFormatter("%(message)s")
    hdlr.setFormatter(fmt)
    rootLogger.addHandler(hdlr)

    # we need to replace all root loggers by ma5 loggers for a proper
    # interface with madgraph5
    SpeyLogger = logging.getLogger("Spey")
    for hdlr in SpeyLogger.handlers:
        SpeyLogger.removeHandler(hdlr)
    hdlr = logging.StreamHandler(LoggerStream)
    fmt = ColoredFormatter("%(message)s")
    hdlr.setFormatter(fmt)
    SpeyLogger.addHandler(hdlr)
    SpeyLogger.propagate = False


[docs] @contextmanager def disable_logging(highest_level: int = logging.CRITICAL): """ Temporary disable logging implementation Args: highest_level (``int``, default ``logging.CRITICAL``): highest level to be set in logging """ previous_level = logging.root.manager.disable logging.disable(highest_level) try: yield finally: logging.disable(previous_level)
[docs] @contextmanager def capture_logs(level: int = logging.DEBUG, stream=None): """ Context manager that captures log records emitted while inside the context and suppresses duplicate messages. Only unique messages are printed once to the provided stream (defaults to sys.stdout). **Example:** .. code:: python3 >>> with capture_logs(logging.INFO) as _: >>> for i in range(100): >>> logging.getLogger("Spey").warning("Same warning") # printed once >>> # outputs: "Same warning" only once Args: level (``int``, default ``logging.DEBUG``): minimum logging level to capture. stream (default ``None``): file-like object to write the unique messages. """ stream = stream or sys.stdout records = [] seen_messages = set() class _DedupHandler(logging.Handler): def emit(self, record): try: msg = self.format(record) except Exception: msg = record.getMessage() # Only add if we haven't seen this exact message before if msg not in seen_messages: seen_messages.add(msg) records.append(msg) handler = _DedupHandler() handler.setFormatter(ColoredFormatter("%(message)s")) handler.setLevel(level) # Get the Spey logger spey_logger = logging.getLogger("Spey") prev_level = spey_logger.level prev_propagate = spey_logger.propagate # Store and remove existing handlers temporarily prev_handlers = spey_logger.handlers[:] for h in prev_handlers: spey_logger.removeHandler(h) spey_logger.addHandler(handler) spey_logger.setLevel(level) spey_logger.propagate = False try: yield # Write unique messages to the provided stream for m in records: stream.write(m + "\n") try: stream.flush() except Exception: pass finally: spey_logger.removeHandler(handler) spey_logger.setLevel(prev_level) spey_logger.propagate = prev_propagate # Restore original handlers for h in prev_handlers: spey_logger.addHandler(h)