El módulo de registro de Python está imprimiendo líneas varias veces

Tengo el siguiente código:

import logging class A(object): def __init__(self): self._l = self._get_logger() def _get_logger(self): loglevel = logging.INFO l = logging.getLogger(__name__) l.setLevel(logging.INFO) h = logging.StreamHandler() f = logging.Formatter('%(asctime)s %(levelname)s %(message)s') h.setFormatter(f) l.addHandler(h) l.setLevel(loglevel) return l def p(self, msg): self._l.info(msg) for msg in ["hey", "there"]: a = A() ap(msg) 

La salida que obtengo es:

 2013-07-19 17:42:02,657 INFO hey 2013-07-19 17:42:02,657 INFO there 2013-07-19 17:42:02,657 INFO there 

¿Por qué se imprime “allí” dos veces? De manera similar, si agrego otro objeto de clase A dentro del bucle e imprimo un mensaje, se imprime tres veces.

La documentación dice que logging.getLogger () siempre devolverá la misma instancia del registrador si el nombre del registrador coincide. En este caso, el nombre coincide. ¿No debería devolver la misma instancia de logger? Si está hecho de hecho, ¿por qué se imprime el mensaje varias veces?

El registrador se crea una vez, pero se crean múltiples controladores.

Crea A vez.

 a = A() for msg in ["hey", "there"]: ap(msg) 

O cambie _get_logger como sigue:

 def _get_logger(self): loglevel = logging.INFO l = logging.getLogger(__name__) if not getattr(l, 'handler_set', None): l.setLevel(loglevel) h = logging.StreamHandler() f = logging.Formatter('%(asctime)s %(levelname)s %(message)s') h.setFormatter(f) l.addHandler(h) l.setLevel(loglevel) l.handler_set = True return l 

ACTUALIZAR

Desde Python 3.2, puede usar logging.Logger.hasHandlers para ver si este registrador tiene algún controlador configurado. (gracias @toom)

 def _get_logger(self): loglevel = logging.INFO l = logging.getLogger(__name__) if not l.hasHandlers(): ... return l 

En mi caso, también se llamaba al controlador de los registradores raíz. Todo lo que hice fue establecer el atributo de propagate de la instancia del registrador en False .

 import logging logger = logging.getLogger("MyLogger") # stop propagting to root logger logger.propagate = False # other log configuration stuff # .... 

Desde python 3.2 y más reciente:

Considere usar hasHandlers() para verificar si un registrador tiene manejadores o no.

https://docs.python.org/3/library/logging.html#logging.Logger.hasHandlers