Estoy usando el registro de Python y, por alguna razón, todos mis mensajes aparecen dos veces.
Tengo un módulo para configurar el registro:
# 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)
Más adelante, llamo a este método para configurar el registro:
if __name__ == '__main__':
tom = Boy()
tom.configure_logging(LOG_FILENAME)
tom.buy_ham()
Y luego, dentro de, digamos, el módulo buy_ham, llamaría:
self.logger.info('Successfully able to write to %s' % path)
Y por alguna razón, todos los mensajes aparecen dos veces. Comenté uno de los controladores de transmisión, sigue siendo lo mismo. Un poco extraño, no estoy seguro de por qué sucede esto ... jajaja. Suponiendo que me haya perdido algo obvio.
Saludos, Victor

configure_logging()que no se llama dos veces (por ejemplo, desde el constructor también)? ¿Se crea solo una instancia de Boy ()?self.logger.handlers = [ch]lugar resolvería este problema, aunque sería mejor asegurarse de no ejecutar este código dos veces, por ejemplo, usandoif not self.loggeral principio.Respuestas:
Está llamando
configure_loggingdos veces (tal vez en el__init__método deBoy):getLoggerdevolverá el mismo objeto, peroaddHandlerno verifica si ya se ha agregado un controlador similar al registrador.Intente rastrear llamadas a ese método y eliminar uno de estos. O configure una bandera
logging_initializedinicializada aFalseen el__init__método deBoyy cambieconfigure_loggingpara no hacer nada si lologging_initializedestáTrue, y para configurarlaTruedespués de haber inicializado el registrador.Si el programa crea varios
Boycasos, usted tiene que cambiar la forma de hacer las cosas con un global deconfigure_loggingla función de la adición de los controladores y elBoy.configure_loggingmétodo sólo inicializar elself.loggeratributo.Otra forma de resolver esto es verificando el atributo de manejadores de su registrador:
fuente
loggervariable utilizada no era la instanciada de una de mis clases, sino laloggervariable presente en la caché de Python3. , y el controlador fue agregado cada 60 segundos por un AppScheduler que configuré. Entonces, estaif not logger.handlerses una forma bastante inteligente de evitar este tipo de fenómeno. ¡Gracias por la solución, camarada :)!Si está viendo este problema y no está agregando el controlador dos veces, vea la respuesta de abarnert aquí
De los documentos :
Entonces, si desea un controlador personalizado en "prueba", y no desea que sus mensajes también vayan al controlador raíz, la respuesta es simple: desactive su indicador de propagación:
logger.propagate = Falso
fuente
El controlador se agrega cada vez que llama desde el exterior. Intente quitar el controlador después de terminar su trabajo:
fuente
logger.handlers.pop()en Python 2.7, hace el trucoSoy un novato en Python, pero esto pareció funcionar para mí (Python 2.7)
fuente
En mi caso, lo configuraría
logger.propagate = Falsepara evitar la doble impresión.En el siguiente código, si lo elimina
logger.propagate = False, verá una impresión doble.fuente
logger.propagate = Falsefue la solución para evitar el doble registro en una aplicación Flask alojada por Waitress, al iniciar sesión en laapp.loggerinstancia de Flask .Una llamada a las
logging.debug()llamadaslogging.basicConfig()si no hay controladores raíz instalados. Eso me estaba sucediendo en un marco de prueba en el que no podía controlar el orden en que se activaban los casos de prueba. Mi código de inicialización estaba instalando el segundo. El predeterminado usa logging.BASIC_FORMAT que no quería.fuente
Parece que si envía algo al registrador (accidentalmente) y luego lo configura, es demasiado tarde. Por ejemplo, en mi código tenía
Obtendría algo como (ignorando las opciones de formato)
y todo se escribió en stdout dos veces. Creo que esto se debe a que la primera llamada a
logging.warningcrea un nuevo controlador automáticamente y luego agregué explícitamente otro controlador. El problema desapareció cuando eliminé la primeralogging.warningllamada accidental .fuente
Me estaba dando una situación extraña en la que los registros de la consola se duplicaban, pero los registros de mis archivos no. Después de un montón de excavaciones, lo descubrí.
Tenga en cuenta que los paquetes de terceros pueden registrar registradores. Esto es algo a tener en cuenta (y en algunos casos no se puede prevenir). En muchos casos, el código de terceros comprueba si hay controladores de registro raíz existentes ; y si no lo hay, registran un nuevo controlador de consola.
Mi solución a esto fue registrar mi registrador de consola en el nivel raíz:
fuente