baseimage-tutorial-framework/tfw/logging.py

134 lines
3.9 KiB
Python
Raw Permalink Normal View History

2019-06-18 16:43:02 +00:00
# pylint: disable=bad-whitespace
from datetime import datetime
2019-06-28 15:34:37 +00:00
from typing import TextIO, Union
from dataclasses import dataclass
from collections.abc import Mapping
2019-07-02 13:39:46 +00:00
from traceback import format_exception
2019-06-18 16:43:02 +00:00
from logging import DEBUG, getLogger, Handler, Formatter, Filter
2019-06-27 15:18:04 +00:00
class Color:
2019-07-04 15:27:25 +00:00
RED = '\033[31m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
BLUE = '\033[34m'
CYAN = '\033[36m'
WHITE = '\033[37m'
RESET = '\033[0m'
2019-06-18 16:43:02 +00:00
2019-06-28 15:34:37 +00:00
@dataclass
class Log:
stream: Union[str, TextIO]
formatter: Formatter
class Logger:
def __init__(self, logs, level=DEBUG):
self.root_logger = getLogger()
self.old_level = self.root_logger.level
2019-06-18 16:43:02 +00:00
self.new_level = level
2019-06-28 15:34:37 +00:00
self.handlers = []
for log in logs:
handler = LogHandler(log.stream)
handler.setFormatter(log.formatter)
self.handlers.append(handler)
2019-06-18 16:43:02 +00:00
def start(self):
2019-06-28 15:34:37 +00:00
self.root_logger.setLevel(self.new_level)
for handler in self.handlers:
self.root_logger.addHandler(handler)
2019-06-18 16:43:02 +00:00
def stop(self):
2019-06-28 15:34:37 +00:00
self.root_logger.setLevel(self.old_level)
for handler in self.handlers:
handler.close()
self.root_logger.removeHandler(handler)
2019-06-18 16:43:02 +00:00
2019-06-28 15:34:37 +00:00
class LogHandler(Handler):
def __init__(self, stream):
if isinstance(stream, str):
self.stream = open(stream, 'a+')
self.close_stream = True
else:
self.stream = stream
self.close_stream = False
2019-06-18 16:43:02 +00:00
super().__init__()
def emit(self, record):
2019-06-28 15:34:37 +00:00
entry = self.format(record)
self.stream.write(entry+'\n')
self.stream.flush()
2019-06-18 16:43:02 +00:00
def close(self):
2019-06-28 15:34:37 +00:00
if self.close_stream:
self.stream.close()
2019-06-18 16:43:02 +00:00
2019-06-28 15:34:37 +00:00
class LogFormatter(Formatter):
2019-06-27 12:08:39 +00:00
severity_to_color = {
2019-07-04 15:27:25 +00:00
'CRITICAL' : Color.RED,
2019-06-27 15:18:04 +00:00
'ERROR' : Color.RED,
'WARNING' : Color.YELLOW,
2019-07-04 15:27:25 +00:00
'INFO' : Color.GREEN,
'DEBUG' : Color.BLUE,
2019-06-27 15:18:04 +00:00
'NOTSET' : Color.CYAN
2019-06-18 16:43:02 +00:00
}
2019-06-27 12:08:39 +00:00
def __init__(self, limit):
self.limit = limit
2019-06-24 12:21:30 +00:00
super().__init__()
2019-06-18 16:43:02 +00:00
def format(self, record):
2019-07-04 15:27:25 +00:00
time = datetime.utcfromtimestamp(record.created).strftime('%H:%M:%S')
2019-06-18 16:43:02 +00:00
if record.args:
tuple_args = (record.args,) if isinstance(record.args, Mapping) else record.args
2019-06-18 16:43:02 +00:00
clean_args = tuple((self.trim(arg) for arg in tuple_args))
2019-06-28 15:34:37 +00:00
message = record.msg % clean_args
2019-06-18 16:43:02 +00:00
else:
2019-06-28 15:34:37 +00:00
message = record.msg
2019-07-02 13:39:46 +00:00
trace = '\n'+''.join(format_exception(*record.exc_info)) if record.exc_info else ''
2019-06-18 16:43:02 +00:00
2019-07-04 15:27:25 +00:00
return (f'[{Color.WHITE}{time}{Color.RESET}|>'
2019-06-28 15:34:37 +00:00
f'{self.severity_to_color[record.levelname]}{record.module}:'
2019-07-02 13:39:46 +00:00
f'{record.levelname.lower()}{Color.RESET}] {message}{trace}')
2019-06-18 16:43:02 +00:00
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-28 15:34:37 +00:00
class VerboseLogFormatter(Formatter):
def format(self, record): # pylint: disable=no-self-use
2019-06-28 15:34:37 +00:00
date = datetime.utcfromtimestamp(record.created).strftime('%H:%M:%S')
if record.args:
message = record.msg % record.args
else:
message = record.msg
2019-07-02 13:39:46 +00:00
trace = '\n'+''.join(format_exception(*record.exc_info)) if record.exc_info else ''
2019-06-28 15:34:37 +00:00
return (f'[{date}|>{record.module}:{record.levelname.lower()}] '
2019-07-02 13:39:46 +00:00
f'{message}{trace}')
2019-06-28 15:34:37 +00:00
2019-06-27 15:18:04 +00:00
class WhitelistFilter(Filter):
2019-06-18 16:43:02 +00:00
def __init__(self, names):
self.names = names
super().__init__()
def filter(self, record):
return record.module in self.names
2019-06-27 15:18:04 +00:00
class BlacklistFilter(Filter):
2019-06-18 16:43:02 +00:00
def __init__(self, names):
self.names = names
super().__init__()
def filter(self, record):
return record.module not in self.names