From 6f898ab23ec1b93ec5e6b04bd6030dae65de0dea Mon Sep 17 00:00:00 2001 From: gryf Date: Tue, 22 Jun 2021 22:03:46 +0200 Subject: [PATCH] Added real logging class, instead of Log class. --- ebook_converter/utils/logging.py | 139 +++++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 8 deletions(-) diff --git a/ebook_converter/utils/logging.py b/ebook_converter/utils/logging.py index 3c06337..0cf2d54 100644 --- a/ebook_converter/utils/logging.py +++ b/ebook_converter/utils/logging.py @@ -1,11 +1,14 @@ """ A simplified logging system """ -import sys -import traceback +import functools import io import os -from functools import partial +import sys +import traceback + +# how about making it really simplified? +import logging from ebook_converter import constants_old @@ -16,6 +19,123 @@ WARN = 2 ERROR = 3 +class CustomFormatter(logging.Formatter): + """Logging Formatter to add colors and count warning / errors""" + + grey = "\x1b[38;21m" + yellow = "\x1b[33;21m" + red = "\x1b[31;21m" + bold_red = "\x1b[31;1m" + reset = "\x1b[0m" + fmt = "%(message)s" + + FORMATS = {logging.DEBUG: grey + fmt + reset, + logging.INFO: grey + fmt + reset, + logging.WARNING: yellow + fmt + reset, + logging.ERROR: red + fmt + reset, + logging.CRITICAL: bold_red + fmt + reset} + + def format(self, record): + log_fmt = self.FORMATS.get(record.levelno) + formatter = logging.Formatter(log_fmt) + return formatter.format(record) + + +class Logger: + """ + Logger class with output on console only + """ + def __init__(self, logger_name, color=False): + """ + Initialize named logger + """ + self._log = logging.getLogger(logger_name) + self.setup_logger() + self._log.set_verbose = self.set_verbose + + def __call__(self): + """ + Calling this object will return configured logging.Logger object with + additional set_verbose() method. + """ + return self._log + + def set_verbose(self, verbose_level, quiet_level): + """ + Change verbosity level. Default level is warning. + """ + self._log.setLevel(logging.WARNING) + + if quiet_level: + self._log.setLevel(logging.ERROR) + if quiet_level > 1: + self._log.setLevel(logging.CRITICAL) + + if verbose_level: + self._log.setLevel(logging.INFO) + if verbose_level > 1: + self._log.setLevel(logging.DEBUG) + + def setup_logger(self): + """ + Create setup instance and make output meaningful :) + """ + if self._log.handlers: + # need only one handler + return + + console_handler = logging.StreamHandler(sys.stderr) + console_handler.set_name("console") + console_formatter = CustomFormatter() + console_handler.setFormatter(console_formatter) + self._log.addHandler(console_handler) + self._log.setLevel(logging.WARNING) + + +BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8) + +#The background is set with 40 plus the number of the color, and the foreground with 30 + +#These are the sequences need to get colored ouput +RESET_SEQ = "\033[0m" +COLOR_SEQ = "\033[1;%dm" +BOLD_SEQ = "\033[1m" + +def formatter_message(message, use_color = True): + if use_color: + message = message.replace("$RESET", RESET_SEQ).replace("$BOLD", + BOLD_SEQ) + else: + message = message.replace("$RESET", "").replace("$BOLD", "") + return message + +class ColoredFormatter(logging.Formatter): + COLORS = {'WARNING': YELLOW, + 'INFO': WHITE, + 'DEBUG': BLUE, + 'CRITICAL': YELLOW, + 'ERROR': RED} + + def __init__(self, msg, use_color=True): + logging.Formatter.__init__(self, msg) + self.use_color = use_color + + def format(self, record): + levelname = record.levelname + if self.use_color and levelname in self.COLORS: + levelname_color = COLOR_SEQ % (30 + self.COLORS[levelname]) + \ + levelname + RESET_SEQ + record.levelname = levelname_color + return logging.Formatter.format(self, record) + + + + + + + + + class Stream(object): def __init__(self, stream=None): @@ -85,10 +205,11 @@ class Log(object): default_output = ANSIStream() self.outputs = [default_output] - self.debug = partial(self.print_with_flush, DEBUG) - self.info = partial(self.print_with_flush, INFO) - self.warn = self.warning = partial(self.print_with_flush, WARN) - self.error = partial(self.print_with_flush, ERROR) + self.debug = functools.partial(self.print_with_flush, DEBUG) + self.info = functools.partial(self.print_with_flush, INFO) + self.warn = self.warning = functools.partial(self.print_with_flush, + WARN) + self.error = functools.partial(self.print_with_flush, ERROR) def prints(self, level, *args, **kwargs): if level < self.filter_level: @@ -129,4 +250,6 @@ class Log(object): o.close() -default_log = Log() +default_log = Logger('ebook-converter')() +# TODO(gryf): remove this after providing value from cmd line/config +default_log.set_verbose(2, 0)