it-swarm.com.de

Handler aus den Logging-Loggern von Python entfernen

Ich spiele mit Pythons Protokolliersystem. Ich habe ein merkwürdiges Verhalten beim Entfernen von Handlern aus einem Logger-Objekt in einer Schleife festgestellt. Meine for-Schleife entfernt nämlich alle bis auf einen Handler. Ein zusätzlicher Aufruf von .removeHandler entfernt den letzten Handler reibungslos. Während der Anrufe werden keine Fehlermeldungen ausgegeben.

Dies ist der Testcode:

import logging
import sys
logging.basicConfig()
dbg = logging.getLogger('dbg')
dbg.setLevel(logging.DEBUG)

testLogger = logging.getLogger('mylogger')
sh = logging.StreamHandler(sys.stdout)
fh = logging.FileHandler('mylogfile.log')
dbg.debug('before adding handlers: %d handlers'%len(testLogger.handlers))
testLogger.addHandler(fh)
testLogger.addHandler(sh)

dbg.debug('before removing. %d handlers: %s'%(len(testLogger.handlers), 
                                              str(testLogger.handlers)))
for h in testLogger.handlers:
    dbg.debug('removing handler %s'%str(h))
    testLogger.removeHandler(h)
    dbg.debug('%d more to go'%len(testLogger.handlers))

#HERE I EXPECT THAT NO HANDLER WILL REMAIN    
dbg.debug('after removing: %d handlers: %s'%(len(testLogger.handlers), 
                                              str(testLogger.handlers)))
if len(testLogger.handlers) > 0:
    #Why is this happening?
    testLogger.removeHandler(testLogger.handlers[0])
dbg.debug('after manually removing the last handler: %d handlers'%len(testLogger.handlers))    

Ich gehe davon aus, dass am Ende der Schleife keine Handler im Objekt testLogger verbleiben werden. Der letzte Aufruf von .removeHandler schlägt jedoch fehl, wie aus der folgenden Ausgabe ersichtlich ist. Trotzdem entfernt ein weiterer Aufruf dieser Funktion den Handler wie erwartet. Hier ist die Ausgabe:

DEBUG:dbg:before adding handlers: 0 handlers
DEBUG:dbg:before removing. 2 handlers: [<logging.FileHandler instance at 0x021263F0>, <logging.StreamHandler instance at 0x021262B0>]
DEBUG:dbg:removing handler <logging.FileHandler instance at 0x021263F0>
DEBUG:dbg:1 more to go
DEBUG:dbg:after removing: 1 handlers: [<logging.StreamHandler instance at 0x021262B0>]
DEBUG:dbg:after manually removing the last handler: 0 handlers

Interessanter ist, dass, wenn ich die ursprüngliche Schleife durch die folgende Schleife ersetze, die Schleife wie erwartet funktioniert und keine Handler am Ende der Schleife im testLogger-Objekt verbleiben. Hier ist die modifizierte Schleife:

while len(testLogger.handlers) > 0:
    h = testLogger.handlers[0]
    dbg.debug('removing handler %s'%str(h))
    testLogger.removeHandler(h)
    dbg.debug('%d more to go'%len(testLogger.handlers))

Was erklärt dieses Verhalten? Ist das ein Fehler oder fehlt mir etwas?

42
Boris Gorelik

Dies ist kein protokollspezifisches Verhalten. Niemals mutiere (Einfügen/Entfernen von Elementen) der Liste, die Sie gerade durchlaufen. Wenn Sie brauchen, machen Sie eine Kopie. In diesem Fall sollte testLogger.handlers = [] den Trick ausführen.

85
Cat Plus Plus

Wenn Sie nicht alle löschen möchten (danke für den Tipp@CatPlusPlus ):

testLogger.handlers = [
    h for h in testLogger.handlers if not isinstance(h, logging.StreamHandler)]
8
hobs

Ich habe gerade herausgefunden, dass Sie dies auch in einer Protokollierungs-INI-Datei mit dem folgenden Block tun können:

[logger_stpipe]
handlers=
propagate=1
qualname=stpipe

Grundsätzlich werden alle Handler für einen bestimmten Logger deaktiviert. Es ist jedoch etwas eingeschränkt, da Sie den Namen des Loggers vorher kennen müssen.

0
Autiwa