""" A log handler wrapper """ import logging.handlers import logging from pathlib import Path from typing import Mapping class Log: """ logger setup """ EXCEPTION: int = 60 def __init__( self, log_path: Path, log_name: str, log_level_console: str = 'WARNING', log_level_file: str = 'DEBUG', add_start_info: bool = True ): logging.addLevelName(Log.EXCEPTION, 'EXCEPTION') if not log_name.endswith('.log'): log_path = log_path.with_suffix('.log') # overall logger settings self.logger = logging.getLogger(log_name) # set maximum logging level for all logging output self.logger.setLevel(logging.DEBUG) self.handlers = [] # console logger self.__console_handler(log_level_console) # file logger self.__file_handler(log_level_file, log_path) # if requests set a start log if add_start_info is True: self.break_line('START') def __filter_exceptions(self, record: logging.LogRecord) -> bool: return record.levelname != "EXCEPTION" def __console_handler(self, log_level_console: str = 'WARNING'): # console logger if not isinstance(getattr(logging, log_level_console.upper(), None), int): log_level_console = 'WARNING' console_handler = logging.StreamHandler() formatter_console = logging.Formatter( ( '[%(asctime)s.%(msecs)03d] ' '[%(filename)s:%(funcName)s:%(lineno)d] ' '<%(levelname)s> ' '%(message)s' ), datefmt="%Y-%m-%d %H:%M:%S", ) console_handler.setLevel(log_level_console) # do not show exceptions logs on console console_handler.addFilter(self.__filter_exceptions) console_handler.setFormatter(formatter_console) self.logger.addHandler(console_handler) def __file_handler(self, log_level_file: str, log_path: Path) -> None: # file logger if not isinstance(getattr(logging, log_level_file.upper(), None), int): log_level_file = 'DEBUG' file_handler = logging.handlers.TimedRotatingFileHandler( filename=log_path, encoding="utf-8", when="D", interval=1 ) formatter_file_handler = logging.Formatter( ( '[%(asctime)s.%(msecs)03d] ' '[%(name)s:%(process)d] ' '[%(pathname)s:%(funcName)s:%(lineno)d] ' '<%(levelname)s> ' '%(message)s' ), datefmt="%Y-%m-%dT%H:%M:%S", ) file_handler.setLevel(log_level_file) file_handler.setFormatter(formatter_file_handler) self.logger.addHandler(file_handler) def break_line(self, info: str = "BREAK"): """ add a break line as info level Keyword Arguments: info {str} -- _description_ (default: {"BREAK"}) """ self.logger.info("[%s] ================================>", info) def exception(self, msg: object, *args: object, extra: Mapping[str, object] | None = None) -> None: """ log on exceotion level Args: msg (object): _description_ *args (object): arguments for msg extra: Mapping[str, object] | None: extra arguments for the formatting if needed """ self.logger.log(Log.EXCEPTION, msg, *args, exc_info=True, extra=extra) def validate_log_level(self, log_level: str) -> bool: """ if the log level is invalid, will erturn false Args: log_level (str): _description_ Returns: bool: _description_ """ return isinstance(getattr(logging, log_level.upper(), None), int) # __END__