diff --git a/src/corelibs/logging_handling/log.py b/src/corelibs/logging_handling/log.py index 4bdd4ac..75acb8a 100644 --- a/src/corelibs/logging_handling/log.py +++ b/src/corelibs/logging_handling/log.py @@ -73,11 +73,32 @@ class CustomConsoleFormatter(logging.Formatter): message = super().format(record) return f"{color}{message}{reset}" - # TODO: add custom handlers for stack_trace, if not set fill with %(filename)s:%(funcName)s:%(lineno)d # hasattr(record, 'stack_trace') +class CustomHandlerFilter(logging.Filter): + """ + Add a custom handler for filtering + """ + def __init__(self, handler_name: str, filter_exceptions: bool = False): + super().__init__(name=handler_name) + self.handler_name = handler_name + self.filter_exceptions = filter_exceptions + + def filter(self, record: logging.LogRecord) -> bool: + # if console and exception do not show + if self.handler_name == 'console' and self.filter_exceptions: + return record.levelname != "EXCEPTION" + # if cnosole entry is true and traget file filter + if hasattr(record, 'console') and getattr(record, 'console') is True and self.handler_name == 'file': + return False + return True + + # def __filter_exceptions(self, record: logging.LogRecord) -> bool: + # return record.levelname != "EXCEPTION" + + # MARK: Log class class Log: """ @@ -142,7 +163,7 @@ class Log: # in the file writer too, for the ones where color is set BEFORE the format # Any is logging.StreamHandler, logging.FileHandler and all logging.handlers.* self.handlers: dict[str, Any] = {} - self.add_handler('file_handler', self.__create_time_rotating_file_handler( + self.add_handler('file_handler', self.__create_timed_rotating_file_handler( self.log_settings['log_level_file'], log_path) ) if self.log_settings['console_enabled']: @@ -211,8 +232,8 @@ class Log: default_log_settings['log_queue'] = __setting return default_log_settings - def __filter_exceptions(self, record: logging.LogRecord) -> bool: - return record.levelname != "EXCEPTION" + # def __filter_exceptions(self, record: logging.LogRecord) -> bool: + # return record.levelname != "EXCEPTION" # MARK: add a handler def add_handler( @@ -259,16 +280,15 @@ class Log: formatter_console = CustomConsoleFormatter(format_string, datefmt=format_date) else: formatter_console = logging.Formatter(format_string, datefmt=format_date) - console_handler.setLevel(log_level_console.name) console_handler.set_name('console') + console_handler.setLevel(log_level_console.name) # do not show exceptions logs on console - if filter_exceptions: - console_handler.addFilter(self.__filter_exceptions) + console_handler.addFilter(CustomHandlerFilter('console', filter_exceptions)) console_handler.setFormatter(formatter_console) return console_handler # MARK: file handler - def __create_time_rotating_file_handler( + def __create_timed_rotating_file_handler( self, log_level_file: LoggingLevel, log_path: Path, when: str = "D", interval: int = 1, backup_count: int = 0 ) -> logging.handlers.TimedRotatingFileHandler: @@ -304,6 +324,8 @@ class Log: ) file_handler.set_name('file_timed_rotate') file_handler.setLevel(log_level_file.name) + # do not show errors flagged with console (they are from exceptions) + file_handler.addFilter(CustomHandlerFilter('file')) file_handler.setFormatter(formatter_file_handler) return file_handler @@ -454,7 +476,11 @@ class Log: self.logger.log(LoggingLevel.EMERGENCY.value, msg, *args, extra=extra, stacklevel=2) # MARK: EXCEPTION: 70 - def exception(self, msg: object, *args: object, extra: MutableMapping[str, object] | None = None) -> None: + def exception( + self, + msg: object, *args: object, extra: MutableMapping[str, object] | None = None, + log_error: bool = True + ) -> None: """ log on exceotion level, this is log.exception, but logs with a new level @@ -462,12 +488,19 @@ class Log: msg (object): _description_ *args (object): arguments for msg extra: Mapping[str, object] | None: extra arguments for the formatting if needed + log_error: (bool): If set to false will not write additional error message for console (Default True) """ if not hasattr(self, 'logger'): raise ValueError('Logger is not yet initialized') if extra is None: extra = {} extra['stack_trace'] = traceback_call_str(start=3) + # write to console first with extra flag for filtering in file + if log_error: + self.logger.log( + LoggingLevel.ERROR.value, + f"<=EXCEPTION> {msg}", *args, extra=dict(extra) | {'console': True}, stacklevel=2 + ) self.logger.log(LoggingLevel.EXCEPTION.value, msg, *args, exc_info=True, extra=extra, stacklevel=2) # MARK: break line diff --git a/test-run/logging_handling/log.py b/test-run/logging_handling/log.py index 8b8cc30..b119d2a 100644 --- a/test-run/logging_handling/log.py +++ b/test-run/logging_handling/log.py @@ -76,7 +76,7 @@ def main(): print(f"Divied: {__test}") except ZeroDivisionError as e: log.logger.critical("Divison through zero: %s", e) - log.exception("Divison through zero") + log.exception("Divison through zero: %s", e) for handler in log.logger.handlers: print(f"Handler (logger) {handler} -> {handler.level} -> {LoggingLevel.from_any(handler.level)}") diff --git a/uv.lock b/uv.lock index e225228..2cf2d68 100644 --- a/uv.lock +++ b/uv.lock @@ -44,7 +44,7 @@ wheels = [ [[package]] name = "corelibs" -version = "0.12.6" +version = "0.13.2" source = { editable = "." } dependencies = [ { name = "jmespath" },