Ich verwende den Python- logging
Mechanismus, um die Ausgabe auf dem Bildschirm zu drucken. Ich könnte dies mit print-Anweisungen tun, möchte dem Benutzer jedoch eine genauere Granularität ermöglichen, um bestimmte Ausgabetypen zu deaktivieren. Ich mag das Format, das für Fehler gedruckt wird, würde aber ein einfacheres Format bevorzugen, wenn der Ausgabepegel "info" ist.
Zum Beispiel:
logger.error("Running cmd failed")
logger.info("Running cmd passed")
In diesem Beispiel möchte ich, dass das Format des Fehlers anders gedruckt wird:
# error
Aug 27, 2009 - ERROR: Running cmd failed
# info
Running cmd passed
Ist es möglich, unterschiedliche Formate für unterschiedliche Protokollebenen zu haben, ohne mehrere Protokollierungsobjekte zu haben? Ich würde es vorziehen, dies zu tun, ohne den Logger nach seiner Erstellung zu ändern, da es eine große Anzahl von if / else-Anweisungen gibt, um zu bestimmen, wie die Ausgabe protokolliert werden soll.
quelle
Ich bin gerade auf dieses Problem gestoßen und hatte Probleme, die im obigen Beispiel verbleibenden "Löcher" auszufüllen. Hier ist eine vollständigere, funktionierende Version, die ich verwendet habe. Hoffentlich hilft das jemandem:
# Custom formatter class MyFormatter(logging.Formatter): err_fmt = "ERROR: %(msg)s" dbg_fmt = "DBG: %(module)s: %(lineno)d: %(msg)s" info_fmt = "%(msg)s" def __init__(self, fmt="%(levelno)s: %(msg)s"): logging.Formatter.__init__(self, fmt) def format(self, record): # Save the original format configured by the user # when the logger formatter was instantiated format_orig = self._fmt # Replace the original format with one customized by logging level if record.levelno == logging.DEBUG: self._fmt = MyFormatter.dbg_fmt elif record.levelno == logging.INFO: self._fmt = MyFormatter.info_fmt elif record.levelno == logging.ERROR: self._fmt = MyFormatter.err_fmt # Call the original formatter class to do the grunt work result = logging.Formatter.format(self, record) # Restore the original format configured by the user self._fmt = format_orig return result
Bearbeiten:
Komplimente von Halloleo, hier ist ein Beispiel, wie Sie das Obige in Ihrem Skript verwenden können:
Bearbeiten 2:
Die Python3-Protokollierung hat sich etwas geändert. Sehen Sie hier für einen Python3 Ansatz.
quelle
MyFormatter
Name" geändert, um dieself
Konsistenz zu erhöhen.fmt = MyFormatter()
<CR>hdlr = logging.StreamHandler(sys.stdout)
<CR><CR>
hdlr.setFormatter (fmt)<CR>
logging.root.addHandler (hdlr)<CR>
logging. root.setLevel (DEBUG) `<CR>logging.Formatter.format
hängt jetzt vomstyle
Parameter von ab__init__
.self._style = logging.PercentStyle(self._fmt)
super()
statt aufgerufen wirdlogging.Formatter
?Und wieder wie JS antworten, aber kompakter.
class SpecialFormatter(logging.Formatter): FORMATS = {logging.DEBUG :"DBG: %(module)s: %(lineno)d: %(message)s", logging.ERROR : "ERROR: %(message)s", logging.INFO : "%(message)s", 'DEFAULT' : "%(levelname)s: %(message)s"} def format(self, record): self._fmt = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT']) return logging.Formatter.format(self, record) hdlr = logging.StreamHandler(sys.stderr) hdlr.setFormatter(SpecialFormatter()) logging.root.addHandler(hdlr) logging.root.setLevel(logging.INFO)
quelle
logging.Formatter.format
hängt jetzt vomstyle
Parameter von ab__init__
.Dies ist eine Anpassung von Estanis Antwort auf die neue Implementierung,
logging.Formatter
die nun auf Formatierungsstilen beruht. Meins basiert auf dem'{'
Stilformat, kann aber angepasst werden. Könnte verfeinert werden, um allgemeiner zu sein und die Auswahl des Formatierungsstils und der benutzerdefinierten Nachrichten als Argumente__init__
zu ermöglichen.class SpecialFormatter(logging.Formatter): FORMATS = {logging.DEBUG : logging._STYLES['{']("{module} DEBUG: {lineno}: {message}"), logging.ERROR : logging._STYLES['{']("{module} ERROR: {message}"), logging.INFO : logging._STYLES['{']("{module}: {message}"), 'DEFAULT' : logging._STYLES['{']("{module}: {message}")} def format(self, record): # Ugly. Should be better self._style = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT']) return logging.Formatter.format(self, record) hdlr = logging.StreamHandler(sys.stderr) hdlr.setFormatter(SpecialFormatter()) logging.root.addHandler(hdlr) logging.root.setLevel(logging.INFO)
quelle
Anstatt sich auf Stile oder interne Felder zu verlassen, können Sie auch einen Formatierer erstellen, der abhängig von record.levelno (oder anderen Kriterien) an andere Formatierer delegiert. Dies ist meiner bescheidenen Meinung nach eine etwas sauberere Lösung. Der folgende Code sollte für jede Python-Version> = 2.7 funktionieren:
Der einfache Weg würde ungefähr so aussehen:
class MyFormatter(logging.Formatter): default_fmt = logging.Formatter('%(levelname)s in %(name)s: %(message)s') info_fmt = logging.Formatter('%(message)s') def format(self, record): if record.levelno == logging.INFO: return self.info_fmt.format(record) else: return self.default_fmt.format(record)
Aber Sie könnten es allgemeiner machen:
class VarFormatter(logging.Formatter): default_formatter = logging.Formatter('%(levelname)s in %(name)s: %(message)s') def __init__(self, formats): """ formats is a dict { loglevel : logformat } """ self.formatters = {} for loglevel in formats: self.formatters[loglevel] = logging.Formatter(formats[loglevel]) def format(self, record): formatter = self.formatters.get(record.levelno, self.default_formatter) return formatter.format(record)
Ich habe hier ein Diktat als Eingabe verwendet, aber natürlich können Sie auch Tupel verwenden, ** kwargs, was auch immer Ihr Boot schwimmt. Dies würde dann verwendet werden wie:
formatter = VarFormatter({logging.INFO: '[%(message)s]', logging.WARNING: 'warning: %(message)s'}) <... attach formatter to logger ...>
quelle
EIN WEG, DAS ZU TUN
Definieren Sie eine Klasse
import logging 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" format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" FORMATS = { logging.DEBUG: grey + format + reset, logging.INFO: grey + format + reset, logging.WARNING: yellow + format + reset, logging.ERROR: red + format + reset, logging.CRITICAL: bold_red + format + reset } def format(self, record): log_fmt = self.FORMATS.get(record.levelno) formatter = logging.Formatter(log_fmt) return formatter.format(record)
Logger instanziieren
# create logger with 'spam_application' logger = logging.getLogger("My_app") logger.setLevel(logging.DEBUG) # create console handler with a higher log level ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) ch.setFormatter(CustomFormatter()) logger.addHandler(ch)
Und benutze!
logger.debug("debug message") logger.info("info message") logger.warning("warning message") logger.error("error message") logger.critical("critical message")
Ergebnis
quelle
Die obige Lösung funktioniert mit Version 3.3.3. Mit 3.3.4 erhalten Sie jedoch den folgenden Fehler.
FORMATS = { logging.DEBUG : logging._STYLES['{']("{module} DEBUG: {lineno}: {message}"),
TypeError: Das 'Tupel'-Objekt kann nicht aufgerufen werden
Nach einigem Suchen in der Protokollierungsklasse Lib \ logging__init __. Py stellte ich fest, dass sich eine Datenstruktur von 3.3.3 auf 3.3.4 geändert hat, die das Problem verursacht
3.3.3
_STYLES = { '%': PercentStyle, '{': StrFormatStyle, '$': StringTemplateStyle }
3.3.4
_STYLES = { '%': (PercentStyle, BASIC_FORMAT), '{': (StrFormatStyle, '{levelname}:{name}:{message} AA'), '$': (StringTemplateStyle, '${levelname}:${name}:${message} BB'), }
Die aktualisierte Lösung ist daher
class SpecialFormatter(logging.Formatter): FORMATS = {logging.DEBUG : logging._STYLES['{'][0]("{module} DEBUG: {lineno}: {message}"), logging.ERROR : logging._STYLES['{'][0]("{module} ERROR: {message}"), logging.INFO : logging._STYLES['{'][0]("{module}: {message}"), 'DEFAULT' : logging._STYLES['{'][0]("{module}: {message}")} def format(self, record): # Ugly. Should be better self._style = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT']) return logging.Formatter.format(self, record)
quelle
from logging import StrFormatStyle
logging._STYLES['{'][0]
Wenn Sie nur die Formatierung bestimmter Ebenen überspringen möchten, können Sie etwas Einfacheres als die anderen Antworten wie die folgenden tun:
class FormatterNotFormattingInfo(logging.Formatter): def __init__(self, fmt = '%(levelname)s:%(message)s'): logging.Formatter.__init__(self, fmt) def format(self, record): if record.levelno == logging.INFO: return record.getMessage() return logging.Formatter.format(self, record)
Dies hat auch den Vorteil, dass vor und nach der Version 3.2 gearbeitet wird, indem keine internen Variablen wie self._fmt oder self._style verwendet werden.
quelle