El registro de Python no genera nada

97

En un script de Python que estoy escribiendo, estoy tratando de registrar eventos usando el módulo de registro. Tengo el siguiente código para configurar mi registrador:

ERROR_FORMAT = "%(levelname)s at %(asctime)s in %(funcName)s in %(filename) at line %(lineno)d: %(message)s"
DEBUG_FORMAT = "%(lineno)d in %(filename)s at %(asctime)s: %(message)s"
LOG_CONFIG = {'version':1,
              'formatters':{'error':{'format':ERROR_FORMAT},
                            'debug':{'format':DEBUG_FORMAT}},
              'handlers':{'console':{'class':'logging.StreamHandler',
                                     'formatter':'debug',
                                     'level':logging.DEBUG},
                          'file':{'class':'logging.FileHandler',
                                  'filename':'/usr/local/logs/DatabaseUpdate.log',
                                  'formatter':'error',
                                  'level':logging.ERROR}},
              'root':{'handlers':('console', 'file')}}
logging.config.dictConfig(LOG_CONFIG)

Cuando trato de ejecutar logging.debug("Some string"), no obtengo ningún resultado en la consola, aunque esta página en los documentos dice que logging.debugel registrador raíz debería mostrar el mensaje. ¿Por qué mi programa no produce nada y cómo puedo solucionarlo?

murgatroid99
fuente

Respuestas:

103

El nivel de registro predeterminado es advertencia. Como no ha cambiado el nivel, el nivel del registrador raíz sigue siendo una advertencia. Eso significa que ignorará cualquier registro con un nivel inferior al de advertencia, incluidos los registros de depuración.

Esto se explica en el tutorial :

import logging
logging.warning('Watch out!') # will print a message to the console
logging.info('I told you so') # will not print anything

La línea 'info' no imprime nada, porque el nivel es más alto que info.

Para cambiar el nivel, simplemente configúrelo en el registrador raíz:

'root':{'handlers':('console', 'file'), 'level':'DEBUG'}

En otras palabras, no es suficiente definir un controlador con level = DEBUG, el nivel de registro real también debe ser DEBUG para que dé salida a algo.

Omri Barel
fuente
7
La documentación dice que su nivel predeterminado es NOTSET, que es un nivel de 0 que debería generar todo ... ¿Por qué no es cierto?
Ben
@Ben, ¿dónde dice eso? Todo lo que puedo ver es "El nivel predeterminado es ADVERTENCIA, lo que significa que solo se rastrearán los eventos de este nivel y superiores, a menos que el paquete de registro esté configurado para hacer lo contrario".
Omri Barel
1
@Ben de acuerdo con los documentos, los registradores se recorren para encontrar el primer padre con level != NOTSETo la raíz (si no se encuentra ninguno). La raíz tiene WARNINGnivel por defecto. Esto está escrito en la sección a la que ha vinculado ( Logger.setLevel).
Omri Barel
6
Tenga en cuenta que después de importar logging, debe llamar logging.basicConfig()al menos una vez. De lo contrario, es posible que se sorprenda mucho de que los registradores infantiles no impriman nada. Las funciones de registro en el registrador raíz lo llaman perezosamente.
Hubert Grzeskowiak
74

Muchos años después, parece que todavía hay un problema de usabilidad con el registrador de Python. Aquí hay algunas explicaciones con ejemplos:

import logging
# This sets the root logger to write to stdout (your console).
# Your script/app needs to call this somewhere at least once.
logging.basicConfig()

# By default the root logger is set to WARNING and all loggers you define
# inherit that value. Here we set the root logger to NOTSET. This logging
# level is automatically inherited by all existing and new sub-loggers
# that do not set a less verbose level.
logging.root.setLevel(logging.NOTSET)

# The following line sets the root logger level as well.
# It's equivalent to both previous statements combined:
logging.basicConfig(level=logging.NOTSET)


# You can either share the `logger` object between all your files or the
# name handle (here `my-app`) and call `logging.getLogger` with it.
# The result is the same.
handle = "my-app"
logger1 = logging.getLogger(handle)
logger2 = logging.getLogger(handle)
# logger1 and logger2 point to the same object:
# (logger1 is logger2) == True


# Convenient methods in order of verbosity from highest to lowest
logger.debug("this will get printed")
logger.info("this will get printed")
logger.warning("this will get printed")
logger.error("this will get printed")
logger.critical("this will get printed")


# In large applications where you would like more control over the logging,
# create sub-loggers from your main application logger.
component_logger = logger.getChild("component-a")
component_logger.info("this will get printed with the prefix `my-app.component-a`")

# If you wish to control the logging levels, you can set the level anywhere 
# in the hierarchy:
#
# - root
#   - my-app
#     - component-a
#

# Example for development:
logger.setLevel(logging.DEBUG)

# If that prints too much, enable debug printing only for your component:
component_logger.setLevel(logging.DEBUG)


# For production you rather want:
logger.setLevel(logging.WARNING)

Una fuente común de confusión proviene de un registrador raíz mal inicializado. Considera esto:

import logging
log = logging.getLogger("myapp")
log.warning("woot")
logging.basicConfig()
log.warning("woot")

Salida:

woot
WARNING:myapp:woot

Dependiendo de su entorno de ejecución y niveles de registro, es posible que la primera línea de registro (antes de la configuración básica) no aparezca en ninguna parte .

Hubert Grzeskowiak
fuente
Mi registro no funciona, ya que no produce ningún archivo de salida. ¿Ves algo que esté haciendo que esté claramente mal? logging.basicConfig( filename='logging.txt', level=logging.DEBUG) logger = logging.getLogger() logger.info('Test B') logging.info('Test A')
Rylan Schaeffer
El archivo de registro ni siquiera se crea
Rylan Schaeffer
Noté que cuando dejo caer un punto de interrupción después logger = logging.getLogger(), el nivel se establece en ADVERTENCIA aunque especifiqué el nivel como DEBUG. ¿Sabes lo que estoy haciendo mal?
Rylan Schaeffer
Hola @RylanSchaeffer, es posible que desee crear una nueva pregunta y proporcionar más detalles. Esto también le dará a otros la oportunidad de ayudarlo.
Hubert Grzeskowiak
Yo hice. Con frecuencia, hacer un comentario es una forma más rápida de encontrar una respuesta porque al menos una persona con conocimientos verá mi pregunta
Rylan Schaeffer
27

Para cualquiera que quiera una respuesta súper simple: simplemente configure el nivel que desea que se muestre. En la parte superior de todos mis scripts, solo puse:

import logging
logging.basicConfig(level = logging.INFO)

Luego, para mostrar cualquier cosa en o por encima de ese nivel:

logging.info("Hi you just set your fleeb to level plumbus")

Es un conjunto jerárquico de cinco niveles para que los registros se muestren en el nivel que establezca o en un nivel superior . Entonces, si desea mostrar un error, puede usar logging.error("The plumbus is broken").

Los niveles, en orden de gravedad creciente, son DEBUG, INFO, WARNING, ERROR, y CRITICAL. La configuración predeterminada es WARNING.

Este es un buen artículo que contiene esta información expresada mejor que mi respuesta:
https://www.digitalocean.com/community/tutorials/how-to-use-logging-in-python-3

Eric
fuente
14

¿Quizás probar esto? Parece que el problema se resuelve después de eliminar todos los controladores en mi caso.

for handler in logging.root.handlers[:]:
    logging.root.removeHandler(handler)

logging.basicConfig(filename='output.log', level=logging.INFO)
yue dong
fuente
SyntaxError: invalid syntax
Eric
2
¿Por qué es esto necesario? ¿Qué controladores vienen con el registrador de Python y por qué están ahí para empezar? O tal vez la pregunta es, ¿por qué basicConfig no los anula / reemplaza?
2019