Je joue avec le système de journalisation de Python. J'ai remarqué un comportement étrange lors de la suppression des gestionnaires d'un objet Logger dans une boucle. À savoir, ma boucle for supprime tous les gestionnaires sauf un. Un appel supplémentaire à .removeHandler
supprime le dernier gestionnaire en douceur. Aucun message d'erreur n'est émis pendant les appels.
C'est le code de test:
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))
J'espère qu'à la fin de la boucle, aucun gestionnaire ne restera dans l'objet testLogger
, cependant Le dernier appel à .removeHandler
échoue apparemment, comme le montre la sortie ci-dessous. Néanmoins, l'appel supplémentaire à cette fonction supprime le gestionnaire comme prévu. Voici la sortie:
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
Plus intéressant encore, si je remplace la boucle d'origine par la suivante, la bouclefonctionne comme prévu et aucun gestionnaire ne reste dans l'objet testLogger
à la fin de la boucle. Voici la boucle modifiée:
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))
Qu'est-ce qui explique ce comportement? Est-ce un bug ou est-ce que je manque quelque chose?
Ce n'est pas un comportement spécifique à l'enregistreur. Never mutate (insert/remove elements) la liste sur laquelle vous êtes en train de parcourir. Si vous en avez besoin, faites-en une copie. Dans ce cas, testLogger.handlers = []
devrait faire l'affaire.
Si vous ne voulez pas tous les supprimer (merci pour le conseil@CatPlusPlus ):
testLogger.handlers = [
h for h in testLogger.handlers if not isinstance(h, logging.StreamHandler)]
Je viens de découvrir que vous pouvez également le faire dans un fichier .ini de journalisation, avec le bloc suivant:
[logger_stpipe]
handlers=
propagate=1
qualname=stpipe
Il désactive fondamentalement tous les gestionnaires pour un enregistreur donné. Mais c'est un peu limité car vous devez connaître le nom du Logger à l'avance.