baseimage-tutorial-framework/lib/tfw/config/log.py

138 lines
4.2 KiB
Python
Raw Normal View History

2019-06-18 16:43:02 +00:00
# pylint: disable=bad-whitespace
from sys import stderr
2019-06-24 12:21:30 +00:00
from collections import deque
2019-06-18 16:43:02 +00:00
from datetime import datetime
2019-06-24 12:21:30 +00:00
from traceback import format_exception, walk_tb
2019-06-18 16:43:02 +00:00
from logging import DEBUG, getLogger, Handler, Formatter, Filter
2019-06-27 12:08:39 +00:00
from .envvars import TFWENV
2019-06-18 16:43:02 +00:00
class COLOR:
BLACK = '\033[30m'
GREY = '\033[30;1m'
RED = '\033[31m'
BOLDRED = '\033[31;1m'
GREEN = '\033[32m'
BOLDGREEN = '\033[32;1m'
ORANGE = '\033[33m'
YELLOW = '\033[33;1m'
BLUE = '\033[34m'
BOLDBLUE = '\033[34;1m'
MAGENTA = '\033[35m'
BOLDMAGENTA = '\033[35;1m'
CYAN = '\033[36m'
BOLDCYAN = '\033[36;1m'
WHITE = '\033[37m'
BOLDWHITE = '\033[37;1m'
RESET = '\033[0m'
class TFWLog:
2019-06-27 12:08:39 +00:00
def __init__(self, path=TFWENV.LOGFILE, level=DEBUG):
2019-06-18 16:43:02 +00:00
self.log = getLogger()
self.old_level = self.log.level
self.new_level = level
self.handler = TFWLogHandler(path)
2019-06-27 12:08:39 +00:00
self.handler.setFormatter(TFWLogFormatter(20))
2019-06-18 16:43:02 +00:00
def start(self):
self.log.setLevel(self.new_level)
self.log.addHandler(self.handler)
def stop(self):
self.log.setLevel(self.old_level)
self.handler.close()
self.log.removeHandler(self.handler)
class TFWLogHandler(Handler):
def __init__(self, path):
self.logfile = open(path, 'a+')
super().__init__()
def emit(self, record):
short_entry, long_entry = self.format(record)
stderr.write(short_entry+'\n')
self.logfile.write(long_entry+'\n')
stderr.flush()
self.logfile.flush()
def close(self):
self.logfile.close()
class TFWLogFormatter(Formatter):
2019-06-27 12:08:39 +00:00
severity_to_color = {
2019-06-18 16:43:02 +00:00
'CRITICAL' : COLOR.BOLDRED,
'ERROR' : COLOR.RED,
'WARNING' : COLOR.YELLOW,
'INFO' : COLOR.BOLDGREEN,
'DEBUG' : COLOR.BOLDWHITE,
'NOTSET' : COLOR.CYAN
}
2019-06-27 12:08:39 +00:00
def __init__(self, limit):
self.limit = limit
2019-06-24 12:21:30 +00:00
self.last_trace = None
super().__init__()
2019-06-18 16:43:02 +00:00
def format(self, record):
date = datetime.utcfromtimestamp(record.created).strftime('%H:%M:%S')
if record.args:
tuple_args = (record.args,) if isinstance(record.args, dict) else record.args
clean_args = tuple((self.trim(arg) for arg in tuple_args))
short_message = record.msg % clean_args
long_message = record.msg % record.args
else:
short_message = record.msg
long_message = record.msg
2019-06-24 12:21:30 +00:00
if record.exc_info:
current_trace = self.fetch_exception_origin(record.exc_info[2])
if current_trace != self.last_trace:
self.last_trace = current_trace
trace = '\n'+''.join(format_exception(*record.exc_info))
else:
trace = (f'\nSee previous traceback...\n'
f'{record.exc_info[0].__name__}: {record.exc_info[1]}')
else:
trace = ''
2019-06-18 16:43:02 +00:00
short_entry = (f'[{COLOR.GREY}{date}{COLOR.RESET}|>'
2019-06-27 12:08:39 +00:00
f'{self.severity_to_color[record.levelname]}{record.module}:'
2019-06-24 12:21:30 +00:00
f'{record.levelname.lower()}{COLOR.RESET}] {short_message}'
f'{trace}')
long_entry = (f'[{date}|>{record.module}:{record.levelname.lower()}] '
f'{long_message}{trace}')
2019-06-18 16:43:02 +00:00
return short_entry, long_entry
2019-06-27 12:08:39 +00:00
def trim(self, value):
2019-06-18 16:43:02 +00:00
if isinstance(value, dict):
2019-06-27 12:17:57 +00:00
return {k: self.trim(v) for k, v in value.items()}
2019-06-27 13:44:23 +00:00
if isinstance(value, str):
value_str = str(value)
return value_str if len(value_str) <= self.limit else f'{value_str[:self.limit]}...'
return value
2019-06-18 16:43:02 +00:00
2019-06-24 12:21:30 +00:00
@staticmethod
def fetch_exception_origin(trace):
return deque(walk_tb(trace), maxlen=1).pop()
2019-06-18 16:43:02 +00:00
class TFWLogWhitelistFilter(Filter):
def __init__(self, names):
self.names = names
super().__init__()
def filter(self, record):
return record.module in self.names
class TFWLogBlacklistFilter(Filter):
def __init__(self, names):
self.names = names
super().__init__()
def filter(self, record):
return record.module not in self.names