2009-09-05 13 views

Respuesta

78

La siguiente secuencia de comandos, log1.py:

import logging, sys 

class SingleLevelFilter(logging.Filter): 
    def __init__(self, passlevel, reject): 
     self.passlevel = passlevel 
     self.reject = reject 

    def filter(self, record): 
     if self.reject: 
      return (record.levelno != self.passlevel) 
     else: 
      return (record.levelno == self.passlevel) 

h1 = logging.StreamHandler(sys.stdout) 
f1 = SingleLevelFilter(logging.INFO, False) 
h1.addFilter(f1) 
rootLogger = logging.getLogger() 
rootLogger.addHandler(h1) 
h2 = logging.StreamHandler(sys.stderr) 
f2 = SingleLevelFilter(logging.INFO, True) 
h2.addFilter(f2) 
rootLogger.addHandler(h2) 
logger = logging.getLogger("my.logger") 
logger.setLevel(logging.DEBUG) 
logger.debug("A DEBUG message") 
logger.info("An INFO message") 
logger.warning("A WARNING message") 
logger.error("An ERROR message") 
logger.critical("A CRITICAL message") 

cuando se ejecuta, produce los siguientes resultados.

 
C:\temp>log1.py 
A DEBUG message 
An INFO message 
A WARNING message 
An ERROR message 
A CRITICAL message 

Como era de esperar, ya que en un terminal sys.stdout y sys.stderr son los mismos. Ahora, vamos a redirigir la salida estándar a un archivo, tmp:

 
C:\temp>log1.py >tmp 
A DEBUG message 
A WARNING message 
An ERROR message 
A CRITICAL message 

Así que el mensaje INFO no se ha impreso al terminal - pero los mensajes dirigidos a sys.stderrse han impreso. Veamos lo que está en tmp:

 
C:\temp>type tmp 
An INFO message 

Así que el enfoque parece hacer lo que quiera.

+0

Gracias, eso es exactamente lo que necesito. Por cierto, eclipe resalta el std. – L1ker

+11

¡Una respuesta del propio autor! Neat-o! – twneale

11

En general, creo que tiene sentido para redirigir los mensajes inferiores a WARNING stdout, en lugar de sólo los mensajes INFO.

Basado en excelente respuesta Vinay Sajip 's, se me ocurrió esto:

class MaxLevelFilter(Filter): 
    '''Filters (lets through) all messages with level < LEVEL''' 
    def __init__(self, level): 
     self.level = level 

    def filter(self, record): 
     return record.levelno < self.level # "<" instead of "<=": since logger.setLevel is inclusive, this should be exclusive 


MIN_LEVEL= DEBUG 
#... 
stdout_hdlr = StreamHandler(sys.stdout) 
stderr_hdlr = StreamHandler(sys.stderr) 
lower_than_warning= MaxLevelFilter(WARNING) 
stdout_hdlr.addFilter(lower_than_warning)  #messages lower than WARNING go to stdout 
stdout_hdlr.setLevel(MIN_LEVEL) 
stderr_hdlr.setLevel(max(MIN_LEVEL, WARNING)) #messages >= WARNING (and >= STDOUT_LOG_LEVEL) go to stderr 
#... 
7

Desde mi edición fue rechazado, aquí está mi respuesta. La respuesta de @ goncalopp es buena, pero no está sola ni funciona de la caja. Aquí está mi versión mejorada:

import sys, logging 


class LogFilter(logging.Filter): 
    """Filters (lets through) all messages with level < LEVEL""" 
    # http://stackoverflow.com/a/24956305/408556 
    def __init__(self, level): 
     self.level = level 

    def filter(self, record): 
     # "<" instead of "<=": since logger.setLevel is inclusive, this should 
     # be exclusive 
     return record.levelno < self.level 

MIN_LEVEL = logging.DEBUG 
stdout_hdlr = logging.StreamHandler(sys.stdout) 
stderr_hdlr = logging.StreamHandler(sys.stderr) 
log_filter = LogFilter(logging.WARNING) 
stdout_hdlr.addFilter(log_filter) 
stdout_hdlr.setLevel(MIN_LEVEL) 
stderr_hdlr.setLevel(max(MIN_LEVEL, logging.WARNING)) 
# messages lower than WARNING go to stdout 
# messages >= WARNING (and >= STDOUT_LOG_LEVEL) go to stderr 

rootLogger = logging.getLogger() 
rootLogger.addHandler(stdout_hdlr) 
rootLogger.addHandler(stderr_hdlr) 
logger = logging.getLogger(__name__) 
logger.setLevel(logging.DEBUG) 

# Example Usage 
>>> logger.debug("A DEBUG message") 
>>> logger.info("An INFO message") 
>>> logger.warning("A WARNING message") 
>>> logger.error("An ERROR message") 
>>> logger.critical("A CRITICAL message") 
Cuestiones relacionadas