Skip to content
Snippets Groups Projects
logger.py 4.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Andreas Bolin's avatar
    Andreas Bolin committed
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    """B-ASIC Scheduler-gui Logger Module.
    
    Contains a logger that logs to the console and a file using levels. It is based
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
    on the :mod:`logging` module and has predefined levels of logging.
    
    Andreas Bolin's avatar
    Andreas Bolin committed
    
    Usage:
    ------
    
        >>> import logger
        >>> log = logger.getLogger()
        >>> log.info('This is a log post with level INFO')
    
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
    .. list-table::
       :widths: 50 25 25
       :header-rows: 1
    
       * - Function call
         - Level
         - Numeric value
       * - debug(str)
         - DEBUG
         - 10
       * - info(str)
         - INFO
         - 20
       * - warning(str)
         - WARNING
         - 30
       * - error(str)
         - ERROR
         - 40
       * - critical(str)
         - CRITICAL
         - 50
       * - exception(str)
         - ERROR
         - 40
    
    Andreas Bolin's avatar
    Andreas Bolin committed
    
    The last `exception(str)` is used to capture exceptions output, that normally
    
    will not be captured.
    
    Andreas Bolin's avatar
    Andreas Bolin committed
    See https://docs.python.org/3/howto/logging.html for more information.
    
    Log Uncaught Exceptions:
    ------------------------
    To log uncaught exceptions, implement the following in your program.
      `sys.excepthook = logger.log_exceptions`"""
    import logging
    import logging.handlers
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
    import os
    import sys
    from logging import Logger
    from types import TracebackType
    
    from typing import Type, Union
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
    def getLogger(
        filename: str = "scheduler-gui.log", loglevel: str = "INFO"
    ) -> Logger:
    
    Andreas Bolin's avatar
    Andreas Bolin committed
        """This function creates console- and filehandler and from those, creates a logger object.
    
        Args:
            filename (str, optional): Output filename. Defaults to 'scheduler-gui.log'.
            loglevel (str, optional): The minimum level that the logger will log. Defaults to 'INFO'.
    
        Returns:
            Logger: 'logging.Logger' object.
        """
    
        # logger = logging.getLogger(name)
        # logger = logging.getLogger('root')
        logger = logging.getLogger()
    
        # if logger 'name' already exists, return it to avoid logging duplicate
        # messages by attaching multiple handlers of the same type
        if logger.handlers:
            return logger
        # if logger 'name' does not already exist, create it and attach handlers
        else:
            # set logLevel to loglevel or to INFO if requested level is incorrect
            loglevel = getattr(logging, loglevel.upper(), logging.INFO)
            logger.setLevel(loglevel)
    
            # setup the console logger
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
            c_fmt_date = "%T"
            c_fmt = (
                "[%(process)d] %(asctime)s %(filename)18s:%(lineno)-4s"
                " %(funcName)20s() %(levelname)-8s: %(message)s"
            )
    
    Andreas Bolin's avatar
    Andreas Bolin committed
            c_formatter = logging.Formatter(c_fmt, c_fmt_date)
            c_handler = logging.StreamHandler()
            c_handler.setFormatter(c_formatter)
            c_handler.setLevel(logging.WARNING)
            logger.addHandler(c_handler)
    
            # setup the file logger
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
            f_fmt_date = "%Y-%m-%dT%T%Z"
            f_fmt = (
                "%(asctime)s %(filename)18s:%(lineno)-4s %(funcName)20s()"
                " %(levelname)-8s: %(message)s"
            )
    
    Andreas Bolin's avatar
    Andreas Bolin committed
            f_formatter = logging.Formatter(f_fmt, f_fmt_date)
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
            f_handler = logging.FileHandler(filename, mode="w")
    
    Andreas Bolin's avatar
    Andreas Bolin committed
            f_handler.setFormatter(f_formatter)
            f_handler.setLevel(logging.DEBUG)
            logger.addHandler(f_handler)
    
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        if logger.name == "scheduler-gui.log":
            logger.info(
                "Running: %s %s",
                os.path.basename(sys.argv[0]),
                " ".join(sys.argv[1:]),
            )
    
    Andreas Bolin's avatar
    Andreas Bolin committed
    
        return logger
    
    
    # log uncaught exceptions
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
    def handle_exceptions(
        exc_type: Type[BaseException],
        exc_value: BaseException,
        exc_traceback: Union[TracebackType, None],
    ) -> None:
        # def log_exceptions(type, value, tb):
    
    Andreas Bolin's avatar
    Andreas Bolin committed
        """This function is a helper function to log uncaught exceptions. Install with:
        `sys.excepthook = <module>.handle_exceptions`"""
        if issubclass(exc_type, KeyboardInterrupt):
            sys.__excepthook__(exc_type, exc_value, exc_traceback)
            return
    
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        logging.exception(
            "Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)
        )
    
    
    Andreas Bolin's avatar
    Andreas Bolin committed
    
    # def qt_message_handler(mode, context, message):
    #     if mode == QtCore.QtInfoMsg:
    #         mode = 'INFO'
    #     elif mode == QtCore.QtWarningMsg:
    #         mode = 'WARNING'
    #     elif mode == QtCore.QtCriticalMsg:
    #         mode = 'CRITICAL'
    #     # elif mode == QtCore.QtErrorMsg:
    #     #     mode = 'ERROR'
    #     elif mode == QtCore.QtFatalMsg:
    #         mode = 'FATAL'
    #     else:
    #         mode = 'DEBUG'
    #     print('qt_message_handler: line: %d, func: %s(), file: %s' % (
    #           context.line, context.function, context.file))
    #     print('  %s: %s\n' % (mode, message))