|
|
|
|
@@ -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
|
|
|
|
|
|