La registrazione di Python non restituisce nulla


94

In uno script Python che sto scrivendo, sto cercando di registrare eventi utilizzando il modulo di registrazione. Ho il seguente codice per configurare il mio logger:

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)

Quando provo a eseguire logging.debug("Some string"), non ottengo alcun output sulla console, anche se questa pagina nei documenti dice che logging.debugdovrebbe avere il logger di root in output il messaggio. Perché il mio programma non emette nulla e come posso risolverlo?

Risposte:


98

Il livello di registrazione predefinito è avviso. Poiché non hai cambiato il livello, il livello del logger di root è ancora un avviso. Ciò significa che ignorerà qualsiasi registrazione con un livello inferiore all'avviso, comprese le registrazioni di debug.

Questo è spiegato nel 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 riga "info" non stampa nulla, perché il livello è superiore a info.

Per cambiare il livello, basta impostarlo nel root logger:

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

In altre parole, non è sufficiente definire un gestore con level = DEBUG, anche il livello di registrazione effettivo deve essere DEBUG per fare in modo che emetta qualcosa.


6
La documentazione dice che il suo livello predefinito è NOTSET che è un livello di 0 che dovrebbe visualizzare tutto ... Perché questo non è vero?
Ben

@ Ben dove si dice? Tutto quello che posso vedere è "Il livello predefinito è WARNING, il che significa che verranno tracciati solo gli eventi di questo livello e di quelli superiori, a meno che il pacchetto di registrazione non sia configurato per fare diversamente".
Omri Barel


1
@Ben secondo i documenti i logger vengono attraversati per trovare il primo genitore con level != NOTSETo la radice (se non viene trovato nessuno). La radice ha il WARNINGlivello per impostazione predefinita. Questo è scritto nella sezione a cui sei collegato ( Logger.setLevel).
Omri Barel

5
Tieni presente che dopo l'importazione loggingè necessario chiamare logging.basicConfig()almeno una volta. Altrimenti potresti essere molto sorpreso dal fatto che i logger secondari non stamperanno nulla. Le funzioni di registrazione sul logger di root lo chiamano pigramente.
Hubert Grzeskowiak

58

Molti anni dopo sembra esserci ancora un problema di usabilità con il logger di Python. Ecco alcune spiegazioni con esempi:

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 comune fonte di confusione proviene da un root logger inizializzato male. Considera questo:

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

Produzione:

woot
WARNING:myapp:woot

A seconda dell'ambiente di runtime e dei livelli di registrazione, la prima riga di registro (prima della configurazione di base) potrebbe non essere visualizzata da nessuna parte .


La mia registrazione non funziona, in quanto non produce file di output. Vedi qualcosa che sto facendo che sia chiaramente sbagliato? logging.basicConfig( filename='logging.txt', level=logging.DEBUG) logger = logging.getLogger() logger.info('Test B') logging.info('Test A')
Rylan Schaeffer

Il file di registrazione non viene nemmeno creato
Rylan Schaeffer

Ho notato che quando abbandono un punto di interruzione dopo logger = logging.getLogger(), il livello è impostato su ATTENZIONE anche se ho specificato il livello come DEBUG. Sai cosa sto sbagliando?
Rylan Schaeffer

Ciao @RylanSchaeffer, potresti voler creare una nuova domanda e fornire ulteriori dettagli. Questo darà anche agli altri la possibilità di aiutarti.
Hubert Grzeskowiak

L'ho fatto. Spesso, chiedere un commento è un modo più veloce per trovare una risposta perché almeno una persona esperta vedrà la mia domanda
Rylan Schaeffer

20

Per chiunque qui desideri una risposta semplicissima: imposta il livello che desideri visualizzare. In cima a tutti i miei script ho appena messo:

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

Quindi, per visualizzare qualsiasi cosa pari o superiore a quel livello:

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

È un insieme gerarchico di cinque livelli in modo che i registri vengano visualizzati al livello impostato o superiore . Quindi, se vuoi visualizzare un errore, puoi usare logging.error("The plumbus is broken").

I livelli, in ordine crescente di gravità, sono DEBUG, INFO, WARNING, ERROR, e CRITICAL. L'impostazione predefinita è WARNING.

Questo è un buon articolo contenente queste informazioni espresse meglio della mia risposta:
https://www.digitalocean.com/community/tutorials/how-to-use-logging-in-python-3


14

Forse provare questo? Sembra che il problema sia risolto dopo aver rimosso tutti i gestori nel mio caso.

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

logging.basicConfig(filename='output.log', level=logging.INFO)

SyntaxError: invalid syntax
Eric

2
Perché è necessario? Quali gestori vengono forniti con il logger python e perché sono lì per cominciare? O forse la domanda è: perché basicConfig non li sovrascrive / li sostituisce?
jrh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.