logging update for exceptions with special error log to console
When calling log.exception it automatically writes a short message to the console as error This error message is tagged <=EXCEPTION> and contains only the message without the stack trace
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)}")
|
||||
|
||||
Reference in New Issue
Block a user