123 lines
3.8 KiB
Python
123 lines
3.8 KiB
Python
"""
|
|
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__
|