Source code for seutil.log

"""
This module assists the logging standard library.  The main functionality is:

* maintain two frequently used handlers: a stderr handler and a file handler, both with
  rich and customizable formats.
* `setup` method to attach them to the root logger.
* `get_logger` method to quickly create a logger with customized level.
"""
import logging
import sys
from logging import CRITICAL, DEBUG, ERROR, INFO, WARNING
from logging.handlers import RotatingFileHandler
from pathlib import Path
from typing import Optional, Union

__all__ = [
    "setup",
    "get_logger",
]


LOGGING_NAMESPACE = "su"

handler_stderr = logging.StreamHandler(sys.stderr)
handler_file = None


[docs]def setup( log_file: Optional[Union[str, Path]] = None, level_stderr: Union[int, str] = logging.INFO, level_file: Union[int, str] = logging.DEBUG, fmt_stderr: str = "[{asctime}{levelname[0]}]{name}: {message}", datefmt_stderr: str = "%H:%M:%S", fmt_file: str = "[{asctime}|{relativeCreated:.3f}|{levelname:7}]{name}: {message} [@{filename}:{lineno}|{funcName}|pid {process}|tid {thread}]", datefmt_file: str = "%Y-%m-%d %H:%M:%S", clear_handlers: bool = True, **kwargs_file: dict, ): """ Setup the stderr and file handlers, and attach them to the root logger. :param log_file: the log file to use; if None, no file handler is created (and any existing one would be removed) :param level_stderr: the level filter of the stderr handler :param level_file: the level filter of the file handler :param fmt_stderr: the format of the stderr handler (with {} style) :param fmt_file: the format of the file handler (with {} style) :param clear_handlers: if True, remove all existing handlers of the root logger; otherwise, keep them as is :param kwargs_file: other optional kwargs to the file handler (RotatingFileHandler) """ global handler_stderr, handler_file root_logger = logging.getLogger(LOGGING_NAMESPACE) root_logger.propagate = False # set to NOTSET+1, so that child logger's effective level can be correctly computed based on this logger root_logger.setLevel(logging.NOTSET + 1) if clear_handlers: root_logger.handlers = [] # update the stderr handler handler_stderr.setLevel(level_stderr) handler_stderr.setFormatter( logging.Formatter(fmt_stderr, datefmt_stderr, style="{") ) root_logger.addHandler(handler_stderr) # update the file handler root_logger.removeHandler(handler_file) if log_file is not None: kwargs_file.setdefault("maxBytes", 10_000_000) kwargs_file.setdefault("backupCount", 1) handler_file = RotatingFileHandler(log_file, **kwargs_file) handler_file.setLevel(level_file) handler_file.setFormatter(logging.Formatter(fmt_file, datefmt_file, style="{")) root_logger.addHandler(handler_file) else: handler_file = None
[docs]def get_logger(name: str, level: Union[int, str] = logging.NOTSET): """ Get a logger with specified name and level. """ logger = logging.getLogger(LOGGING_NAMESPACE + "." + name) logger.setLevel(level) return logger