2009-09-05 13 views

Odpowiedz

78

Poniższy skrypt, 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") 

podczas uruchamiania, produkuje następujące rezultaty.

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

Jak można się spodziewać, ponieważ na terminalu sys.stdout i sys.stderr są takie same. A teraz przekierować stdout do pliku, tmp:

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

Więc komunikat INFO nie został wydrukowany na terminal - ale komunikaty skierowane do sys.stderrmają zostały wydrukowane. Spójrzmy na to, co znajduje się w tmp:

 
C:\temp>type tmp 
An INFO message 

Więc to podejście wydaje się robić to, co chcesz.

+0

Dziękuję, to jest dokładnie to, czego potrzebuję. Przy okazji eclipe podkreślają std. – L1ker

+11

Odpowiedź od samego autora! Neat-o! – twneale

11

Generalnie myślę, że to ma sens przekierować wiadomości niższe niż WARNING do stdout, zamiast tylko INFO wiadomości.

podstawie doskonałą odpowiedź Vinay Sajip „s, wpadłem na to:

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

Ponieważ moja edycja została odrzucona, oto moja odpowiedź. Odpowiedź @ goncalopp jest dobra, ale nie działa samodzielnie lub nie działa. Oto moja ulepszona wersja:

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")