2012-12-12 8 views
21

Non riesco a eseguire un file di registrazione al volo. Cambio di rubrica.Come modificare il filehandle con la registrazione Python al volo con classi diverse e importazioni

Ad esempio, ho 3 classi

one.py

import logging 
class One(): 
    def __init__(self,txt="?"): 
     logging.debug("Hey, I'm the class One and I say: %s" % txt) 

two.py

import logging 
class Two(): 
    def __init__(self,txt="?"): 
     logging.debug("Hey, I'm the class Two and I say: %s" % txt) 

config.py

import logging 
class Config(): 
    def __init__(self,logfile=None): 
     logging.debug("Reading config") 
     self.logfile(logfile) 

myapp

from one import One 
from two import Two 
from config import Config 
import logging 

#Set default logging 
logging.basicConfig( 
    level=logging.getLevelName(DEBUG), 
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', 
    filename=None 
) 

logging.info("Starting with stdout") 

o=One(txt="STDOUT") 
c=Config(logfile="/tmp/logfile") 

# Here must be the code that change the logging configuration and set the filehandler 

t=One(txt="This must be on the file, not STDOUT") 

Se provo loggin.basicConfig() ancora una volta, non funziona.

risposta

28

Infatti, logging.basicConfig non fa nulla se un gestore è stato istituito già:

Questa funzione non fa nulla se il logger principale ha già gestori configurati per esso.

Avrai bisogno di sostituire il gestore corrente sul logger principale:

import logging 

fileh = logging.FileHandler('/tmp/logfile', 'a') 
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 
fileh.setFormatter(formatter) 

log = logging.getLogger() # root logger 
for hdlr in log.handlers[:]: # remove all old handlers 
    log.removeHandler(hdlr) 
log.addHandler(fileh)  # set the new handler 

Vedi l'Configuring Logging chapter nella HOWTO Python registrazione.

+0

Funziona anche con il daemon python! –

+0

In realtà non si dovrebbero rimuovere i gestori da un elenco mentre si sta iterando su di esso, nel mio caso uno dei logger è rimasto nell'elenco. Vedi [questo thread] (http://stackoverflow.com/questions/7484454/removing-handlers-from-pythons-logging-loggers). Il semplice 'log.handlers = [fileh]' dovrebbe funzionare. – hillel

+1

@hillel: ah, infatti, il ciclo dovrebbe fare una copia; corretto. Prendi in considerazione che il metodo 'removeHandler()' si occupa anche del blocco per rendere i gestori della rimozione thread-safe, sebbene assegnare direttamente un nuovo oggetto lista * dovrebbe * anche essere soddisfacente. –

7

Ho trovato un modo più semplice rispetto alla risposta sopra "accettata". Se hai un riferimento al gestore, tutto ciò che devi fare è chiamare il metodo close() e quindi impostare la proprietà baseFilename. Quando assegni baseFilename, assicurati di utilizzare os.path.abspath(). C'è un commento nella fonte della biblioteca che indica che è necessario. Conservo i miei elementi di configurazione in un dict globale(), quindi è facile mantenere gli oggetti di riferimento FileHandler. Come puoi vedere di seguito, bastano 2 righe di codice per cambiare un nome file di registro per un gestore al volo.

import logging 

def setup_logging(): 
    global config 

    if config['LOGGING_SET']: 
    config['LOG_FILE_HDL'].close() 
    config['LOG_FILE_HDL'].baseFilename = os.path.abspath(config['LOG_FILE']) 

    config['DEBUG_LOG_HDL'].close() 
    config['DEBUG_LOG_HDL'].baseFilename = os.path.abspath(config['DEBUG_LOG']) 
    else: 
    format_str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 
    formatter = logging.Formatter(format_str) 

    log = logging.getLogger() 

    log.setLevel(logging.DEBUG) 

    # add file mode="w" to overwrite 
    config['LOG_FILE_HDL'] = logging.FileHandler(config['LOG_FILE'], mode='a') 
    config['LOG_FILE_HDL'].setLevel(logging.INFO) 
    config['LOG_FILE_HDL'].setFormatter(formatter) 
    log.addHandler(config['LOG_FILE_HDL']) 

    # the delay=1 should prevent the file from being opened until used. 
    config['DEBUG_LOG_HDL'] = logging.FileHandler(config['DEBUG_LOG'], mode='a', delay=1) 
    config['DEBUG_LOG_HDL'].setLevel(logging.DEBUG) 
    config['DEBUG_LOG_HDL'].setFormatter(formatter) 
    log.addHandler(config['DEBUG_LOG_HDL']) 

    ch = logging.StreamHandler() 
    ch.setLevel(logging.DEBUG) 
    ch.setFormatter(formatter) 
    log.addHandler(ch) 
    config['LOGGING_SET'] = True 
1

La risposta fornita da @Martijn Pieters funziona correttamente. Tuttavia, lo snipper di codice rimuove tutti i gestori e riporta solo il gestore di file. Ciò sarà problematico se la tua applicazione ha gestori aggiunti da altri moduli.

Quindi, il frammento di seguito è progettato in modo tale da sostituire solo il gestore di file.

La riga if isinstance(hdlr,log.FileHander) è la chiave.

import logging 

filehandler = logging.FileHandler('/tmp/logfile', 'a') 
formatter = logging.Formatter('%(asctime)-15s::%(levelname)s::%(filename)s::%(funcName)s::%(lineno)d::%(message)s') 
filehandler.setFormatter(formatter) 
log = logging.getLogger() # root logger - Good to get it only once. 
for hdlr in log.handlers[:]: # remove the existing file handlers 
    if isinstance(hdlr,log.FileHander): 
     log.removeHandler(hdlr) 
log.addHandler(filehandler)  # set the new handler 
# set the log level to INFO, DEBUG as the default is ERROR 
logging.setLevel(log.DEBUG)  
Problemi correlati