544 Stimmen

Wie kann ich die Python-Logging-Ausgabe einfärben?

Vor einiger Zeit sah ich eine Mono-Anwendung mit farbiger Ausgabe, vermutlich aufgrund des Protokollsystems (da alle Meldungen standardisiert waren).

Jetzt hat Python die logging Modul, mit dem Sie eine Vielzahl von Optionen zur Anpassung der Ausgabe angeben können. Ich stelle mir vor, dass etwas Ähnliches auch mit Python möglich wäre, aber ich kann nirgendwo herausfinden, wie man das macht.

Gibt es eine Möglichkeit, die Python logging Modulausgabe in Farbe?

Ich möchte z. B. Fehler in rot, Fehlermeldungen in blau oder gelb usw.

Natürlich würde dies wahrscheinlich ein kompatibles Terminal erfordern (die meisten modernen Terminals sind kompatibel); aber ich könnte auf die ursprüngliche logging Ausgabe, wenn Farbe nicht unterstützt wird.

Haben Sie eine Idee, wie ich mit dem Logging-Modul eine farbige Ausgabe erhalten kann?

15voto

camillobruni Punkte 2228

Ich habe das Beispiel von airmind aktualisiert und unterstütze nun Tags für Vorder- und Hintergrund. Verwenden Sie einfach die Farbvariablen $BLACK - $WHITE in Ihrem Log-Formatierungsstring. Um den Hintergrund zu setzen, verwenden Sie einfach $BG-BLACK - $BG-WHITE.

import logging

BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)

COLORS = {
    'WARNING'  : YELLOW,
    'INFO'     : WHITE,
    'DEBUG'    : BLUE,
    'CRITICAL' : YELLOW,
    'ERROR'    : RED,
    'RED'      : RED,
    'GREEN'    : GREEN,
    'YELLOW'   : YELLOW,
    'BLUE'     : BLUE,
    'MAGENTA'  : MAGENTA,
    'CYAN'     : CYAN,
    'WHITE'    : WHITE,
}

RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ  = "\033[1m"

class ColorFormatter(logging.Formatter):

    def __init__(self, *args, **kwargs):
        # can't do super(...) here because Formatter is an old school class
        logging.Formatter.__init__(self, *args, **kwargs)

    def format(self, record):
        levelname = record.levelname
        color     = COLOR_SEQ % (30 + COLORS[levelname])
        message   = logging.Formatter.format(self, record)
        message   = message.replace("$RESET", RESET_SEQ)\
                           .replace("$BOLD",  BOLD_SEQ)\
                           .replace("$COLOR", color)
        for k,v in COLORS.items():
            message = message.replace("$" + k,    COLOR_SEQ % (v+30))\
                             .replace("$BG" + k,  COLOR_SEQ % (v+40))\
                             .replace("$BG-" + k, COLOR_SEQ % (v+40))
        return message + RESET_SEQ

logging.ColorFormatter = ColorFormatter

Jetzt können Sie einfach folgendes in Ihrer Konfigurationsdatei tun:

[formatter_colorFormatter]
class=logging.ColorFormatter
format= $COLOR%(levelname)s $RESET %(asctime)s $BOLD$COLOR%(name)s$RESET %(message)s

11voto

Nick Punkte 26768

Sehen Sie sich die folgende Lösung an. Der Stream-Handler sollte das Ding sein, das die Färbung vornimmt, dann haben Sie die Möglichkeit, Wörter zu färben und nicht nur die ganze Zeile (mit dem Formatter).

http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html

11voto

ToTamire Punkte 783

Farblogs

Installation

pip install coloredlogs

Verwendung

Minimale Nutzung:
import logging
import coloredlogs

coloredlogs.install()  # install a handler on the root logger

logging.debug('message with level debug')
logging.info('message with level info')
logging.warning('message with level warning')
logging.error('message with level error')
logging.critical('message with level critical')

Ergebnisse mit: minimal usage

Beginnen Sie mit der Fehlersuche auf Nachrichtenebene:
import logging
import coloredlogs

coloredlogs.install(level='DEBUG')  # install a handler on the root logger with level debug

logging.debug('message with level debug')
logging.info('message with level info')
logging.warning('message with level warning')
logging.error('message with level error')
logging.critical('message with level critical')

Ergebnisse mit: debug level

Nachrichten aus Bibliotheken ausblenden:
import logging
import coloredlogs

logger = logging.getLogger(__name__)  # get a specific logger object
coloredlogs.install(level='DEBUG')  # install a handler on the root logger with level debug
coloredlogs.install(level='DEBUG', logger=logger)  # pass a specific logger object

logging.debug('message with level debug')
logging.info('message with level info')
logging.warning('message with level warning')
logging.error('message with level error')
logging.critical('message with level critical')

Ergebnisse mit: debug level

Protokollmeldungen formatieren:
import logging
import coloredlogs

logger = logging.getLogger(__name__)  # get a specific logger object
coloredlogs.install(level='DEBUG')  # install a handler on the root logger with level debug
coloredlogs.install(level='DEBUG', logger=logger)  # pass a specific logger object
coloredlogs.install(
    level='DEBUG', logger=logger,
    fmt='%(asctime)s.%(msecs)03d %(filename)s:%(lineno)d %(levelname)s %(message)s'
)

logging.debug('message with level debug')
logging.info('message with level info')
logging.warning('message with level warning')
logging.error('message with level error')
logging.critical('message with level critical')

Ergebnisse mit: format log messages

Verfügbare Formatattribute:
  • %(asctime)s - Zeit als menschenlesbare Zeichenkette, wann der Protokollierungsaufruf erfolgte
  • %(created)f - Zeit als Float, zu der der Protokollierungsaufruf getätigt wurde
  • %(filename)s - Name der Datei
  • %(funcName)s - Name der Funktion, die den Protokollierungsaufruf enthält
  • %(hostname)s - System-Hostname
  • %(levelname)s - Ebene der Textprotokollierung
  • %(levelno)s - Ganzzahlige Protokollierungsstufe
  • %(lineno)d - Zeilennummer, in der der Logging-Aufruf getätigt wurde
  • %(message)s - An den Protokollierungsaufruf übergebene Nachricht (wie %(msg)s )
  • %(module)s - Dateiname ohne Erweiterung, von dem aus die Protokollierung aufgerufen wurde
  • %(msecs)d - Millisekundenanteil des Zeitpunkts, zu dem der Protokollierungsaufruf erfolgte
  • %(msg)s - An den Protokollierungsaufruf übergebene Nachricht (wie %(message)s )
  • %(name)s - Name des Loggers
  • %(pathname)s - Vollständiger Pfadname der Datei, die den Protokollierungsaufruf enthält
  • %(process)d - Prozess-ID
  • %(processName)s - Name des Prozesses
  • %(programname)s - System Programmname
  • %(relativeCreated)d - Zeitpunkt des Logging-Aufrufs als Ganzzahl in Millisekunden, bezogen auf den Zeitpunkt, zu dem das Logging-Modul geladen wurde
  • %(thread)d - Gewinde-ID
  • %(threadName)s - Name des Themas
  • %(username)s - System-Benutzername

Quellen:

Paket Coloredlogs

Protokollierungsbibliothek

11voto

Mikko Ohtamaa Punkte 75407

Jetzt gibt es ein freigegebenes PyPi-Modul für anpassbare farbige Logging-Ausgaben:

https://pypi.python.org/pypi/rainbow_logging_handler/

y

https://github.com/laysakura/rainbow_logging_handler

  • Unterstützt Windows

  • Unterstützt Django

  • Anpassbare Farben

Da es als Python-Ei verteilt wird, ist es sehr einfach für jede Python-Anwendung zu installieren.

10voto

dux2 Punkte 1600

Wie wäre es, zusätzlich zur Einfärbung nach Stufe auch die Argumente der Protokollnachrichten mit wechselnden Farben hervorzuheben? Ich habe kürzlich einfachen Code dafür geschrieben. Ein weiterer Vorteil ist, dass der Log-Aufruf mit der Klammerformatierung von Python 3 gemacht wird. ( "{}" ).

Aktuellen Code und Beispiele finden Sie hier: https://github.com/davidohana/colargulog

Beispiel für Logging-Code:

root_logger = logging.getLogger()
console_handler = logging.StreamHandler(stream=sys.stdout)
console_format = "%(asctime)s - %(levelname)-8s - %(name)-25s - %(message)s"
colored_formatter = ColorizedArgsFormatter(console_format)
console_handler.setFormatter(colored_formatter)
root_logger.addHandler(console_handler)

logger = logging.getLogger(__name__)
logger.info("Hello World")
logger.info("Request from {} handled in {:.3f} ms", socket.gethostname(), 11)
logger.info("Request from {} handled in {:.3f} ms", "127.0.0.1", 33.1)
logger.info("My favorite drinks are {}, {}, {}, {}", "milk", "wine", "tea", "beer")
logger.debug("this is a {} message", logging.getLevelName(logging.DEBUG))
logger.info("this is a {} message", logging.getLevelName(logging.INFO))
logger.warning("this is a {} message", logging.getLevelName(logging.WARNING))
logger.error("this is a {} message", logging.getLevelName(logging.ERROR))
logger.critical("this is a {} message", logging.getLevelName(logging.CRITICAL))
logger.info("Does old-style formatting also work? %s it is, but no colors (yet)", True)

Ausgabe:

enter image description here

Umsetzung:

"""
colargulog - Python3 Logging with Colored Arguments and new string formatting style

Written by david.ohana@ibm.com
License: Apache-2.0
"""

import logging
import logging.handlers
import re

class ColorCodes:
    grey = "\x1b[38;21m"
    green = "\x1b[1;32m"
    yellow = "\x1b[33;21m"
    red = "\x1b[31;21m"
    bold_red = "\x1b[31;1m"
    blue = "\x1b[1;34m"
    light_blue = "\x1b[1;36m"
    purple = "\x1b[1;35m"
    reset = "\x1b[0m"

class ColorizedArgsFormatter(logging.Formatter):
    arg_colors = [ColorCodes.purple, ColorCodes.light_blue]
    level_fields = ["levelname", "levelno"]
    level_to_color = {
        logging.DEBUG: ColorCodes.grey,
        logging.INFO: ColorCodes.green,
        logging.WARNING: ColorCodes.yellow,
        logging.ERROR: ColorCodes.red,
        logging.CRITICAL: ColorCodes.bold_red,
    }

    def __init__(self, fmt: str):
        super().__init__()
        self.level_to_formatter = {}

        def add_color_format(level: int):
            color = ColorizedArgsFormatter.level_to_color[level]
            _format = fmt
            for fld in ColorizedArgsFormatter.level_fields:
                search = "(%\(" + fld + "\).*?s)"
                _format = re.sub(search, f"{color}\\1{ColorCodes.reset}", _format)
            formatter = logging.Formatter(_format)
            self.level_to_formatter[level] = formatter

        add_color_format(logging.DEBUG)
        add_color_format(logging.INFO)
        add_color_format(logging.WARNING)
        add_color_format(logging.ERROR)
        add_color_format(logging.CRITICAL)

    @staticmethod
    def rewrite_record(record: logging.LogRecord):
        if not BraceFormatStyleFormatter.is_brace_format_style(record):
            return

        msg = record.msg
        msg = msg.replace("{", "_{{")
        msg = msg.replace("}", "_}}")
        placeholder_count = 0
        # add ANSI escape code for next alternating color before each formatting parameter
        # and reset color after it.
        while True:
            if "_{{" not in msg:
                break
            color_index = placeholder_count % len(ColorizedArgsFormatter.arg_colors)
            color = ColorizedArgsFormatter.arg_colors[color_index]
            msg = msg.replace("_{{", color + "{", 1)
            msg = msg.replace("_}}", "}" + ColorCodes.reset, 1)
            placeholder_count += 1

        record.msg = msg.format(*record.args)
        record.args = []

    def format(self, record):
        orig_msg = record.msg
        orig_args = record.args
        formatter = self.level_to_formatter.get(record.levelno)
        self.rewrite_record(record)
        formatted = formatter.format(record)

        # restore log record to original state for other handlers
        record.msg = orig_msg
        record.args = orig_args
        return formatted

class BraceFormatStyleFormatter(logging.Formatter):
    def __init__(self, fmt: str):
        super().__init__()
        self.formatter = logging.Formatter(fmt)

    @staticmethod
    def is_brace_format_style(record: logging.LogRecord):
        if len(record.args) == 0:
            return False

        msg = record.msg
        if '%' in msg:
            return False

        count_of_start_param = msg.count("{")
        count_of_end_param = msg.count("}")

        if count_of_start_param != count_of_end_param:
            return False

        if count_of_start_param != len(record.args):
            return False

        return True

    @staticmethod
    def rewrite_record(record: logging.LogRecord):
        if not BraceFormatStyleFormatter.is_brace_format_style(record):
            return

        record.msg = record.msg.format(*record.args)
        record.args = []

    def format(self, record):
        orig_msg = record.msg
        orig_args = record.args
        self.rewrite_record(record)
        formatted = self.formatter.format(record)

        # restore log record to original state for other handlers
        record.msg = orig_msg
        record.args = orig_args
        return formatted

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X