2012-06-20 1 views
19

Ho uno script Python che fa uso di "Stampa" per la stampa su stdout. Di recente ho aggiunto la registrazione tramite Python Logger e vorrei farlo in modo che queste istruzioni di stampa vadano al logger se la registrazione è abilitata. Non voglio modificare o rimuovere queste istruzioni di stampa.Reindirizzare l'output di "stampa" Python al logger

Posso accedere facendo 'log.info ("qualche info msg")'. Voglio essere in grado di fare qualcosa del genere:

if logging_enabled: 
    sys.stdout=log.info 
print("test") 

Se la registrazione è attivata, "test" deve essere registrato come se l'avessi fatto log.info ("test"). Se la registrazione non è abilitata, "test" dovrebbe essere stampato sullo schermo.

È possibile? So che posso dirigere stdout a un file in maniera simile (vedi: redirect prints to log file)

risposta

15

Sono disponibili due opzioni:

  1. Aprire un file di log e sostituirlo sys.stdout con esso, non una funzione:

    log = open("myprog.log", "a") 
    sys.stdout = log 
    
    >>> print("Hello") 
    >>> # nothing is printed because it goes to the log file instead. 
    
  2. Sostituire di stampa con la funzione di registro:

    # If you're using python 2.x, uncomment the next line 
    #from __future__ import print_function 
    print = log.info 
    
    >>> print("Hello!") 
    >>> # nothing is printed because log.info is called instead of print 
    
+0

Nel primo esempio, è possibile avere entrambi, nel file di e sullo schermo stdout? –

1

Per un metodo che funziona con 2.x see here:

Citando

"La seconda tecnica è venuto alla mia attenzione quando ho riletto Learning Python per la seconda volta. Coinvolge riorientare l'istruzione print direttamente come segue:.

print >>output, "wello horld" 

in cui l'uscita è un oggetto scrivibile"

+2

Sebbene questo collegamento possa rispondere alla domanda, è meglio includere qui le parti essenziali della risposta e fornire il link per riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia. –

+1

@david notato, aggiunto estratto – tacaswell

2

si dovrebbe davvero fare il contrario: regolando la configurazione di registrazione per utilizzare print dichiarazioni o qualcosa del genere altrimenti, a seconda delle impostazioni, non sovrascrivere il comportamento di print, poiché alcune delle impostazioni che potrebbero essere introdotte in futuro (ad esempio da te o da qualcun altro che usa il modulo) potrebbero effettivamente inviarlo allo stdout e si avranno problemi

C'è un handl er che dovrebbe reindirizzare i tuoi messaggi di registro al flusso corretto (file, stdout o qualsiasi altra cosa simile ai file). Si chiama StreamHandler ed è in bundle con il modulo logging.

Quindi, in pratica secondo me dovresti fare, quello che hai dichiarato che non vuoi fare: sostituire le dichiarazioni print con la registrazione effettiva.

+0

Userò la registrazione per gli script futuri, ma per lo scopo di ciò che sto facendo non vale la pena di aggiornare tutto per il logger. Cercherò comunque su StreamHandler. – Rauffle

+0

@Rauffle: come desideri. Suggerisco caldamente di utilizzare la seconda soluzione menzionata da C0deH4cker, altrimenti potresti avere problemi che ho menzionato nella mia risposta. – Tadeck

6

Naturalmente, è possibile sia stampare sullo standard output e aggiungere un file di log, in questo modo:

# Uncomment the line below for python 2.x 
#from __future__ import print_function 

import logging 

logging.basicConfig(level=logging.INFO, format='%(message)s') 
logger = logging.getLogger() 
logger.addHandler(logging.FileHandler('test.log', 'a')) 
print = logger.info 

print('yo!') 
5

Un altro metodo è quello di avvolgere il registratore in un oggetto che traduce le chiamate a write al logger log metodo.

Ferry Boender fa proprio questo, provided under the GPL license in a post il his website:

import logging 
import sys 

class StreamToLogger(object): 
    """ 
    Fake file-like stream object that redirects writes to a logger instance. 
    """ 
    def __init__(self, logger, log_level=logging.INFO): 
     self.logger = logger 
     self.log_level = log_level 
     self.linebuf = '' 

    def write(self, buf): 
     for line in buf.rstrip().splitlines(): 
     self.logger.log(self.log_level, line.rstrip()) 

logging.basicConfig(
    level=logging.DEBUG, 
    format='%(asctime)s:%(levelname)s:%(name)s:%(message)s', 
    filename="out.log", 
    filemode='a' 
) 

stdout_logger = logging.getLogger('STDOUT') 
sl = StreamToLogger(stdout_logger, logging.INFO) 
sys.stdout = sl 

stderr_logger = logging.getLogger('STDERR') 
sl = StreamToLogger(stderr_logger, logging.ERROR) 
sys.stderr = sl 

Questo vi permette di indirizzare facilmente tutto l'output a un registratore di vostra scelta. Se necessario, è possibile salvare sys.stdout e/o sys.stderr come indicato da altri in questa discussione prima di sostituirlo se è necessario ripristinarlo in un secondo momento.

0

Un'opzione molto più semplice,

import logging, sys 
logging.basicConfig(filename='path/to/logfile', level=logging.DEBUG) 
logger = logging.getLogger() 
sys.stderr.write = lambda s: logger.error(s) 
sys.stdout.write = lambda s: logger.info(s) 
+2

Questa soluzione funziona solo se non si utilizza logging.StreamHandler() per stampare anche il registro sullo schermo. Perché se lo fai, mandi il messaggio in un ciclo infinito: il gestore del flusso prova a scriverlo su sys.stdout.write, dove viene reindirizzato al logger e poi di nuovo al gestore del flusso. – Decrayer