Ich hätte gerne loglevel TRACE (5) für meine Anwendung, da ich das nicht für debug()
ausreichend halte . Außerdem log(5, msg)
ist es nicht das, was ich will. Wie kann ich einem Python-Logger ein benutzerdefiniertes Googlevel hinzufügen?
Ich habe eine mylogger.py
mit folgendem Inhalt:
import logging
@property
def log(obj):
myLogger = logging.getLogger(obj.__class__.__name__)
return myLogger
In meinem Code verwende ich es folgendermaßen:
class ExampleClass(object):
from mylogger import log
def __init__(self):
'''The constructor with the logger'''
self.log.debug("Init runs")
Jetzt möchte ich anrufen self.log.trace("foo bar")
Vielen Dank im Voraus für Ihre Hilfe.
Bearbeiten (8. Dezember 2016): Ich habe die akzeptierte Antwort in pfa's geändert , was meiner Meinung nach eine ausgezeichnete Lösung ist, die auf dem sehr guten Vorschlag von Eric S. basiert.
quelle
logging.DEBUG_LEVEL_NUM = 9
damit Sie überall dort auf diese Debug-Ebene zugreifen können, wo Sie den Logger in Ihren Code importieren?DEBUG_LEVEL_NUM = 9
sollten Sie stattdessen definierenlogging.DEBUG_LEVEL_NUM = 9
. Auf diese Weise können Sielog_instance.setLevel(logging.DEBUG_LEVEL_NUM)
die gleiche Art und Weise verwenden, wie Sie Right Knowlogging.DEBUG
oderlogging.INFO
logging.DEBUGV = DEBUG_LEVELV_NUM
undlogging.__all__ += ['DEBUGV']
Die zweite ist nicht besonders wichtig, aber die erste ist erforderlich, wenn Sie Code haben, der die Protokollierungsstufe dynamisch anpasst, und Sie möchten in der Lage sein, so etwas wieif verbose: logger.setLevel(logging.DEBUGV)
`Ich nahm die Antwort "Lambda vermeiden" und musste ändern, wo die log_at_my_log_level hinzugefügt wurde. Ich habe auch das Problem gesehen, das Paul gemacht hat. "Ich glaube nicht, dass das funktioniert. Benötigen Sie keinen Logger als erstes Argument in log_at_my_log_level?" Das hat bei mir funktioniert
quelle
__init__.py
und seien Sie glücklich: DTypeError: not all arguments converted during string formatting
aber es funktioniert gut mit *. (Python 3.4.3). Ist es ein Problem mit der Python-Version oder etwas, das mir fehlt?AttributeError: module 'logging' has no attribute 'debugv'
Ich kombiniere alle vorhandenen Antworten mit einer Reihe von Nutzungserfahrungen und denke, ich habe eine Liste aller Dinge erstellt, die getan werden müssen, um eine vollständig nahtlose Nutzung der neuen Ebene sicherzustellen. Bei den folgenden Schritten wird davon ausgegangen, dass Sie eine neue Ebene
TRACE
mit Wert hinzufügenlogging.DEBUG - 5 == 5
:logging.addLevelName(logging.DEBUG - 5, 'TRACE')
muss aufgerufen werden, um die neue Ebene intern zu registrieren, damit sie namentlich referenziert werden kann.logging
Gründen der Konsistenz als Attribut hinzugefügt werden :logging.TRACE = logging.DEBUG - 5
.trace
muss eine aufgerufene Methode hinzugefügtlogging
werden. Es sollte verhalten sich wiedebug
,info
usw.trace
muss der aktuell konfigurierten Logger-Klasse hinzugefügt werden. Da dies nicht zu 100% garantiert istlogging.Logger
, verwenden Sielogging.getLoggerClass()
stattdessen.Alle Schritte sind in der folgenden Methode dargestellt:
quelle
Oldest
und Sie werden es zu schätzen wissen, dass dies die beste Antwort von allen ist!args
derlogForLevel
Implementierung beabsichtigt / erforderlich?Diese Frage ist ziemlich alt, aber ich habe mich gerade mit dem gleichen Thema befasst und einen Weg gefunden, der den bereits erwähnten ähnlich ist und der mir etwas sauberer erscheint. Dies wurde auf 3.4 getestet, daher bin ich mir nicht sicher, ob die verwendeten Methoden in älteren Versionen vorhanden sind:
quelle
get
undsetLoggerClass
genau tun und warum werden sie benötigt?TRACE
der Standardprotokollierungsbibliothek eine Ebene hinzugefügt werden soll . +1Wer hat mit der schlechten Praxis begonnen, interne Methoden anzuwenden (
self._log
) und warum basiert jede Antwort darauf?! Die pythonische Lösung wäre,self.log
stattdessen zu verwenden, damit Sie sich nicht mit internen Dingen herumschlagen müssen:quelle
Ich finde es einfacher, ein neues Attribut für das Logger-Objekt zu erstellen, das die Funktion log () übergibt. Ich denke, das Logger-Modul liefert aus genau diesem Grund den addLevelName () und den log (). Somit sind keine Unterklassen oder neue Methoden erforderlich.
jetzt
sollte wie erwartet funktionieren.
quelle
_log
, nichtlog
.Obwohl wir bereits viele richtige Antworten haben, ist das Folgende meiner Meinung nach pythonischer:
Wenn Sie
mypy
Ihren Code verwenden möchten , wird empfohlen, ihn hinzuzufügen# type: ignore
, um Warnungen beim Hinzufügen von Attributen zu unterdrücken.quelle
logging.trace = partial(logging.log, logging.TRACE) # type: ignore
?Ich denke, Sie müssen die
Logger
Klasse unterordnen und eine Methode hinzufügen, die aufgerufen wirdtrace
und im GrundeLogger.log
mit einer niedrigeren Stufe als aufruftDEBUG
. Ich habe dies nicht versucht, aber dies ist, was die Dokumente anzeigen .quelle
logging.getLogger
, um Ihre Unterklasse anstelle der integrierten Klasse zurückzugeben.setLoggerClass(MyClass)
und danngetLogger()
wie gewohnt anrufen ...Tipps zum Erstellen eines benutzerdefinierten Loggers:
_log
, verwendenlog
(Sie müssen nicht überprüfenisEnabledFor
)getLogger
müssen Sie die Klasse über festlegensetLoggerClass
__init__
für den Logger keine Klasse definieren , wenn Sie nichts speichernWenn Sie diesen Logger aufrufen, verwenden Sie ihn
setLoggerClass(MyLogger)
, um ihn zum Standardlogger zu machengetLogger
Sie werden müssen
setFormatter
,setHandler
undsetLevel(TRACE)
auf diehandler
und auf dielog
sich tatsächlich auf diese se geringe Spurquelle
Das hat bei mir funktioniert:
Das Lambda / FuncName-Problem wurde mit logger._log behoben, wie @marqueed hervorhob. Ich denke, die Verwendung von Lambda sieht ein bisschen sauberer aus, aber der Nachteil ist, dass es keine Schlüsselwortargumente annehmen kann. Ich habe das selbst nie benutzt, also kein Problem.
quelle
Nach meiner Erfahrung ist dies die vollständige Lösung des Problems der Operation. Um zu vermeiden, dass "Lambda" als die Funktion angesehen wird, in der die Nachricht gesendet wird, gehen Sie tiefer:
Ich habe noch nie versucht, mit einer eigenständigen Logger-Klasse zu arbeiten, aber ich denke, die Grundidee ist dieselbe (benutze _log).
quelle
logger
als erstes Argumentlog_at_my_log_level
?Ergänzung zum Beispiel von Mad Physicists, um den Dateinamen und die Zeilennummer korrekt zu erhalten:
quelle
Basierend auf der angehefteten Antwort habe ich eine kleine Methode geschrieben, mit der automatisch neue Protokollierungsstufen erstellt werden
Konfiguration kann so aussehen:
quelle
Als Alternative zum Hinzufügen einer zusätzlichen Methode zur Logger-Klasse würde ich die Verwendung der
Logger.log(level, msg)
Methode empfehlen .quelle
Ich bin verwirrt; Zumindest mit Python 3.5 funktioniert es einfach:
Ausgabe:
quelle
logger.trace('hi')
was meiner Meinung nach das Hauptziel istFür den Fall, dass jemand dem Protokollierungsmodul (oder einer Kopie davon) automatisch eine neue Protokollierungsstufe hinzufügen möchte, habe ich diese Funktion erstellt und die Antwort von @ pfa erweitert:
quelle
setattr
stattdessen austauschen ...