2012-06-20 23 views
19

Tengo un script de Python que hace uso de 'Imprimir' para imprimir en stdout. Recientemente agregué el registro a través de Python Logger y me gustaría hacerlo para que estas declaraciones de impresión vayan al registrador si el registro está habilitado. No quiero modificar o eliminar estas declaraciones de impresión.Redirigir la salida de Python 'print' a Logger

Puedo iniciar sesión haciendo 'log.info ("some info msg")'. Quiero ser capaz de hacer algo como esto:

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

Si está habilitado el registro, "prueba" debe iniciar sesión como si lo hiciera log.info ("test"). Si el registro no está habilitado, la "prueba" debería simplemente imprimirse en la pantalla.

¿Esto es posible? Sé que puedo dirigir la salida estándar a un archivo de una manera similar (ver: redirect prints to log file)

Respuesta

15

Usted tiene dos opciones:

  1. Abrir un archivo de registro y reemplazar sys.stdout con él, no una función:

    log = open("myprog.log", "a") 
    sys.stdout = log 
    
    >>> print("Hello") 
    >>> # nothing is printed because it goes to the log file instead. 
    
  2. Reemplazar impresión con su función de 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

En el primer ejemplo, es posible tener tanto, en el expediente y en la salida estándar de la pantalla? –

1

Para un método que funciona con 2.x see here:

Citando

"La segunda técnica me llamó la atención cuando vuelvo a leer Learning Python por segunda vez. Se trata de la reorientación de la declaración de impresión directa de la siguiente manera:.

print >>output, "wello horld" 

en que la producción es un objeto puede escribir"

+2

Si bien este enlace puede responder a la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace de referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. –

+1

@david señaló, extracto agregado – tacaswell

2

que realmente debería hacerlo a la inversa: mediante el ajuste de la configuración de registro que puede utilizar print declaraciones o algo De lo contrario, según la configuración. No sobrescriba el comportamiento de print, ya que algunas de las configuraciones que se pueden introducir en el futuro (por ejemplo, usted o alguien que use su módulo) pueden realmente enviarlo al stdout y tendrá problemas

Hay un manojo er que se supone que debe redirigir sus mensajes de registro a la transmisión correcta (archivo, stdout o cualquier otro archivo similar). Se llama StreamHandler y se incluye con el módulo logging.

Por lo tanto, básicamente, en mi opinión, debe hacer, lo que indicó que no desea hacer: reemplazar las declaraciones print con el registro real.

+0

Utilizaré el registro para futuros guiones, pero para el propósito de lo que estoy haciendo no vale la pena el tiempo para actualizar todo para el registrador. Aunque miraré a StreamHandler. – Rauffle

+0

@Rauffle: como lo desee. Sugiero usar la segunda solución mencionada por C0deH4cker, de lo contrario, puede que tenga problemas que mencioné en mi respuesta. – Tadeck

6

Por supuesto, ambos pueden imprimir en la salida estándar y añadir a un archivo de registro, así:

# 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 método más es envolver el registrador en un objeto que se traduce llamadas a write a la método log del registrador.

Ferry Boender hace precisamente esto, provided under the GPL license en a post en 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 

Esto le permite facilidad para enviar toda la salida a un registrador de su elección. Si es necesario, puede guardar sys.stdout y/o sys.stderr como lo mencionaron otros en este hilo antes de reemplazarlo si necesita restaurarlo más tarde.

0

Una opción mucho más simple,

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

Esta solución solo funciona si no utiliza logging.StreamHandler() para imprimir también el registro en su pantalla. Porque si lo hace, envía el mensaje en un bucle infinito: el controlador de flujo intenta escribirlo en sys.stdout.write, donde se lo redirige al registrador y luego nuevamente al controlador de flujo. – Decrayer

Cuestiones relacionadas