代码之家  ›  专栏  ›  技术社区  ›  Cloud

将所有stdout/stderr全局重定向到记录器

  •  4
  • Cloud  · 技术社区  · 7 年前

    出身背景

    我有一个非常大的python应用程序,它启动命令行实用程序来获取所需的数据片段。目前,我只是将python启动程序脚本重定向到一个日志文件,该文件为我提供了 print() 输出,加上命令行实用程序的输出,即:

    python -m launcher.py &> /root/out.log
    

    问题

    I've since implemented a proper logger via logging , which lets me format the logging statements more precisely, lets me limit log file size, etc. 我已经换掉了大部分 打印() 对我的记录器进行调用的语句。然而,我有一个问题:命令行应用程序的输出都没有出现在我的日志中。相反,它会被转储到控制台。此外,这些项目的启动方式也不尽相同:有些是通过 popen() ,部分由 exec() ,部分由 os.system()


    问题

    是否有方法全局重定向所有 stdout / stderr 文本到我的日志功能,而不必重写/修改启动这些命令行工具的代码?我尝试设置以下内容,我在另一个问题中发现:

    sys.stderr.write = lambda s: logger.error(s)
    

    然而,它失败于“ sys.stderr.write 是只读的”。

    2 回复  |  直到 4 年前
        1
  •  1
  •   Edwin van Mierlo    7 年前

    虽然这不是一个完整的答案,但它可能会显示一个重定向,以适应您的特定情况。不久前我就是这样做的。虽然我不记得我为什么这样做,或者我试图规避的限制是什么,但下面是重定向 stdout stderr 到一个班级 print() 声明。该类随后写入屏幕和文件:

    import os
    import sys
    import datetime
    
    class DebugLogger():
    
        def __init__(self, filename):
            timestamp = datetime.datetime.strftime(datetime.datetime.utcnow(), 
                                                   '%Y-%m-%d-%H-%M-%S-%f')
            #build up full path to filename
            logfile = os.path.join(os.path.dirname(sys.executable), 
                                   filename + timestamp)
            self.terminal = sys.stdout
            self.log = open(logfile, 'a')
    
        def write(self, message):
            timestamp = datetime.datetime.strftime(datetime.datetime.utcnow(), 
                                                   ' %Y-%m-%d-%H:%M:%S.%f')
            #write to screen
            self.terminal.write(message)
            #write to file
            self.log.write(timestamp + ' - ' + message)      
            self.flush()
    
        def flush(self):
            self.terminal.flush()
            self.log.flush()
            os.fsync(self.log.fileno())
    
        def close(self):
            self.log.close()
    
    
    def main(debug = False):
        if debug:
            filename = 'blabla'
            sys.stdout = DebugLogger(filename)
            sys.stderr = sys.stdout
        print('test')
    
    if __name__ == '__main__':
        main(debug = True)
    
        2
  •  1
  •   Aaron    7 年前
    import sys
    import io
    
    class MyStream(io.IOBase):
        def write(self, s):
            logger.error(s)
    
    sys.stderr = MyStream()
    
    print('This is an error', stream=sys.stderr)
    

    这是对 sys.stderr 转到记录器。 原来的那个总是在 sys.__stderr__