Registro de Python: deshabilite el registro de módulos importados

100

Estoy usando el módulo de registro de Python y me gustaría deshabilitar los mensajes de registro impresos por los módulos de terceros que importo. Por ejemplo, estoy usando algo como lo siguiente:

logger = logging.getLogger()
logger.setLevel(level=logging.DEBUG)
fh = logging.StreamHandler()
fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
fh.setFormatter(fh_formatter)
logger.addHandler(fh)

Esto imprime mis mensajes de depuración cuando hago un logger.debug ("¡mi mensaje!"), Pero también imprime los mensajes de depuración de cualquier módulo que importe (como solicitudes y muchas otras cosas).

Me gustaría ver solo los mensajes de registro de los módulos que me interesan. ¿Es posible hacer que el módulo de registro haga esto?

Idealmente, me gustaría poder decirle al registrador que imprima mensajes de "ModuleX, ModuleY" e ignore todos los demás.

Miré lo siguiente, pero no quiero tener que deshabilitar / habilitar el registro antes de cada llamada a una función importada: registro: ¿cómo ignorar los registros del módulo importado?

moto de nieve ciega
fuente

Respuestas:

69

El problema es que llamar getLoggersin argumentos devuelve el registrador raíz, por lo que cuando establece el nivel enlogging.DEBUG , también establece el nivel para otros módulos que usan ese registrador.

Puede resolver esto simplemente no usando el registrador raíz. Para hacer esto, simplemente pase un nombre como argumento, por ejemplo, el nombre de su módulo:

logger = logging.getLogger('my_module_name')
# as before

esto creará un nuevo registrador y, por lo tanto, no cambiará inadvertidamente el nivel de registro de otros módulos.


Obviamente, debe usar en logger.debuglugar de, logging.debugya que esta última es una función de conveniencia que llama al debugmétodo del registrador raíz.

Esto se menciona en el Tutorial de registro avanzado . También le permite saber qué módulo activó el mensaje de registro de una manera sencilla.

Bakuriu
fuente
37
Estoy creando un registrador con __name__r pero todavía veo los registros de los módulos importados. Estoy intentando configurar el registro con un archivo de configuración ini, ¿qué debo hacer para eso?
Durga Swaroop
8
La creación de un registrador con __name__tampoco funcionó para mí. ¿Quizás porque estoy usando un script independiente y no un "módulo"? Lo que funcionó para mí fue configurar el registro para módulos importados ( matpplotliben mi caso) a través de logging.getLogger("matplotlib").setLevel(logging.WARNING)y para mi script a través de logging.basicConfig.
bli
1
Solo quería resaltar el valor de tu línea "Obviamente tienes que usar en logger.debuglugar de logging.debug". Es un error fácil de cometer al usar el registro en lugar del registrador, pero usurpa toda la configuración inteligente que desea configurar. ¡He pasado las últimas horas viviendo esto!
timdadev
@bli Existe una gran diferencia entre registrar cuando se desarrolla una biblioteca y cuando se desarrolla un ejecutable. Básicamente: si está escribiendo un módulo / paquete que está destinado a ser importado que debiera no configurar nada. El módulo solo debe contener las logger = logging.getLogger('package.my_module')llamadas y sus llamadas could logger.debug/warning, sin configuración de niveles de registro o controladores. Cuando escriba la aplicación binaria allí , debe decidir el nivel de los distintos registros y controladores. Las bibliotecas que contienen la configuración de registro siempre serán un problema.
Bakuriu
En mi caso, el paquete que importo usa el registrador raíz (vía logging.info). ¿Hay alguna forma de deshabilitar específicamente los registros raíz de este paquete?
IanS
45

Si va a usar el loggingpaquete python , es una convención común definir un registrador en cada módulo que lo usa.

logger = logging.getLogger(__name__)

Muchos paquetes populares de Python hacen esto, incluido requests. Si un paquete usa esta convención, es fácil habilitar / deshabilitar el registro para él, porque el nombre del registrador será el mismo nombre que el del paquete (o será un hijo de ese registrador). Incluso puede registrarlo en el mismo archivo que sus otros registradores.

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

requests_logger = logging.getLogger('requests')
requests_logger.setLevel(logging.DEBUG)

handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
logger.addHandler(handler)
requests_logger.addHandler(handler)
Brendan Abel
fuente
15
Tenga en cuenta que cuando intente configurar sus registradores como en el tutorial básico oficial con logging.basicConfig(...)todos los registradores, ahora saldrá a logging.lastResort(comenzando con Python 3.2, que es stderr) si no se proporcionó un controlador o al controlador que configuró. Así que no lo use o seguirá recibiendo todos los mensajes de registro de todos modos.
user136036
44

No estoy seguro de si esto es apropiado para publicar, pero estuve atascado durante mucho tiempo y quería ayudar a cualquiera con el mismo problema, ¡ya que no lo había encontrado en ningún otro lugar!

Obtenía registros de depuración de matplotlib a pesar de seguir la documentación bastante sencilla en el tutorial avanzado de registro y la resolución de problemas . Estaba iniciando mi registrador en main()un archivo e importando una función para crear un gráfico desde otro archivo (donde había importado matplotlib).

Lo que funcionó para mí fue establecer el nivel de matplotlib antes de importarlo, en lugar de después, como lo hice para otros módulos en mi archivo principal. Esto me pareció contrario a la intuición, por lo que si alguien tiene una idea de cómo puede configurar la configuración para un registrador que aún no se ha importado, tendré curiosidad por saber cómo funciona. ¡Gracias!

En mi archivo principal:

import logging
import requests
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logging.getLogger('requests').setLevel(logging.DEBUG)

def main():
  ...

En mi plot.pyarchivo:

import logging
logging.getLogger('matplotlib').setLevel(logging.WARNING)
import matplotlib.pyplot as plt

def generatePlot():
  ...
finlandés
fuente
Recibí un error: el objeto 'Logger' no tiene el atributo 'DEBUG'. logger.DEBUGdebería serlogging.DEBUG
foxiris
¡Gracias! ¡Realmente ayuda! Configuré el nivel de registro de matplotlib después de mi configuración de registro principal y antes del comando que importará matplotlib. ¡Resuelto!
gph
He creado el registro para matplotlibque WARNING después he importado el módulo, ya que añadir que antes de importar daría una pelusa de errores. Todavía funcionó para mí. Estoy usando matplotlib==3.3.2Python 3.7 si ayuda.
Fin-2-Fin
9

@Bakuriu explica con bastante elegancia la función. Por el contrario, puede utilizar el getLogger()método para recuperar y reconfigurar / deshabilitar los registradores no deseados.

También quería agregar que el logging.fileConfig()método acepta un parámetro llamado disable_existing_loggersque deshabilitará cualquier registrador previamente definido (es decir, en módulos importados).

apex-meme-señor
fuente
9

Esto deshabilita todos los registradores existentes, como los creados por módulos importados, mientras se sigue utilizando el registrador raíz (y sin tener que cargar un archivo externo).

logging.config.dictConfig({
    'version': 1,
    'disable_existing_loggers': True,
})

¡Tenga en cuenta que primero debe importar todos los módulos que no desea que se registren! De lo contrario, no se considerarán "registradores existentes". Luego deshabilitará todos los registradores de esos módulos. ¡Esto podría llevarlo a perderse también errores importantes!

Para obtener ejemplos más detallados sobre el uso de opciones relacionadas para la configuración, consulte https://gist.github.com/st4lk/6287746 , y aquí hay un ejemplo (que funciona parcialmente) usando YAML para la configuración con la coloredlogbiblioteca.

avv
fuente
¿Cuál es tu pregunta?
user1767754
1
Esto funciona, por requestejemplo, pero no funcionará cuando los módulos importados creen sus registradores dentro de su clase a la que llamarías más tarde, como APSchedulerhace cuando llamas BackgroundScheduler.BackgroundScheduler(). Consulte aquí para obtener una solución: stackoverflow.com/a/48891485/2441026
user136036
Esto funciona para mi caso con el archivo de configuración
yaml
4

Podrías usar algo como:

logging.getLogger("imported_module").setLevel(logging.WARNING)
logging.getLogger("my_own_logger_name").setLevel(logging.DEBUG)

Esto establecerá el nivel de registro de mi propio módulo en DEBUG, mientras que evita que el módulo importado use el mismo nivel.

Nota: "imported_module"se puede reemplazar con imported_module.__name__(sin comillas), y "my_own_logger_name"se puede reemplazar por __name__si esa es la forma en que prefiere hacerlo.

Kamiku
fuente
1

Yo tuve el mismo problema. Tengo un archivo logging_config.py que importo en todos los demás archivos py. En el archivo logging_config.py configuré el nivel de registro del registrador raíz en ERROR (de forma predeterminada, su advertencia):

logging.basicConfig(
    handlers=[
        RotatingFileHandler('logs.log',maxBytes=1000, backupCount=2),
        logging.StreamHandler(), #print to console
    ],
    level=logging.ERROR
)

En otros módulos, importo logging_config.py y declaro un nuevo registrador y configuro su nivel para depurar:

log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)

De esta manera, todo lo que inicie sesión en mis archivos py se registra, pero las cosas que se registran en el nivel de depuración e información mediante módulos importados como urllib, request, boto3, etc.no se registran. Si hay algún error en esos módulos de importación, entonces se registra, ya que configuré el nivel de registradores raíz en ERROR.

Aseem
fuente
0

Otra cosa a considerar es la propiedad de propagación de la clase Logger.

Por ejemplo, biblioteca py-suds para manejar llamadas de jabón, incluso poner ERROR

logging.getLogger('suds.client').setLevel(logging.ERROR)
logging.getLogger('suds.transport').setLevel(logging.ERROR)
logging.getLogger('suds.xsdschema').setLevel(logging.ERROR)
logging.getLogger('suds.wsdl').setLevel(logging.ERROR)

registros registros sobre un módulo llamado sxbasics.py creación de una gran cantidad de registros

ingrese la descripción de la imagen aquí

que debido a que la propagación de los registros es Verdadera de forma predeterminada, estableciendo en Falso, en cambio, recuperé 514 MB de registros.

import logging
logging.getLogger("suds").propagate = False
logging.getLogger('suds.client').setLevel(logging.ERROR)
logging.getLogger('suds.transport').setLevel(logging.ERROR)
logging.getLogger('suds.xsdschema').setLevel(logging.ERROR)
logging.getLogger('suds.wsdl').setLevel(logging.ERROR)
Andrea Bisello
fuente