Python-Protokollierung - Deaktivieren Sie die Protokollierung von importierten Modulen

94

Ich verwende das Python-Protokollierungsmodul und möchte Protokollnachrichten deaktivieren, die von den von mir importierten Drittanbieter-Modulen gedruckt werden. Zum Beispiel verwende ich so etwas wie das Folgende:

logger = logging.getLogger()
logger.setLevel(level=logging.DEBUG)
fh = logging.StreamHandler()
fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
fh.setFormatter(fh_formatter)
logger.addHandler(fh)

Dadurch werden meine Debug-Meldungen ausgedruckt, wenn ich einen logger.debug ("meine Nachricht!") Ausführe, aber es werden auch die Debug-Meldungen von jedem Modul ausgedruckt, das ich importiere (z. B. Anforderungen und eine Reihe anderer Dinge).

Ich möchte nur die Protokollnachrichten von Modulen sehen, an denen ich interessiert bin. Ist es möglich, dass das Protokollierungsmodul dies tut?

Im Idealfall möchte ich den Logger anweisen können, Nachrichten von "ModuleX, ModuleY" zu drucken und alle anderen zu ignorieren.

Ich habe mir Folgendes angesehen, möchte aber nicht vor jedem Aufruf einer importierten Funktion die Protokollierung deaktivieren / aktivieren müssen: Protokollierung - Wie werden importierte Modulprotokolle ignoriert?

blindsnowmobile
quelle

Antworten:

66

Das Problem ist, dass beim Aufrufen getLoggerohne Argumente der Root- Logger zurückgegeben wird. Wenn Sie also die Ebene festlegen, legen logging.DEBUGSie auch die Ebene für andere Module fest, die diesen Logger verwenden.

Sie können dies lösen, indem Sie den Root-Logger einfach nicht verwenden. Übergeben Sie dazu einfach einen Namen als Argument, zum Beispiel den Namen Ihres Moduls:

logger = logging.getLogger('my_module_name')
# as before

Dadurch wird ein neuer Logger erstellt, und die Protokollierungsstufe für andere Module wird nicht versehentlich geändert.


Natürlich müssen Sie logger.debugstattdessen verwenden, logging.debugda letztere eine praktische Funktion ist, die die debugMethode des Root-Loggers aufruft .

Dies wird im Advanced Logging Tutorial erwähnt . Außerdem können Sie auf einfache Weise feststellen, welches Modul die Protokollnachricht ausgelöst hat.

Bakuriu
quelle
33
Ich erstelle einen Logger mit __name__r, sehe aber immer noch die Protokolle der importierten Module. Ich versuche, die Protokollierung mit einer INI-Konfigurationsdatei zu konfigurieren. Was soll ich dafür tun?
Durga Swaroop
5
Das Erstellen eines Loggers mit __name__hat bei mir auch nicht funktioniert. Vielleicht, weil ich ein eigenständiges Skript und kein "Modul" verwende? Für mich hat es funktioniert, die Protokollierung für importierte Module ( matpplotlibin meinem Fall) über logging.getLogger("matplotlib").setLevel(logging.WARNING)und für mein Skript über zu konfigurieren logging.basicConfig.
bli
45

Wenn Sie das Python- loggingPaket verwenden, ist es üblich, in jedem Modul, das es verwendet, einen Logger zu definieren.

logger = logging.getLogger(__name__)

Viele beliebte Python-Pakete tun dies, einschließlich requests. Wenn ein Paket diese Konvention verwendet, ist es einfach, die Protokollierung für dieses Paket zu aktivieren / deaktivieren, da der Name des Protokollierers mit dem Namen des Pakets identisch ist (oder ein untergeordnetes Element dieses Protokollierers ist). Sie können es sogar in derselben Datei wie Ihre anderen Logger protokollieren.

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

requests_logger = logging.getLogger('requests')
requests_logger.setLevel(logging.DEBUG)

handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
logger.addHandler(handler)
requests_logger.addHandler(handler)
Brendan Abel
quelle
15
Beachten Sie, dass beim Versuch, Ihre Logger wie im offiziellen Basis-Tutorial mit logging.basicConfig(...)allen Loggern zu konfigurieren, entweder entweder logging.lastResort(beginnend mit Python 3.2, das ist stderr) ausgegeben wird, wenn kein Handler angegeben wurde, oder an den von Ihnen festgelegten Handler. Verwenden Sie es also nicht, sonst erhalten Sie trotzdem weiterhin alle Protokollnachrichten.
user136036
42

Ich bin mir nicht sicher, ob dies zum Posten geeignet ist, aber ich war lange festgefahren und wollte jemandem mit dem gleichen Problem helfen, da ich es nirgendwo anders gefunden hatte!

Ich habe Debug-Protokolle von matplotlib erhalten, obwohl ich der recht einfachen Dokumentation im erweiterten Tutorial zur Protokollierung und der Fehlerbehebung gefolgt bin . Ich habe meinen Logger main()für eine Datei initiiert und eine Funktion importiert, um ein Diagramm aus einer anderen Datei zu erstellen (in die ich matplotlib importiert hatte).

Was für mich funktioniert hat, war, die Ebene von matplotlib vor dem Importieren festzulegen , anstatt danach, wie ich es für andere Module in meiner Hauptdatei getan habe. Dies schien mir nicht intuitiv zu sein. Wenn also jemand einen Einblick hat, wie Sie die Konfiguration für einen Logger festlegen können, der noch nicht importiert wurde, wäre ich gespannt, wie dies funktioniert. Vielen Dank!

In meiner Hauptdatei:

import logging
import requests
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logging.getLogger('requests').setLevel(logging.DEBUG)

def main():
  ...

In meiner plot.pyDatei:

import logging
logging.getLogger('matplotlib').setLevel(logging.WARNING)
import matplotlib.pyplot as plt

def generatePlot():
  ...
Finn
quelle
Ich habe die Fehlermeldung "Logger" -Objekt hat kein Attribut "DEBUG". logger.DEBUGsollte seinlogging.DEBUG
Foxiris
Vielen Dank! Es hilft wirklich! Ich habe die Matplotlib-Protokollierungsstufe nach meiner Hauptprotokollierungskonfiguration und vor dem Befehl festgelegt, der die Matplotlib importiert. Gelöst!
gph
9

@ Bakuriu erklärt ganz elegant die Funktion. Umgekehrt können Sie die getLogger()Methode verwenden, um unerwünschte Logger abzurufen und neu zu konfigurieren / zu deaktivieren.

Ich wollte auch hinzufügen, dass die logging.fileConfig()Methode einen aufgerufenen Parameter akzeptiert disable_existing_loggers, der alle zuvor definierten Logger deaktiviert (dh in importierten Modulen).

Apex-Meme-Lord
quelle
8

Dadurch werden alle vorhandenen Protokollierer deaktiviert, z. B. diejenigen, die von importierten Modulen erstellt wurden, während der Root-Protokollierer weiterhin verwendet wird (und ohne dass eine externe Datei geladen werden muss).

logging.config.dictConfig({
    'version': 1,
    'disable_existing_loggers': True,
})

Beachten Sie, dass Sie alle Module importieren müssen, die nicht zuerst protokolliert werden sollen! Andernfalls werden diese nicht als "vorhandene Logger" betrachtet. Anschließend werden alle Logger dieser Module deaktiviert. Dies kann dazu führen, dass Sie auch wichtige Fehler verpassen!

Ausführlichere Beispiele für verwandte Konfigurationsoptionen finden Sie unter https://gist.github.com/st4lk/6287746 . Hier ist ein (teilweise funktionierendes) Beispiel für die Konfiguration von YAML mit der coloredlogBibliothek.

avv
quelle
Was ist deine Frage?
user1767754
1
Dies funktioniert zum requestBeispiel, aber es funktioniert nicht, wenn die importierten Module ihre Logger in ihrer Klasse erstellen, die Sie später aufrufen würden, wie APSchedulerdies beim Aufrufen der Fall ist BackgroundScheduler.BackgroundScheduler(). Eine Lösung finden Sie hier: stackoverflow.com/a/48891485/2441026
user136036
Dies funktioniert für meinen Fall mit der Yaml-Konfigurationsdatei
user4015990
4

Sie könnten etwas verwenden wie:

logging.getLogger("imported_module").setLevel(logging.WARNING)
logging.getLogger("my_own_logger_name").setLevel(logging.DEBUG)

Dadurch wird die Protokollstufe meines eigenen Moduls auf DEBUG gesetzt, während verhindert wird, dass das importierte Modul dieselbe Stufe verwendet.

Hinweis: "imported_module"Kann durch imported_module.__name__(ohne Anführungszeichen) ersetzt werden und "my_own_logger_name"kann durch ersetzt werden, __name__wenn Sie dies bevorzugen.

Kamiku
quelle
1

Ich hatte das gleiche Problem. Ich habe eine logging_config.py-Datei, die ich in alle anderen py-Dateien importiere. In der Datei logging_config.py habe ich die Protokollierungsstufe des Root-Loggers auf ERROR gesetzt (standardmäßig die Warnung):

logging.basicConfig(
    handlers=[
        RotatingFileHandler('logs.log',maxBytes=1000, backupCount=2),
        logging.StreamHandler(), #print to console
    ],
    level=logging.ERROR
)

In anderen Modulen importiere ich logging_config.py und deklariere einen neuen Logger und setze dessen Level auf Debug:

log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)

Auf diese Weise wird alles protokolliert, was ich in meinen py-Dateien anmelde, aber auf Debug- und Info-Ebene von importierten Modulen wie urllib, request, boto3 usw. protokollierte Inhalte werden nicht protokolliert. Wenn in diesem Importmodul ein Fehler auftritt, wird es protokolliert, da ich die Root-Logger-Ebene auf ERROR gesetzt habe.

Aseem
quelle
0

Eine weitere zu berücksichtigende Sache ist die Propagate- Eigenschaft der Logger-Klasse.

Zum Beispiel eine py-suds-Bibliothek zur Bearbeitung von Seifenanrufen, die sogar auf ERROR gestellt wird

logging.getLogger('suds.client').setLevel(logging.ERROR)
logging.getLogger('suds.transport').setLevel(logging.ERROR)
logging.getLogger('suds.xsdschema').setLevel(logging.ERROR)
logging.getLogger('suds.wsdl').setLevel(logging.ERROR)

protokolliert Protokolle über ein Modul namens sxbasics.py, das eine große Anzahl von Protokollen erstellt

Geben Sie hier die Bildbeschreibung ein

Da die Weitergabe der Protokolle standardmäßig True ist und stattdessen auf False gesetzt wurde, habe ich 514 MB Protokolle wiederhergestellt.

import logging
logging.getLogger("suds").propagate = False
logging.getLogger('suds.client').setLevel(logging.ERROR)
logging.getLogger('suds.transport').setLevel(logging.ERROR)
logging.getLogger('suds.xsdschema').setLevel(logging.ERROR)
logging.getLogger('suds.wsdl').setLevel(logging.ERROR)
Andrea Bisello
quelle