2013-10-17 98 views
17

我有一個記錄器,它有一個RotatingFileHandler。 我想將所有StdoutStderr重定向到記錄器。 如何做?如何將stdout和stderr重定向到Python中的記錄器

+0

你有寫文件描述符1和2的直接外部模塊/庫? –

+0

@ IgnacioVazquez-Abrams我真的不明白你的意思,但我會盡力解釋。我正在使用幾個python進程,並且從所有這些進程中,我想將所有'stdout'和'stderr'消息重定向到我的記錄器。 – orenma

+0

可能的重複[如何將sys.stdout複製到python中的日誌文件?](https://stackoverflow.com/questions/616645/how-do-i-duplicate-sys-stdout-to-a-log -python) – user

回答

8

如果它是一個全功能的Python系統(即沒有C庫寫入FDS直接作爲伊格納西奧巴斯克斯 - 艾布拉姆斯問),然後根據提示here你也許可以使用的方法:

class LoggerWriter: 
    def __init__(self, logger, level): 
     self.logger = logger 
     self.level = level 

    def write(self, message): 
     if message != '\n': 
      self.logger.log(self.level, message) 

和然後將sys.stdoutsys.stderr設置爲LoggerWriter實例。

+0

謝謝你,那是做的工作,但由於某種原因'stderr'發送它的消息每個單詞分開,你知道爲什麼嗎? – orenma

+0

@orenma大概是因爲寫逐字。您可以調整我的示例代碼以更貼近地滿足您的需求。 –

+0

如果重定向stderr後調用sys.stderr.flush()會怎麼樣? – Moberg

14

沒有足夠的評論意見,但我想添加這個工作的版本,以防其他人處於類似的情況。

class LoggerWriter: 
    def __init__(self, level): 
     # self.level is really like using log.debug(message) 
     # at least in my case 
     self.level = level 

    def write(self, message): 
     # if statement reduces the amount of newlines that are 
     # printed to the logger 
     if message != '\n': 
      self.level(message) 

    def flush(self): 
     # create a flush method so things can be flushed when 
     # the system wants to. Not sure if simply 'printing' 
     # sys.stderr is the correct way to do it, but it seemed 
     # to work properly for me. 
     self.level(sys.stderr) 

,這看起來是這樣的:

log = logging.getLogger('foobar') 
sys.stdout = LoggerWriter(log.debug) 
sys.stderr = LoggerWriter(log.warning) 
+0

由於flush方法,我得到一個奇怪的輸出:'警告archan_pylint:18:'。看來stderr對象被打印出來而不是換行符,否則,所以我只是刪除了flush方法,現在它似乎可以工作。 – Pawamoy

1

平齊加入維奈Sajip的回答是:

class LoggerWriter: 
    def __init__(self, logger, level): 
     self.logger = logger 
     self.level = level 

    def write(self, message): 
     if message != '\n': 
      self.logger.log(self.level, message) 

    def flush(self): 
     pass 
5

所有之前的答案似乎都增加了額外的換行符的問題,他們不需要。最適合我的解決方案是從http://www.electricmonk.nl/log/2011/08/14/redirect-stdout-and-stderr-to-a-logger-in-python/,在那裏他展示瞭如何stdout和標準錯誤發送到記錄器:

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 

print "Test to standard out" 
raise Exception('Test to standard error') 

輸出看起來像:

2011-08-14 14:46:20,573:INFO:STDOUT:Test to standard out 
2011-08-14 14:46:20,573:ERROR:STDERR:Traceback (most recent call last): 
2011-08-14 14:46:20,574:ERROR:STDERR: File "redirect.py", line 33, in 
2011-08-14 14:46:20,574:ERROR:STDERR:raise Exception('Test to standard error') 
2011-08-14 14:46:20,574:ERROR:STDERR:Exception 
2011-08-14 14:46:20,574:ERROR:STDERR:: 
2011-08-14 14:46:20,574:ERROR:STDERR:Test to standard error 

注意self.linebuf =' '是正在處理刷新的地方,而不是執行刷新功能。

+1

此代碼已獲得許可[GPL](https://www.electricmonk.nl/log/posting-license/)。我不確定它是否可以發佈到SO上,這需要與[CC by-sa](https://meta.stackexchange.com/help/licensing)兼容。 – asmeurer

2

您可以使用redirect_stdout情況管理器:

import logging 
from contextlib import redirect_stdout 

logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 
logging.write = lambda msg: logging.info(msg) if msg != '\n' else None 

with redirect_stdout(logging): 
    print('Test') 

或類似這樣的

import logging 
from contextlib import redirect_stdout 


logger = logging.getLogger('Meow') 
logger.setLevel(logging.INFO) 
formatter = logging.Formatter(
    fmt='[{name}] {asctime} {levelname}: {message}', 
    datefmt='%m/%d/%Y %H:%M:%S', 
    style='{' 
) 
ch = logging.StreamHandler() 
ch.setLevel(logging.INFO) 
ch.setFormatter(formatter) 
logger.addHandler(ch) 

logger.write = lambda msg: logger.info(msg) if msg != '\n' else None 

with redirect_stdout(logger): 
    print('Test') 
相關問題