Source code for pymepix.core.log

# This file is part of Pymepix
#
# In all scientific work using Pymepix, please reference it as
#
# A. F. Al-Refaie, M. Johny, J. Correa, D. Pennicard, P. Svihra, A. Nomerotski, S. Trippel, and J. Küpper:
# "PymePix: a python library for SPIDR readout of Timepix3", J. Inst. 14, P10003 (2019)
# https://doi.org/10.1088/1748-0221/14/10/P10003
# https://arxiv.org/abs/1905.07999
#
# Pymepix is free software: you can redistribute it and/or modify it under the terms of the GNU
# General Public License as published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not,
# see <https://www.gnu.org/licenses/>.


import logging
import multiprocessing as mp
from abc import abstractmethod

__all__ = ["Logger", "ProcessLogger"]


class PymepixLogger:
    """Base class for logging in pymepix."""

    COLOR_CODES = {
        "DEBUG": "\033[94m",
        "INFO": "\033[92m",
        "WARNING": "\033[93m",
        "ERROR": "\033[91m",
        "CRITICAL": "\033[95m",
        "RESET": "\033[0m",
    }

    def __init__(self, name, level, prefix="pymepix"):
        self._log_name = f"{prefix}.{name}"
        self._logger = self.getLogger(self._log_name)
        self.setFormatter()
        self.setLevel(level)

    @property
    def logName(self):
        return self._log_name

    @abstractmethod
    def getLogger(self, name):
        pass

    def setFormatter(self):
        # Remove all handlers associated with the logger
        if self._logger.hasHandlers():
            self._logger.handlers.clear()

        handler = logging.StreamHandler()
        formatter = self.ColoredFormatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
        handler.setFormatter(formatter)
        self._logger.addHandler(handler)

    def setLevel(self, level):
        self._logger.setLevel(level)

    @classmethod
    def basicConfig(cls, **kwargs):
        logging.basicConfig(**kwargs)

    class ColoredFormatter(logging.Formatter):
        def format(self, record):
            log_color = PymepixLogger.COLOR_CODES.get(record.levelname, PymepixLogger.COLOR_CODES["RESET"])
            reset_color = PymepixLogger.COLOR_CODES["RESET"]
            record.msg = f"{log_color}{record.msg}{reset_color}"
            return super().format(record)

    def info(self, message, *args, **kwargs):
        self._logger.info(message, *args, **kwargs)

    def warning(self, message, *args, **kwargs):
        self._logger.warning(message, *args, **kwargs)

    def debug(self, message, *args, **kwargs):
        self._logger.debug(message, *args, **kwargs)

    def error(self, message, *args, **kwargs):
        self._logger.error(message, *args, **kwargs)

    def critical(self, message, *args, **kwargs):
        self._logger.critical(message, *args, **kwargs)


[docs] class Logger(PymepixLogger): """ Standard logging implementation using Python's built-in logging library. This class extends the `PymepixLogger` base class to provide standard logging capabilities with customizable formatting and color coding for console output. It retrieves and manages a logger instance from the `logging` module and allows configuration of log level and format. """ def __init__(self, name, level=logging.INFO, prefix="pymepix"): super().__init__(name, level, prefix)
[docs] def getLogger(self, name): return logging.getLogger(name)
[docs] class ProcessLogger(PymepixLogger): """ Logging implementation for multiprocessing environments. This class extends the `PymepixLogger` base class to provide logging capabilities suitable for use in multiprocessing contexts. It retrieves and manages a logger instance compatible with the `multiprocessing` module's logging mechanism. """ def __init__(self, name, level=logging.INFO): super().__init__(name, level)
[docs] def getLogger(self, name): """ Retrieves a logger instance from the `multiprocessing` module. Parameters ---------- name : str The name of the logger to be retrieved. Returns ------- logging.Logger The logger instance compatible with multiprocessing logging. """ return mp.get_logger()
def main(): logger = Logger("example") # Configure logging once at the start of the script # Example usage with different log levels logger.setLevel(logging.INFO) # Ensure correct level is set logger.debug("This is a debug message.") # This will be printed logger.info("This is an info message.") # This will be printed logger.warning("This is a warning message.") # This will be printed logger.error("This is an error message.") # This will be printed logger.critical("This is a critical message.") # This will be printed if __name__ == "__main__": main()