Ich verwende die Protokollierungsfunktion für Python 2.7.3. Die Dokumentation für diese Python-Version lautet :
Das Protokollierungspaket datiert neuere Formatierungsoptionen wie str.format () und string.Template vor. Diese neueren Formatierungsoptionen werden unterstützt ...
Ich mag 'neues' Format mit geschweiften Klammern. Also versuche ich etwas zu tun wie:
log = logging.getLogger("some.logger")
log.debug("format this message {0}", 1)
Und Fehler bekommen:
TypeError: Nicht alle Argumente wurden während der Formatierung der Zeichenfolge konvertiert
Was ich hier vermisse?
PS Ich möchte nicht verwenden
log.debug("format this message {0}".format(1))
In diesem Fall wird die Nachricht unabhängig von der Logger-Ebene immer formatiert.
python
python-2.7
string-formatting
MajesticRa
quelle
quelle
log.debug("format this message%d" % 1)
Formatter
, um '{' als Stil zu verwendenAntworten:
BEARBEITEN: Sehen Sie sich den
StyleAdapter
Ansatz in der Antwort von @Dunes im Gegensatz zu dieser Antwort an. Es ermöglicht die Verwendung alternativer Formatierungsstile ohne Boilerplate, während die Methoden des Loggers (debug (), info (), error () usw.) aufgerufen werden.Aus den Dokumenten - Verwendung alternativer Formatierungsstile :
Und:
Kopieren Sie dies in das
wherever
Modul:class BraceMessage(object): def __init__(self, fmt, *args, **kwargs): self.fmt = fmt self.args = args self.kwargs = kwargs def __str__(self): return self.fmt.format(*self.args, **self.kwargs)
Dann:
from wherever import BraceMessage as __ log.debug(__('Message with {0} {name}', 2, name='placeholders'))
Hinweis: Die eigentliche Formatierung wird verzögert, bis dies erforderlich ist. Wenn beispielsweise DEBUG-Nachrichten nicht protokolliert werden, wird die Formatierung überhaupt nicht durchgeführt.
quelle
num = 2; name = 'placeholders'; log.debug(f'Message with {num} {name}')
Hier ist eine weitere Option, bei der die in der Antwort von Dunes genannten Keyword-Probleme nicht auftreten. Es können nur positional (
{0}
) - Argumente und keine keyword ({foo}
) - Argumente verarbeitet werden. Es sind auch keine zwei Aufrufe zum Formatieren erforderlich (unter Verwendung des Unterstrichs). Es hat den ick-Faktor der Unterklassestr
:class BraceString(str): def __mod__(self, other): return self.format(*other) def __str__(self): return self class StyleAdapter(logging.LoggerAdapter): def __init__(self, logger, extra=None): super(StyleAdapter, self).__init__(logger, extra) def process(self, msg, kwargs): if kwargs.pop('style', "%") == "{": # optional msg = BraceString(msg) return msg, kwargs
Sie verwenden es so:
logger = StyleAdapter(logging.getLogger(__name__)) logger.info("knights:{0}", "ni", style="{") logger.info("knights:{}", "shrubbery", style="{")
Natürlich können Sie das mit gekennzeichnete Häkchen entfernen
# optional
, um alle Nachrichten über den Adapter zur Verwendung einer neuen Formatierung zu zwingen.Hinweis für alle, die diese Antwort Jahre später lesen : Ab Python 3.2 können Sie den Stilparameter für
Formatter
Objekte verwenden:Die Dokumente enthalten das Beispiel
logging.Formatter('{asctime} {name} {levelname:8s} {message}', style='{')
Beachten Sie, dass Sie in diesem Fall das
logger
mit dem neuen Format immer noch nicht aufrufen können . Das heißt, Folgendes wird immer noch nicht funktionieren:logger.info("knights:{say}", say="ni") # Doesn't work! logger.info("knights:{0}", "ni") # Doesn't work either
quelle
Formatter
, was jetzt richtig ist (glaube ich). DasStyleAdapter
funktioniert noch,BraceString
eine String - Unterklasse ist, dann ist es sicher selbst zurückzukehren , aus__str__
Dies war meine Lösung für das Problem, als ich feststellte, dass bei der Protokollierung nur die Formatierung im printf-Stil verwendet wird. Dadurch können Protokollierungsaufrufe gleich bleiben - keine spezielle Syntax wie z
log.info(__("val is {}", "x"))
. Die für den Code erforderliche Änderung besteht darin, den Logger in a zu verpackenStyleAdapter
.from inspect import getargspec class BraceMessage(object): def __init__(self, fmt, args, kwargs): self.fmt = fmt self.args = args self.kwargs = kwargs def __str__(self): return str(self.fmt).format(*self.args, **self.kwargs) class StyleAdapter(logging.LoggerAdapter): def __init__(self, logger): self.logger = logger def log(self, level, msg, *args, **kwargs): if self.isEnabledFor(level): msg, log_kwargs = self.process(msg, kwargs) self.logger._log(level, BraceMessage(msg, args, kwargs), (), **log_kwargs) def process(self, msg, kwargs): return msg, {key: kwargs[key] for key in getargspec(self.logger._log).args[1:] if key in kwargs}
Verwendung ist:
log = StyleAdapter(logging.getLogger(__name__)) log.info("a log message using {type} substitution", type="brace")
Es ist erwähnenswert, dass diese Umsetzungsprobleme haben , wenn Schlüsselwörter für Klammer Substitution verwendet wurden , umfassen
level
,msg
,args
,exc_info
,extra
oderstack_info
. Dies sind Argumentnamen, die von derlog
Methode von verwendet werdenLogger
. Wenn Sie einen dieser Namen benötigen, ändern Sie dieseprocess
, um diese Namen auszuschließen, oder entfernen Sie sie einfachlog_kwargs
aus dem_log
Anruf. Darüber hinaus ignoriert diese Implementierung auch stillschweigend falsch geschriebene Schlüsselwörter, die für den Logger bestimmt sind (z. B.ectra
).quelle
Die einfachere Lösung wäre die Verwendung des hervorragenden
logbook
Modulsimport logbook import sys logbook.StreamHandler(sys.stdout).push_application() logbook.debug('Format this message {k}', k=1)
Oder umso vollständiger:
>>> import logbook >>> import sys >>> logbook.StreamHandler(sys.stdout).push_application() >>> log = logbook.Logger('MyLog') >>> log.debug('Format this message {k}', k=1) [2017-05-06 21:46:52.578329] DEBUG: MyLog: Format this message 1
quelle
Wie in anderen Antworten erwähnt, wird die in Python 3.2 eingeführte Formatierung im geschweiften Stil nur für die Formatzeichenfolge verwendet, nicht für die eigentlichen Protokollnachrichten.
Um die Formatierung der eigentlichen Protokollnachricht im Klammerstil zu aktivieren, können wir einen Teil des Protokollierungscodes mit Affen-Patches versehen.
Im Folgenden wird das
logging
Modul gepatcht, um eineget_logger
Funktion zu erstellen , die einen Protokollierer zurückgibt, der die neue Formatierung für jeden von ihm verarbeiteten Protokolldatensatz verwendet.import functools import logging import types def _get_message(record): """Replacement for logging.LogRecord.getMessage that uses the new-style string formatting for its messages""" msg = str(record.msg) args = record.args if args: if not isinstance(args, tuple): args = (args,) msg = msg.format(*args) return msg def _handle_wrap(fcn): """Wrap the handle function to replace the passed in record's getMessage function before calling handle""" @functools.wraps(fcn) def handle(record): record.getMessage = types.MethodType(_get_message, record) return fcn(record) return handle def get_logger(name=None): """Get a logger instance that uses new-style string formatting""" log = logging.getLogger(name) if not hasattr(log, "_newstyle"): log.handle = _handle_wrap(log.handle) log._newstyle = True return log
Verwendung:
>>> log = get_logger() >>> log.warning("{!r}", log) <logging.RootLogger object at 0x4985a4d3987b>
Anmerkungen:
logging.getLogger
mitget_logger
)get_logger
Funktion erstellte Logger (bricht keine Pakete von Drittanbietern).logging.getLogger()
Aufruf erneut auf den Logger zugegriffen wird , gilt die Formatierung im neuen Stil weiterhin.exc_info
,stack_info
,stacklevel
undextra
).logging.LogRecord
wie gewohnt auf Objekten gespeichert (in einigen Fällen nützlich mit benutzerdefinierten Protokollhandlern).logging
Quellcode des Moduls ansieht , scheint es, als sollte er bis zurstr.format
Einführung von Python 2.6 funktionieren (aber ich habe ihn nur in Version 3.5 und höher getestet).quelle
Versuchen Sie es
logging.setLogRecordFactory
in Python 3.2+:import collections import logging class _LogRecord(logging.LogRecord): def getMessage(self): msg = str(self.msg) if self.args: if isinstance(self.args, collections.Mapping): msg = msg.format(**self.args) else: msg = msg.format(*self.args) return msg logging.setLogRecordFactory(_LogRecord)
quelle
%
Formatierung verwenden, da die Datensatzfactory für das Protokollierungsmodul global ist.Ich habe einen benutzerdefinierten Formatierer namens ColorFormatter erstellt , der das Problem folgendermaßen behandelt:
class ColorFormatter(logging.Formatter): def format(self, record): # previous stuff, copy from logging.py… try: # Allow {} style message = record.getMessage() # printf except TypeError: message = record.msg.format(*record.args) # later stuff…
Dadurch bleibt es mit verschiedenen Bibliotheken kompatibel. Der Nachteil ist, dass es wahrscheinlich nicht performant ist, da möglicherweise zweimal versucht wird, die Zeichenfolge zu formatieren.
quelle
Hier ist etwas ganz Einfaches, das funktioniert:
debug_logger: logging.Logger = logging.getLogger("app.debug") def mydebuglog(msg: str, *args, **kwargs): if debug_logger.isEnabledFor(logging.DEBUG): debug_logger.debug(msg.format(*args, **kwargs))
Dann:
mydebuglog("hello {} {val}", "Python", val="World")
quelle
Ähnliche Lösung pR0Ps', Verpackung
getMessage
inLogRecord
durch VerpackungmakeRecord
(statthandle
in ihrer Antwort) in Fällen ,Logger
dass sollte neue Formatierungs-fähig sein:def getLogger(name): log = logging.getLogger(name) def Logger_makeRecordWrapper(name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None): self = log record = logging.Logger.makeRecord(self, name, level, fn, lno, msg, args, exc_info, func, sinfo) def LogRecord_getMessageNewStyleFormatting(): self = record msg = str(self.msg) if self.args: msg = msg.format(*self.args) return msg record.getMessage = LogRecord_getMessageNewStyleFormatting return record log.makeRecord = Logger_makeRecordWrapper return log
Ich habe dies mit Python 3.5.3 getestet.
quelle