web-dev-qa-db-fra.com

Suppression des gestionnaires des enregistreurs de journalisation de python

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?

42
Boris Gorelik

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.

85
Cat Plus Plus

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)]
8
hobs

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.

0
Autiwa