2012-02-16 15 views
8

Stavo cercando di creare un attributo personalizzato per la registrazione (nome della classe del chiamante, nome del modulo, ecc.) E mi sono bloccato con una strana eccezione che mi diceva che l'istanza LogRecord creata nel processo non aveva gli attributi necessari Dopo un po 'di test ho finito con questo:Modulo di registrazione Python: logger personalizzati

import logging 

class MyLogger(logging.getLoggerClass()): 
    value = None 

logging.setLoggerClass(MyLogger) 

loggers = [ 
    logging.getLogger(), 
    logging.getLogger(""), 
    logging.getLogger("Name") 
] 

for logger in loggers: 
    print(isinstance(logger, MyLogger), hasattr(logger, "value")) 

questo apparentemente corretta pezzo di rendimenti codice:

False False 
False False 
True True 

bug o funzionalità?

risposta

5

Guardando il codice sorgente si può vedere la seguente:

root = RootLogger(WARNING) 
def getLogger(name=None): 
    if name: 
     return Logger.manager.getLogger(name) 
    else: 
     return root 

ovvero un logger principale predefinita, viene creato quando il modulo viene importato. Quindi, ogni volta che si cerca il root looger (passando un valore falso come la stringa vuota), si otterrà un oggetto logging.RootLogger indipendentemente da qualsiasi chiamata a logging.setLoggerClass.

Per quanto riguarda la classe logger in uso possiamo vedere:

_loggerClass = None 
def setLoggerClass(klass): 
    ... 
    _loggerClass = klass 

Ciò significa che una variabile globale contiene la classe logger da utilizzare in futuro.

In aggiunta a questo, guardando logging.Manager (usato da logging.getLogger), possiamo vedere questo:

def getLogger(self, name): 
    ... 
      rv = (self.loggerClass or _loggerClass)(name) 

Cioè, se self.loggerClass non è impostato (che non verrà meno che non hai esplicitamente impostalo), viene utilizzata la classe dalla variabile globale.

Quindi, è una funzionalità. Il root logger è sempre un oggetto logging.RootLogger e gli altri oggetti logger vengono creati in base alla configurazione in quel momento.

2

logging.getLogger() e logging.getLogger("") non restituiscono un MyLogger perché restituiscono il logger principale della gerarchia di registrazione, come descritto nella logging documentation:

logging.getLogger ([name])

Return un logger con il nome specificato o, se nessun nome è specificato, restituisce un logger che è il logger principale della gerarchia.

Così, come si ha il registratore impostato:

>>> logging.getLogger() 
<logging.RootLogger object at 0x7d9450> 
>>> logging.getLogger("foo") 
<test3.MyLogger object at 0x76d9f0> 

Non credo che questo è legato al KeyError hai iniziato il tuo post. Dovresti pubblicare il codice che ha generato quell'eccezione (test.py).

+0

Grazie per il tuo commento, ho modificato la domanda. Ma penso che questo comportamento non sia quello che ci si aspetterebbe di accadere. – Pastafarianist

+0

Perché non è quello che ti aspetteresti che accada? È * precisamente * ciò che la documentazione dice che accadrà quando non viene specificato alcun nome. –

+4

Anche se questo è quello che dice la documentazione, è contro-intuitivo. Impostando una classe per i logger, mi aspetterei che _all_ logger abbiano quella classe, inclusa quella di root ed escludendo quelli già istanziati. – Pastafarianist

Problemi correlati