2013-07-16 9 views
33

Diciamo che ho il seguente codice:Qual è il punto di setLevel in un gestore di registrazione Python?

import logging 
import logging.handlers 

a = logging.getLogger('myapp') 
h = logging.handlers.RotatingFileHandler('foo.log') 
h.setLevel(logging.DEBUG) 
a.addHandler(h) 

# The effective log level is still logging.WARN 
print a.getEffectiveLevel() 
a.debug('foo message') 
a.warn('warning message') 

mi aspetto che l'impostazione logging.DEBUG sul gestore causerebbe messaggi a livello di debug da scrivere nel file di registro. Tuttavia, stampa 30 per il livello effettivo (uguale a logging.WARNING, l'impostazione predefinita) e registra solo il messaggio warn nel file di registro, non il messaggio di debug.

Sembra che il livello di log del conduttore sia caduto sul pavimento, ad es. è silenziosamente ignorato. Il che mi fa meravigliare, perché avere il setLevel sul gestore?

+0

Buona domanda, ma per motivi di coerenza, se si sta testando 'a.getEffectiveLevel',' a.setLevel' ha più senso di 'h.setLevel'. –

+0

In questo caso il gestore non ha un comando 'getEffectiveLevel' –

risposta

34

Consente un controllo più preciso. Per impostazione predefinita, il logger root ha il set di livelli WARNING, questo significa che non stamperà i messaggi con un livello inferiore (indipendentemente da come sono impostati i livelli dei gestori!). Ma, se si imposta il livello del logger principale per DEBUG, anzi il messaggio vengono inviati al file di registro:

import logging 
import logging.handlers 

a = logging.getLogger('myapp') 
a.setLevel(logging.DEBUG) # set root's level 
h = logging.handlers.RotatingFileHandler('foo.log') 
h.setLevel(logging.DEBUG) 
a.addHandler(h) 
print a.getEffectiveLevel() 
a.debug('foo message') 
a.warn('warning message') 

Ora, un'immagine che si desidera aggiungere un nuovo gestore che non registra le informazioni di debug. È possibile farlo semplicemente impostando il livello di registrazione del gestore:

import logging 
import logging.handlers 

a = logging.getLogger('myapp') 
a.setLevel(logging.DEBUG) # set root's level 

h = logging.handlers.RotatingFileHandler('foo.log') 
h.setLevel(logging.DEBUG) 
a.addHandler(h) 

h2 = logging.handlers.RotatingFileHandler('foo2.log') 
h2.setLevel(logging.WARNING) 
a.addHandler(h2) 

print a.getEffectiveLevel() 
a.debug('foo message') 
a.warn('warning message') 

Ora, il file di log foo.log conterrà entrambi i messaggi, mentre il file foo2.log conterrà solo il messaggio di avviso. Potresti essere interessato ad avere un file di registro di soli messaggi a livello di errore, quindi aggiungere semplicemente un Handler e impostare il suo livello su logging.ERROR, tutto usando lo stesso Logger.

Si può pensare al livello di registrazione Logger come una restrizione globale su cui i messaggi sono "interessanti" per un determinato logger e i suoi gestori. I messaggi che sono considerati dal logger successivamente vengono inviati ai gestori, che eseguono il proprio processo di filtraggio e registrazione.

+3

Quindi la migliore pratica è impostare un livello inferiore di logger root e controllare la registrazione tramite il livello dei gestori. Ho ragione? – laike9m

+0

Non è "la migliore pratica", è solo che fare qualsiasi altra cosa è piuttosto inutile. Se il livello del gestore è DEBUG ma il logger invia solo ERROR, il gestore ovviamente riceverà (e passerà) ERROR. – hmijail

14

Nella registrazione Python ci sono due concetti diversi: il livello al quale il logger accede e il livello effettivamente attivato dal gestore.

Quando una chiamata per accedere è fatto, ciò che sta accadendo è fondamentalmente:

if self.level <= loglevel: 
    for handler in self.handlers: 
     handler(loglevel, message) 

Mentre ciascuno di questi gestori saranno quindi chiamare:

if self.level <= loglevel: 
    # do something spiffy with the log! 

Se vuoi un mondo reale dimostrazione di questo, è possibile guardare Django's config settings. Includerò qui il codice pertinente

LOGGING = { 
    #snip 
    'handlers': { 
     'null': { 
      'level': 'DEBUG', 
      'class': 'logging.NullHandler', 
     }, 
     'console':{ 
      'level': 'DEBUG', 
      'class': 'logging.StreamHandler', 
      'formatter': 'simple' 
     }, 
     'mail_admins': { 
      'level': 'ERROR', 
      'class': 'django.utils.log.AdminEmailHandler', 
      'filters': ['special'] 
     } 
    }, 
    'loggers': { 
     #snip 
     'myproject.custom': { 
      # notice how there are two handlers here! 
      'handlers': ['console', 'mail_admins'], 
      'level': 'INFO', 
      'filters': ['special'] 
     } 
    } 
} 

Così, nella configurazione di cui sopra, registra solo per getLogger('myproject.custom').info e soprattutto andranno trattati per la registrazione. Quando ciò accade, la console emetterà tutti i risultati (verrà emesso tutto perché è impostato sul livello DEBUG), mentre il logger mail_admins si verificherà per tutti gli ERROR s, FATAL s e CRITICAL s.

suppongo po 'di codice che non è Django potrebbe aiutare anche:

import logging.handlers as hand 
import logging as logging 

# to make things easier, we'll name all of the logs by the levels 
fatal = logging.getLogger('fatal') 
warning = logging.getLogger('warning') 
info = logging.getLogger('info') 

fatal.setLevel(logging.FATAL) 
warning.setLevel(logging.WARNING) 
info.setLevel(logging.INFO)  

fileHandler = hand.RotatingFileHandler('rotating.log') 

# notice all three are re-using the same handler. 
fatal.addHandler(fileHandler) 
warning.addHandler(fileHandler) 
info.addHandler(fileHandler) 

# the handler should log everything except logging.NOTSET 
fileHandler.setLevel(logging.DEBUG) 

for logger in [fatal,warning,info]: 
    for level in ['debug','info','warning','error','fatal']: 
     method = getattr(logger,level) 
     method("Debug " + logger.name + " = " + level) 

# now, the handler will only do anything for *fatal* messages... 
fileHandler.setLevel(logging.FATAL) 

for logger in [fatal,warning,info]: 
    for level in ['debug','info','warning','error','fatal']: 
     method = getattr(logger,level) 
     method("Fatal " + logger.name + " = " + level) 

che si traduce in:

Debug fatal = fatal 
Debug warning = warning 
Debug warning = error 
Debug warning = fatal 
Debug info = info 
Debug info = warning 
Debug info = error 
Debug info = fatal 
Fatal fatal = fatal 
Fatal warning = fatal 
Fatal info = fatal 

Anche in questo caso, si noti come info registrato qualcosa al info, warning, error, e fatal quando il gestore di registri era impostato su DEBUG, ma quando il gestore era impostato su all'improvviso solo i messaggi lo rendevano t o il file.

9

I gestori rappresentano diversi segmenti di pubblico per la registrazione di eventi. I livelli sugli handler sono usati per controllare la verbosità dell'output visto da un particolare pubblico, e comportano lo in aggiunta allo a qualsiasi livello impostato sui logger. I livelli sui logger vengono utilizzati per controllare la verbosità complessiva della registrazione da parti diverse di un'applicazione o di una libreria.

Vedi this diagram per ulteriori informazioni su come gli eventi di registrazione vengono gestiti:

enter image description here