2009-09-05 30 views

Trả lời

78

Các kịch bản sau đây, 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") 

khi chạy, tạo ra kết quả như sau.

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

Như bạn mong muốn, vì trên một thiết bị đầu cuối sys.stdoutsys.stderr đều giống nhau. Bây giờ, chúng ta hãy chuyển hướng stdout vào một tập tin, tmp:

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

Vì vậy, thông điệp INFO chưa được in vào thiết bị đầu cuối - nhưng những thông điệp hướng đến sys.stderrđã được in. Hãy xem những gì trong số tmp:

 
C:\temp>type tmp 
An INFO message 

Cách tiếp cận đó dường như làm những gì bạn muốn.

+0

Cảm ơn bạn, đó là chính xác những gì tôi cần. Bằng cách eclipe làm nổi bật của std. – L1ker

+11

Câu trả lời từ chính tác giả! Neat-o! – twneale

11

Nói chung, tôi nghĩ rằng nó làm cho tinh thần để chuyển hướng thông điệp thấp hơn WARNING để stdout, thay vì chỉ INFO điệp.

Dựa trên câu trả lời tuyệt vời Vinay Sajip 's, tôi đến với điều này:

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

Kể từ khi chỉnh sửa của tôi đã bị từ chối, đây là câu trả lời của tôi. @ goncalopp của câu trả lời là tốt nhưng không đứng một mình hoặc làm việc ra khỏi hộp. Đây là phiên bản cải tiến của tôi:

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") 
Các vấn đề liên quan