web-dev-qa-db-fra.com

enregistrer les messages apparaissant deux fois avec Python Logging

J'utilise la journalisation Python et, pour une raison quelconque, tous mes messages apparaissent deux fois.

J'ai un module pour configurer la journalisation:

# BUG: It's outputting logging messages twice - not sure why - it's not the propagate setting.
def configure_logging(self, logging_file):
    self.logger = logging.getLogger("my_logger")
    self.logger.setLevel(logging.DEBUG)
    self.logger.propagate = 0
    # Format for our loglines
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    # Setup console logging
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    ch.setFormatter(formatter)
    self.logger.addHandler(ch)
    # Setup file logging as well
    fh = logging.FileHandler(LOG_FILENAME)
    fh.setLevel(logging.DEBUG)
    fh.setFormatter(formatter)
    self.logger.addHandler(fh)

Plus tard, j'appelle cette méthode pour configurer la journalisation:

if __== '__main__':
    tom = Boy()
    tom.configure_logging(LOG_FILENAME)
    tom.buy_ham()

Et puis à l'intérieur, le module buy_ham, j'appellerais:

self.logger.info('Successfully able to write to %s' % path)

Et pour une raison quelconque, tous les messages apparaissent deux fois. J'ai commenté l'un des gestionnaires de flux, toujours la même chose. Un peu bizarre, je ne sais pas pourquoi cela se passe ... lol. En supposant que j'ai raté quelque chose d'évident.

A bientôt, Victor

61
victorhooi

Vous appelez deux fois configure_logging (peut-être dans la méthode __init__ de Boy): getLogger renverra le même objet, mais addHandler ne vérifie pas si un gestionnaire similaire a déjà été ajouté à l'enregistreur. 

Essayez de suivre les appels de cette méthode et d’en éliminer une. Ou définissez un indicateur logging_initialized initialisé à False dans la méthode __init__ de Boy et remplacez configure_logging par ne rien faire si logging_initialized est True et définissez-le sur True après avoir initialisé le consignateur. 

Si votre programme crée plusieurs instances Boy, vous devrez changer la façon dont vous procédez avec une fonction globale configure_logging en ajoutant les gestionnaires, et la méthode Boy.configure_logging n'initialisant que l'attribut self.logger.

Une autre façon de résoudre ce problème consiste à vérifier l’attribut handlers de votre enregistreur:

logger = logging.getLogger('my_logger')
if not logger.handlers:
    # create the handlers and call logger.addHandler(logging_handler)
88
gurney alex

Le gestionnaire est ajouté chaque fois que vous appelez de l'extérieur. Essayez de supprimer le gestionnaire après avoir terminé votre travail:

self.logger.removeHandler(ch)
6
Mayukh Roy

Je suis un débutant en python, mais cela a semblé fonctionner pour moi (Python 2.7)

while logger.handlers:
     logger.handlers.pop()
5
Gregory Ponto

Si vous voyez ce problème et que vous n’ajoutez pas le gestionnaire deux fois, voyez la réponse d’abarnert ici

De la docs :

Remarque: Si vous associez un gestionnaire à un enregistreur et à un ou plusieurs de ses ancêtres, il peut émettre le même enregistrement plusieurs fois. En général, vous ne devrait pas avoir besoin d'attacher un gestionnaire à plus d'un enregistreur - si vous attachez-le simplement à l’enregistreur approprié qui se trouve le plus haut dans le Logger Logger, il verra tous les événements enregistrés par tous les descendants les enregistreurs, à condition que leur paramètre de propagation soit laissé défini sur True. UNE Le scénario courant consiste à attacher des gestionnaires uniquement à l'enregistreur racine et à laissez la propagation s'occuper du reste.

Donc, si vous voulez un gestionnaire personnalisé sur "test" et que vous ne voulez pas que ses messages soient également envoyés au gestionnaire racine, la réponse est simple: désactivez son indicateur de propagation:

logger.propagate = False

5

Un appel à logging.debug() appelle logging.basicConfig() si aucun gestionnaire racine n'est installé. Cela se passait pour moi dans un cadre de test où je ne pouvais pas contrôler l'ordre de renvoi des cas de test. Mon code d'initialisation installait le second. La valeur par défaut utilise logging.BASIC_FORMAT que je ne voulais pas.

0
JimB