2013-10-17 43 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') 
相关问题