2012-12-27 13 views
257

C'è un modo per fare il logging Python utilizzando il modulo logging e inviare automaticamente allo stdout inoltre nel file di registro dove dovrebbero andare? Ad esempio, vorrei che tutte le chiamate a logger.warning, logger.critical, logger.error andassero nei luoghi previsti, ma che siano inoltre sempre copiate su stdout. Questo per evitare la duplicazione di messaggi come:Creazione di logger Python tutti i messaggi su stdout in aggiunta al registro

mylogger.critical("something failed") 
print "something failed" 
+0

Si prega di controllare questa risposta https://stackoverflow.com/questions/9321741/printing-to-screen-and-writing-to -a-file-allo-stesso-tempo – SeF

risposta

369

Tutta l'uscita di registrazione viene gestita dagli handler; basta aggiungere un logging.StreamHandler() al logger principale.

Ecco un esempio la configurazione di un gestore flusso (usando stdout al posto del default stderr) e aggiungendolo al logger principale:

import logging 
import sys 

root = logging.getLogger() 
root.setLevel(logging.DEBUG) 

ch = logging.StreamHandler(sys.stdout) 
ch.setLevel(logging.DEBUG) 
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 
ch.setFormatter(formatter) 
root.addHandler(ch) 
+3

Va bene, ma se è già reindirizzato a un file come posso averlo essere stampato su '' stdout'' in aggiunta? – user248237dfsf

+31

@ user248237: aggiungendo un * nuovo * gestore come illustrato. I nuovi gestori non sostituiscono i gestori esistenti, ma * anche * elaborano le voci del registro. –

+0

@MartijnPieters c'è un modo per aggiungere una stringa a ogni istruzione del registro stampata? –

41

E 'possibile utilizzare più gestori.

import logging 
import auxiliary_module 

# create logger with 'spam_application' 
log = logging.getLogger('spam_application') 
log.setLevel(logging.DEBUG) 

# create formatter and add it to the handlers 
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 

# create file handler which logs even debug messages 
fh = logging.FileHandler('spam.log') 
fh.setLevel(logging.DEBUG) 
fh.setFormatter(formatter) 
log.addHandler(fh) 

# create console handler with a higher log level 
ch = logging.StreamHandler() 
ch.setLevel(logging.ERROR) 
ch.setFormatter(formatter) 
log.addHandler(ch) 

log.info('creating an instance of auxiliary_module.Auxiliary') 
a = auxiliary_module.Auxiliary() 
log.info('created an instance of auxiliary_module.Auxiliary') 

log.info('calling auxiliary_module.Auxiliary.do_something') 
a.do_something() 
log.info('finished auxiliary_module.Auxiliary.do_something') 

log.info('calling auxiliary_module.some_function()') 
auxiliary_module.some_function() 
log.info('done with auxiliary_module.some_function()') 

# remember to close the handlers 
for handler in log.handlers: 
    handler.close() 
    log.removeFilter(handler) 

Si veda: https://docs.python.org/2/howto/logging-cookbook.html

+4

Risposta meravigliosa, anche se un po 'confusa. Adoro come mostri come utilizzare diversi livelli e formati per flussi e file. +1, ma +2 nello spirito. –

254

il modo più semplice:

import logging 
import sys 
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 
+34

Hm, ma questo non è registrato in un file, giusto?La domanda era come fare il logging al file _and_ alla console. – Weidenrinde

+8

Questo potrebbe non essere quello che l'OP chiedeva, ma è esattamente quello che stavo cercando e il primo successo su Google. +1 – phoenix

+0

Probabilmente la risposta che ti serve, ma non quello che è stato richiesto :-P –

23

Il modo più semplice per accedere a file e stderr:

import logging 
    logging.basicConfig(filename="logfile.txt") 
    stderrLogger=logging.StreamHandler() 
    stderrLogger.setFormatter(logging.Formatter(logging.BASIC_FORMAT)) 
    logging.getLogger().addHandler(stderrLogger) 
+0

Questo non mostra le etichette INFO, DEBUG ed ERRORE prima del messaggio di registrazione nella console. Mostra quelle etichette nel file. Qualche idea di mostrare anche le etichette nella console? –

+1

Grazie, @JahMyst, ho aggiunto il formattatore. Sfortunatamente, non è più così breve, ma è ancora il modo più semplice. :-) – Weidenrinde

+0

Grazie, è grandioso! –

-13

hacker, ma più semplice:

def print_n_log(msg,f): 
    f.write(msg + "\n") 
    print msg 
f = open("log_output.txt","w") 

allora ogni volta che avete bisogno di stampare + registrare qualcosa basta chiamare

print_n_log("my message, hark!", f) 

e al poi fine dello script chiudere il file di registro:

f.close() 
+0

... oltre al registro! – kame

9

Si potrebbe creare due gestori per il file e stdout e quindi creare un logger con argomento handlers su basicConfig. Potrebbe essere utile se avete la stessa log_level e formato di output per entrambi i gestori:

import logging 
import sys 

file_handler = logging.FileHandler(filename='tmp.log') 
stdout_handler = logging.StreamHandler(sys.stdout) 
handlers = [file_handler, stdout_handler] 

logging.basicConfig(
    level=logging.DEBUG, 
    format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', 
    handlers=handlers 
) 

logger = logging.getLogger('LOGGER_NAME') 
Problemi correlati