From afdab2570782604dc0e3c22ad96948c16daab434 Mon Sep 17 00:00:00 2001 From: Robert Kaussow Date: Sat, 12 Jun 2021 16:32:37 +0200 Subject: [PATCH] feat: add json and simple log formatter --- poetry.lock | 15 --- prometheuspvesd/cli.py | 25 +++- prometheuspvesd/config.py | 9 +- prometheuspvesd/discovery.py | 2 +- prometheuspvesd/logger.py | 246 +++++++++++++++++++++++++++++++++++ prometheuspvesd/utils.py | 223 ------------------------------- 6 files changed, 270 insertions(+), 250 deletions(-) create mode 100644 prometheuspvesd/logger.py diff --git a/poetry.lock b/poetry.lock index d6a6789..1e3576b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -927,26 +927,18 @@ pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, - {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, - {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, - {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, - {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, - {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, - {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, - {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, - {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, @@ -967,29 +959,22 @@ requests = [ {file = "ruamel.yaml.clib-0.2.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2"}, {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026"}, {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b"}, - {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1236df55e0f73cd138c0eca074ee086136c3f16a97c2ac719032c050f7e0622f"}, {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-win32.whl", hash = "sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f"}, {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62"}, {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c"}, {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988"}, - {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:2fd336a5c6415c82e2deb40d08c222087febe0aebe520f4d21910629018ab0f3"}, {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-win32.whl", hash = "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2"}, {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91"}, {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6"}, {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e"}, - {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:75f0ee6839532e52a3a53f80ce64925ed4aed697dd3fa890c4c918f3304bd4f4"}, {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-win32.whl", hash = "sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6"}, {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5"}, {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0"}, {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99"}, - {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8be05be57dc5c7b4a0b24edcaa2f7275866d9c907725226cdde46da09367d923"}, {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win32.whl", hash = "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1"}, {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b"}, {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6ac7e45367b1317e56f1461719c853fd6825226f45b835df7436bb04031fd8a"}, {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b4b0d31f2052b3f9f9b5327024dc629a253a83d8649d4734ca7f35b60ec3e9e5"}, - {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:1f8c0a4577c0e6c99d208de5c4d3fd8aceed9574bb154d7a2b21c16bb924154c"}, - {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-win32.whl", hash = "sha256:46d6d20815064e8bb023ea8628cfb7402c0f0e83de2c2227a88097e239a7dffd"}, - {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:6c0a5dc52fc74eb87c67374a4e554d4761fd42a4d01390b7e868b30d21f4b8bb"}, {file = "ruamel.yaml.clib-0.2.2.tar.gz", hash = "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7"}, ] six = [ diff --git a/prometheuspvesd/cli.py b/prometheuspvesd/cli.py index 4a388f9..a941888 100644 --- a/prometheuspvesd/cli.py +++ b/prometheuspvesd/cli.py @@ -13,8 +13,8 @@ from prometheuspvesd import __version__ from prometheuspvesd.config import SingleConfig from prometheuspvesd.discovery import Discovery from prometheuspvesd.exception import APIError +from prometheuspvesd.logger import SingleLog from prometheuspvesd.model import HostList -from prometheuspvesd.utils import SingleLog class PrometheusSD: @@ -54,7 +54,11 @@ class PrometheusSD: """ parser = argparse.ArgumentParser(description="Prometheus Service Discovery for Proxmox VE") parser.add_argument( - "-c", "--config", dest="config_file", help="location of configuration file" + "-c", + "--config", + dest="config_file", + action="store", + help="location of configuration file" ) parser.add_argument( "-o", "--output", dest="output_file", action="store", help="output file" @@ -68,10 +72,15 @@ class PrometheusSD: help="delay between discovery runs" ) parser.add_argument( - "--no-service", - dest="service", - action="store_false", - help="run discovery as a service" + "--no-service", dest="service", action="store_false", help="run discovery only once" + ) + parser.add_argument( + "-f", + "--log-format", + dest="logging.format", + metavar="LOG_FORMAT", + action="store", + help="used log format" ) parser.add_argument( "-v", dest="logging.level", action="append_const", const=-1, help="increase log level" @@ -92,7 +101,9 @@ class PrometheusSD: self.log.sysexit_with_message(e) try: - self.log.set_level(config.config["logging"]["level"]) + self.log.update_logger( + config.config["logging"]["level"], config.config["logging"]["format"] + ) except ValueError as e: self.log.sysexit_with_message("Can not set log level.\n{}".format(str(e))) diff --git a/prometheuspvesd/config.py b/prometheuspvesd/config.py index 6dd6349..f72d0d5 100644 --- a/prometheuspvesd/config.py +++ b/prometheuspvesd/config.py @@ -43,11 +43,11 @@ class Config(): "file": True, "type": environs.Env().str }, - "logging.json": { - "default": False, - "env": "LOG_JSON", + "logging.format": { + "default": "console", + "env": "LOG_FORMAT", "file": True, - "type": environs.Env().bool + "type": environs.Env().str }, "output_file": { "default": default_output_file, @@ -213,6 +213,7 @@ class Config(): defaults.pop("config_file") defaults["logging"]["level"] = defaults["logging"]["level"].upper() + defaults["logging"]["format"] = defaults["logging"]["format"].strip().lower() Path(PurePath(self.config_file).parent).mkdir(parents=True, exist_ok=True) Path(PurePath(defaults["output_file"]).parent).mkdir(parents=True, exist_ok=True) diff --git a/prometheuspvesd/discovery.py b/prometheuspvesd/discovery.py index 3c2474d..dbb073f 100644 --- a/prometheuspvesd/discovery.py +++ b/prometheuspvesd/discovery.py @@ -12,7 +12,7 @@ from prometheuspvesd.config import SingleConfig from prometheuspvesd.exception import APIError from prometheuspvesd.model import Host from prometheuspvesd.model import HostList -from prometheuspvesd.utils import SingleLog +from prometheuspvesd.logger import SingleLog from prometheuspvesd.utils import to_bool try: diff --git a/prometheuspvesd/logger.py b/prometheuspvesd/logger.py new file mode 100644 index 0000000..1411d89 --- /dev/null +++ b/prometheuspvesd/logger.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python3 +"""Global utility methods and classes.""" + +import logging +import os +import sys + +import colorama +from pythonjsonlogger import jsonlogger + +from prometheuspvesd.utils import Singleton +from prometheuspvesd.utils import to_bool + +CONSOLE_FORMAT = "{}{}[%(levelname)s]{} %(message)s" +JSON_FORMAT = "%(asctime)s %(levelname)s %(message)s" + + +def _should_do_markup(): + py_colors = os.environ.get("PY_COLORS", None) + if py_colors is not None: + return to_bool(py_colors) + + return sys.stdout.isatty() and os.environ.get("TERM") != "dumb" + + +colorama.init(autoreset=True, strip=not _should_do_markup()) + + +class LogFilter(object): + """A custom log filter which excludes log messages above the logged level.""" + + def __init__(self, level): + """ + Initialize a new custom log filter. + + :param level: Log level limit + :returns: None + + """ + self.__level = level + + def filter(self, logRecord): # noqa + # https://docs.python.org/3/library/logging.html#logrecord-attributes + return logRecord.levelno <= self.__level + + +class SimpleFormatter(logging.Formatter): + """Logging Formatter for simple logs.""" + + def format(self, record): # noqa + return logging.Formatter.format(self, record) + + +class MultilineFormatter(logging.Formatter): + """Logging Formatter to reset color after newline characters.""" + + def format(self, record): # noqa + record.msg = record.msg.replace("\n", "\n{}... ".format(colorama.Style.RESET_ALL)) + return logging.Formatter.format(self, record) + + +class MultilineJsonFormatter(jsonlogger.JsonFormatter): + """Logging Formatter to remove newline characters.""" + + def format(self, record): # noqa + record.msg = record.msg.replace("\n", " ") + return jsonlogger.JsonFormatter.format(self, record) + + +class Log: + """Handle logging.""" + + def __init__(self, level=logging.WARN, name="prometheuspvesd", log_format="console"): + self.logger = logging.getLogger(name) + self.logger.setLevel(level) + self.logger.addHandler(self._get_error_handler(log_format)) + self.logger.addHandler(self._get_warn_handler(log_format)) + self.logger.addHandler(self._get_info_handler(log_format)) + self.logger.addHandler(self._get_critical_handler(log_format)) + self.logger.addHandler(self._get_debug_handler(log_format)) + self.logger.propagate = False + + def _get_error_handler(self, log_format): + handler = logging.StreamHandler(sys.stderr) + handler.setLevel(logging.ERROR) + handler.addFilter(LogFilter(logging.ERROR)) + + if log_format == "json": + handler.setFormatter(MultilineJsonFormatter(JSON_FORMAT)) + elif log_format == "simple": + handler.setFormatter(SimpleFormatter()) + else: + handler.setFormatter( + MultilineFormatter( + self.error( + CONSOLE_FORMAT.format( + colorama.Fore.RED, colorama.Style.BRIGHT, colorama.Style.RESET_ALL + ) + ) + ) + ) + + return handler + + def _get_warn_handler(self, log_format): + handler = logging.StreamHandler(sys.stdout) + handler.setLevel(logging.WARN) + handler.addFilter(LogFilter(logging.WARN)) + + if log_format == "json": + handler.setFormatter(MultilineJsonFormatter(JSON_FORMAT)) + elif log_format == "simple": + handler.setFormatter(SimpleFormatter()) + else: + handler.setFormatter( + MultilineFormatter( + self.warn( + CONSOLE_FORMAT.format( + colorama.Fore.YELLOW, colorama.Style.BRIGHT, colorama.Style.RESET_ALL + ) + ) + ) + ) + + return handler + + def _get_info_handler(self, log_format): + handler = logging.StreamHandler(sys.stdout) + handler.setLevel(logging.INFO) + handler.addFilter(LogFilter(logging.INFO)) + + if log_format == "json": + handler.setFormatter(MultilineJsonFormatter(JSON_FORMAT)) + elif log_format == "simple": + handler.setFormatter(SimpleFormatter()) + else: + handler.setFormatter( + MultilineFormatter( + self.info( + CONSOLE_FORMAT.format( + colorama.Fore.CYAN, colorama.Style.BRIGHT, colorama.Style.RESET_ALL + ) + ) + ) + ) + + return handler + + def _get_critical_handler(self, log_format): + handler = logging.StreamHandler(sys.stderr) + handler.setLevel(logging.CRITICAL) + handler.addFilter(LogFilter(logging.CRITICAL)) + + if log_format == "json": + handler.setFormatter(MultilineJsonFormatter(JSON_FORMAT)) + elif log_format == "simple": + handler.setFormatter(SimpleFormatter()) + else: + handler.setFormatter( + MultilineFormatter( + self.critical( + CONSOLE_FORMAT.format( + colorama.Fore.RED, colorama.Style.BRIGHT, colorama.Style.RESET_ALL + ) + ) + ) + ) + + return handler + + def _get_debug_handler(self, log_format): + handler = logging.StreamHandler(sys.stderr) + handler.setLevel(logging.DEBUG) + handler.addFilter(LogFilter(logging.DEBUG)) + + if log_format == "json": + handler.setFormatter(MultilineJsonFormatter(JSON_FORMAT)) + elif log_format == "simple": + handler.setFormatter(SimpleFormatter()) + else: + handler.setFormatter( + MultilineFormatter( + self.critical( + CONSOLE_FORMAT.format( + colorama.Fore.BLUE, colorama.Style.BRIGHT, colorama.Style.RESET_ALL + ) + ) + ) + ) + + return handler + + def update_logger(self, level=None, log_level=None): + for handler in self.logger.handlers[:]: + self.logger.removeHandler(handler) + + self.logger.setLevel(level) + self.logger.addHandler(self._get_error_handler(log_level)) + self.logger.addHandler(self._get_warn_handler(log_level)) + self.logger.addHandler(self._get_info_handler(log_level)) + self.logger.addHandler(self._get_critical_handler(log_level)) + self.logger.addHandler(self._get_debug_handler(log_level)) + + def debug(self, msg): + """Format info messages and return string.""" + return msg + + def critical(self, msg): + """Format critical messages and return string.""" + return msg + + def error(self, msg): + """Format error messages and return string.""" + return msg + + def warn(self, msg): + """Format warn messages and return string.""" + return msg + + def info(self, msg): + """Format info messages and return string.""" + return msg + + def _color_text(self, color, msg): + """ + Colorize strings. + + :param color: colorama color settings + :param msg: string to colorize + :returns: string + + """ + return "{}{}{}".format(color, msg, colorama.Style.RESET_ALL) + + def sysexit(self, code=1): + sys.exit(code) + + def sysexit_with_message(self, msg, code=1): + self.logger.critical(str(msg)) + self.sysexit(code) + + +class SingleLog(Log, metaclass=Singleton): + """Singleton logging class.""" + + pass diff --git a/prometheuspvesd/utils.py b/prometheuspvesd/utils.py index 38c35e9..bbb37bf 100644 --- a/prometheuspvesd/utils.py +++ b/prometheuspvesd/utils.py @@ -1,33 +1,13 @@ #!/usr/bin/env python3 """Global utility methods and classes.""" -import logging -import os -import sys from distutils.util import strtobool -import colorama -from pythonjsonlogger import jsonlogger - -CONSOLE_FORMAT = "{}{}[%(levelname)s]{} %(message)s" -JSON_FORMAT = "(asctime) (levelname) (message)" - def to_bool(string): return bool(strtobool(str(string))) -def _should_do_markup(): - py_colors = os.environ.get("PY_COLORS", None) - if py_colors is not None: - return to_bool(py_colors) - - return sys.stdout.isatty() and os.environ.get("TERM") != "dumb" - - -colorama.init(autoreset=True, strip=not _should_do_markup()) - - class Singleton(type): """Meta singleton class.""" @@ -37,206 +17,3 @@ class Singleton(type): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] - - -class LogFilter(object): - """A custom log filter which excludes log messages above the logged level.""" - - def __init__(self, level): - """ - Initialize a new custom log filter. - - :param level: Log level limit - :returns: None - - """ - self.__level = level - - def filter(self, logRecord): # noqa - # https://docs.python.org/3/library/logging.html#logrecord-attributes - return logRecord.levelno <= self.__level - - -class MultilineFormatter(logging.Formatter): - """Logging Formatter to reset color after newline characters.""" - - def format(self, record): # noqa - record.msg = record.msg.replace("\n", "\n{}... ".format(colorama.Style.RESET_ALL)) - return logging.Formatter.format(self, record) - - -class MultilineJsonFormatter(jsonlogger.JsonFormatter): - """Logging Formatter to remove newline characters.""" - - def format(self, record): # noqa - record.msg = record.msg.replace("\n", " ") - return jsonlogger.JsonFormatter.format(self, record) - - -class Log: - """Handle logging.""" - - def __init__(self, level=logging.WARN, name="prometheuspvesd", json=False): - self.logger = logging.getLogger(name) - self.logger.setLevel(level) - self.logger.addHandler(self._get_error_handler(json=json)) - self.logger.addHandler(self._get_warn_handler(json=json)) - self.logger.addHandler(self._get_info_handler(json=json)) - self.logger.addHandler(self._get_critical_handler(json=json)) - self.logger.addHandler(self._get_debug_handler(json=json)) - self.logger.propagate = False - - def _get_error_handler(self, json=False): - handler = logging.StreamHandler(sys.stderr) - handler.setLevel(logging.ERROR) - handler.addFilter(LogFilter(logging.ERROR)) - handler.setFormatter( - MultilineFormatter( - self.error( - CONSOLE_FORMAT.format( - colorama.Fore.RED, colorama.Style.BRIGHT, colorama.Style.RESET_ALL - ) - ) - ) - ) - - if json: - handler.setFormatter(MultilineJsonFormatter(JSON_FORMAT)) - - return handler - - def _get_warn_handler(self, json=False): - handler = logging.StreamHandler(sys.stdout) - handler.setLevel(logging.WARN) - handler.addFilter(LogFilter(logging.WARN)) - handler.setFormatter( - MultilineFormatter( - self.warn( - CONSOLE_FORMAT.format( - colorama.Fore.YELLOW, colorama.Style.BRIGHT, colorama.Style.RESET_ALL - ) - ) - ) - ) - - if json: - handler.setFormatter(MultilineJsonFormatter(JSON_FORMAT)) - - return handler - - def _get_info_handler(self, json=False): - handler = logging.StreamHandler(sys.stdout) - handler.setLevel(logging.INFO) - handler.addFilter(LogFilter(logging.INFO)) - handler.setFormatter( - MultilineFormatter( - self.info( - CONSOLE_FORMAT.format( - colorama.Fore.CYAN, colorama.Style.BRIGHT, colorama.Style.RESET_ALL - ) - ) - ) - ) - - if json: - handler.setFormatter(MultilineJsonFormatter(JSON_FORMAT)) - - return handler - - def _get_critical_handler(self, json=False): - handler = logging.StreamHandler(sys.stderr) - handler.setLevel(logging.CRITICAL) - handler.addFilter(LogFilter(logging.CRITICAL)) - handler.setFormatter( - MultilineFormatter( - self.critical( - CONSOLE_FORMAT.format( - colorama.Fore.RED, colorama.Style.BRIGHT, colorama.Style.RESET_ALL - ) - ) - ) - ) - - if json: - handler.setFormatter(MultilineJsonFormatter(JSON_FORMAT)) - - return handler - - def _get_debug_handler(self, json=False): - handler = logging.StreamHandler(sys.stderr) - handler.setLevel(logging.DEBUG) - handler.addFilter(LogFilter(logging.DEBUG)) - handler.setFormatter( - MultilineFormatter( - self.critical( - CONSOLE_FORMAT.format( - colorama.Fore.BLUE, colorama.Style.BRIGHT, colorama.Style.RESET_ALL - ) - ) - ) - ) - - if json: - handler.setFormatter(MultilineJsonFormatter(JSON_FORMAT)) - - return handler - - def set_level(self, s): - self.logger.setLevel(s) - - def debug(self, msg): - """Format info messages and return string.""" - return msg - - def critical(self, msg): - """Format critical messages and return string.""" - return msg - - def error(self, msg): - """Format error messages and return string.""" - return msg - - def warn(self, msg): - """Format warn messages and return string.""" - return msg - - def info(self, msg): - """Format info messages and return string.""" - return msg - - def _color_text(self, color, msg): - """ - Colorize strings. - - :param color: colorama color settings - :param msg: string to colorize - :returns: string - - """ - return "{}{}{}".format(color, msg, colorama.Style.RESET_ALL) - - def sysexit(self, code=1): - sys.exit(code) - - def sysexit_with_message(self, msg, code=1): - self.logger.critical(str(msg)) - self.sysexit(code) - - -class SingleLog(Log, metaclass=Singleton): - """Singleton logging class.""" - - pass - - -class UnsafeTag: - """Handle custom yaml unsafe tag.""" - - yaml_tag = u"!unsafe" - - def __init__(self, value): - self.unsafe = value - - @staticmethod - def yaml_constructor(loader, node): - return loader.construct_scalar(node)