diff --git a/inputremapper/logger.py b/inputremapper/logger.py index 320e2f30..4118b4e5 100644 --- a/inputremapper/logger.py +++ b/inputremapper/logger.py @@ -91,12 +91,14 @@ def is_debug(): return logger.level <= logging.DEBUG -def get_ansi_code(r, g, b): - return 16 + b + (6 * g) + (36 * r) +class ColorfulFormatter(logging.Formatter): + """Overwritten Formatter to print nicer logs. + It colors all logs from the same filename in the same color to visually group them + together. It also adds process name, process id, file, line-number and time. -class Formatter(logging.Formatter): - """Overwritten Formatter to print nicer logs.""" + If debug mode is not active, it will not do any of this. + """ def __init__(self): super().__init__() @@ -111,18 +113,19 @@ class Formatter(logging.Formatter): # https://stackoverflow.com/a/596243 brightness = 0.2126 * r + 0.7152 * g + 0.0722 * b if brightness < 1: - # prefer light colors, because most people have a dark terminal background + # prefer light colors, because most people have a dark + # terminal background continue if g + b <= 1: - # red is reserved for errors + # red makes it look like it's an error continue if abs(g - b) < 2 and abs(b - r) < 2 and abs(r - g) < 2: # no colors that are too grey continue - self.allowed_colors.append(get_ansi_code(r, g, b)) + self.allowed_colors.append(self._get_ansi_code(r, g, b)) self.level_based_colors = { logging.WARNING: 11, @@ -130,33 +133,38 @@ class Formatter(logging.Formatter): logging.FATAL: 9, } - self.process_name = { - "gtk": "GUI", - "helper": "GUI-Helper", - "service": "Service", - "control": "Control", - }.get(sys.argv[0].split("-")[-1], sys.argv[0]) - self.process_color = self.word_to_color(sys.argv[0]) + def _get_ansi_code(self, r, g, b): + return 16 + b + (6 * g) + (36 * r) - def word_to_color(self, word): + def _word_to_color(self, word): """Convert a word to a 8bit ansi color code.""" digit_sum = sum([ord(char) for char in word]) index = digit_sum % len(self.allowed_colors) return self.allowed_colors[index] - def allocate_debug_log_color(self, record): - """Pick a random color that ideally has enough contrast to the previously picked colors.""" - if self.file_color_mapping.get(record.pathname) is not None: - return self.file_color_mapping[record.pathname] + def _allocate_debug_log_color(self, record): + """Get the color that represents the source file of the log.""" + if self.file_color_mapping.get(record.filename) is not None: + return self.file_color_mapping[record.filename] - color = self.word_to_color(record.pathname) + color = self._word_to_color(record.filename) - if self.file_color_mapping.get(record.pathname) is None: + if self.file_color_mapping.get(record.filename) is None: # calculate the color for each file only once - self.file_color_mapping[record.pathname] = color + self.file_color_mapping[record.filename] = color return color + def _get_process_name(self): + """Generate a beaitiful to read name for this process.""" + name = sys.argv[0].split("/")[-1].split("-")[-1] + return { + "gtk": "GUI", + "helper": "GUI-Helper", + "service": "Service", + "control": "Control", + }.get(name, name) + def _get_format(self, record): """Generate a message format string.""" debug_mode = is_debug() @@ -169,23 +177,27 @@ class Formatter(logging.Formatter): color = self.level_based_colors[record.levelno] return f"\033[38;5;{color}m%(levelname)s\033[0m: %(message)s" + color = self._allocate_debug_log_color(record) if record.levelno in [logging.ERROR, logging.WARNING, logging.FATAL]: - color = self.level_based_colors[record.levelno] + # underline + style = f"\033[4;38;5;{color}m" else: - color = self.allocate_debug_log_color(record) + style = f"\033[38;5;{color}m" + + process_color = self._word_to_color(f"{os.getpid()}{sys.argv[0]}") return ( # noqa f'{datetime.now().strftime("%H:%M:%S.%f")} ' - f"\033[38;5;{self.process_color}m" # color + f"\033[38;5;{process_color}m" # color f"{os.getpid()} " - f"{self.process_name} " + f"{self._get_process_name()} " "\033[0m" # end style - f"\033[38;5;{color}m" # color + f"{style}" f"%(levelname)s " f"%(filename)s:%(lineno)d: " "%(message)s" "\033[0m" # end style - ) + ).replace(" ", " ") def format(self, record): """Overwritten format function.""" @@ -195,7 +207,7 @@ class Formatter(logging.Formatter): handler = logging.StreamHandler() -handler.setFormatter(Formatter()) +handler.setFormatter(ColorfulFormatter()) logger.addHandler(handler) logger.setLevel(logging.INFO) logging.getLogger("asyncio").setLevel(logging.WARNING) @@ -274,7 +286,7 @@ def add_filehandler(log_path=LOG_PATH): file.writelines(content) file_handler = logging.FileHandler(log_path) - file_handler.setFormatter(Formatter()) + file_handler.setFormatter(ColorfulFormatter()) logger.addHandler(file_handler) logger.info('Starting logging to "%s"', log_path)