import logging import pathlib import sys from functools import partial class ContextFilter(logging.Filter): def __init__(self, context): super().__init__() self.context = context def filter(self, record): record.context = self.context return True _CONTEXT_FILTER = ContextFilter('N/A') def init_logging(app_context='N/A'): logging.basicConfig( level=logging.INFO, format='%(asctime)s.%(msecs)03d [%(context)s] %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%dT%H:%M:%S', ) handler = logging.getLogger().handlers[0] # Get the default handler handler.addFilter(_CONTEXT_FILTER) set_context(app_context) def set_context(app_context): _CONTEXT_FILTER.context = app_context def _resolve_module_path(filepath: str) -> str: path = pathlib.Path(filepath) filepath_resolved = path.resolve() for root in map(pathlib.Path, sys.path): try: root = root.resolve() relative = filepath_resolved.relative_to(root) return '.'.join(relative.with_suffix('').parts) except ValueError: continue return path.name def get_file_logger(file: str): """Works better than `logging.getLogger(__name__)` providing correct name for __main__ script.""" logger_name = _resolve_module_path(file) return logging.getLogger(logger_name) def print_to_logger(*args, logger, **kwargs): """Prints the given arguments to the logger as an info message.""" message = " ".join(str(arg) for arg in args) logger.info(message) def redirect_print_to_logger(logger): """Redirects print statements to the specified logger.""" return partial(print_to_logger, logger=logger)