Files
adb-autosync/BetterADBSync/SAOLogging.py
2025-10-25 20:59:58 -04:00

100 lines
4.4 KiB
Python
Executable File

"""Nice logging, with colors on Linux."""
from typing import Any, Union
import logging
import sys
class ColoredFormatter(logging.Formatter):
"""Logging Formatter to add colors"""
fg_bright_blue = "\x1b[94m"
fg_yellow = "\x1b[33m"
fg_red = "\x1b[31m"
fg_bright_red_bold = "\x1b[91;1m"
reset = "\x1b[0m"
def __init__(self, fmt, datefmt):
super().__init__()
self.messagefmt = fmt
self.datefmt = datefmt
self.formats = {
logging.DEBUG: "{}{}{}".format(self.fg_bright_blue, self.messagefmt, self.reset),
logging.INFO: "{}".format(self.messagefmt),
logging.WARNING: "{}{}{}".format(self.fg_yellow, self.messagefmt, self.reset),
logging.ERROR: "{}{}{}".format(self.fg_red, self.messagefmt, self.reset),
logging.CRITICAL: "{}{}{}".format(self.fg_bright_red_bold, self.messagefmt, self.reset)
}
self.formatters = {
logging.DEBUG: logging.Formatter(self.formats[logging.DEBUG], datefmt = self.datefmt),
logging.INFO: logging.Formatter(self.formats[logging.INFO], datefmt = self.datefmt),
logging.WARNING: logging.Formatter(self.formats[logging.WARNING], datefmt = self.datefmt),
logging.ERROR: logging.Formatter(self.formats[logging.ERROR], datefmt = self.datefmt),
logging.CRITICAL: logging.Formatter(self.formats[logging.CRITICAL], datefmt = self.datefmt)
}
def format(self, record):
formatter = self.formatters[record.levelno]
return formatter.format(record)
def setup_root_logger(
no_color: bool = False,
verbosity_level: int = 0,
quietness_level: int = 0,
messagefmt: str = "[%(asctime)s][%(levelname)s] %(message)s (%(filename)s:%(lineno)d)",
messagefmt_verbose: str = "[%(asctime)s][%(levelname)s] %(message)s (%(filename)s:%(lineno)d)",
datefmt: str = "%Y-%m-%d %H:%M:%S"
):
messagefmt_to_use = messagefmt_verbose if verbosity_level else messagefmt
logging_level = 10 * (2 + quietness_level - verbosity_level)
if not no_color and sys.platform == "linux":
formatter_class = ColoredFormatter
else:
formatter_class = logging.Formatter
root_logger = logging.getLogger()
root_logger.setLevel(logging_level)
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter_class(fmt = messagefmt_to_use, datefmt = datefmt))
root_logger.addHandler(console_handler)
def logging_fatal(message, log_stack_info: bool = True, exit_code: int = 1):
logging.critical(message)
logging.debug("Stack Trace", stack_info = log_stack_info)
logging.critical("Exiting")
raise SystemExit(exit_code)
def log_tree(title, tree, finals = None, log_leaves_types = True, logging_level = logging.INFO):
"""Log tree nicely if it is a dictionary.
log_leaves_types can be False to log no leaves, True to log all leaves, or a tuple of types for which to log."""
if finals is None:
finals = []
if not isinstance(tree, dict):
logging.log(msg = "{}{}{}".format(
"".join([" " if final else "" for final in finals[:-1]] + ["" if final else "" for final in finals[-1:]]),
title,
": {}".format(tree) if log_leaves_types is not False and (log_leaves_types is True or isinstance(tree, log_leaves_types)) else ""
), level = logging_level)
else:
logging.log(msg = "{}{}".format(
"".join([" " if final else "" for final in finals[:-1]] + ["" if final else "" for final in finals[-1:]]),
title
), level = logging_level)
tree_items = list(tree.items())
for key, value in tree_items[:-1]:
log_tree(key, value, finals = finals + [False], log_leaves_types = log_leaves_types, logging_level = logging_level)
for key, value in tree_items[-1:]:
log_tree(key, value, finals = finals + [True], log_leaves_types = log_leaves_types, logging_level = logging_level)
# like logging.CRITICAl, logging.DEBUG etc
FATAL = 60
def perror(s: Union[str, Any], e: Exception, logging_level: int = logging.ERROR):
strerror = e.strerror if (isinstance(e, OSError) and e.strerror is not None) else e.__class__.__name__
msg = f"{s}{': ' if s else ''}{strerror}"
if logging_level == FATAL:
logging_fatal(msg)
else:
logging.log(logging_level, msg)