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

在仍打印到stdout时将stdout重定向到日志文件?

  •  3
  • KDecker  · 技术社区  · 7 年前

    1 , 2 3 尽管它们要么只是重定向输出,而不是显示或使用 logging .从阅读 登录中 doc

    上面所有链接的问题都是您尚未编写的代码的控制台输出,这些代码也会打印到控制台。 我希望在执行结束时获得程序的整个控制台输出

    我的第一直觉是

    logFile = open('LogFile.txt', 'w')
    def print_log(msg):
        print(msg)
        logFile.write(msg)
    
    print_log('Hello World!')
    
    logFile.close()
    

    但这仍然无法从正在使用的其他代码和库中捕获控制台输出。 有没有办法在执行结束时保存python脚本的控制台输出?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Qeek    7 年前

    import io
    import sys
    from enum import Enum
    
    
    class Tee(io.StringIO):
        class Source(Enum):
            STDOUT = 1
            STDERR = 2
    
        def __init__(self, clone=Source.STDOUT, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
            self._clone = clone
    
            if clone == Tee.Source.STDOUT:
                self._out = sys.stdout
            elif clone == Tee.Source.STDERR:
                self._out = sys.stderr
            else:
                raise ValueError("Clone has to be STDOUT or STDERR.")
    
        def write(self, *args, **kwargs):
            self._out.write(*args, **kwargs)
            return super().write(*args, **kwargs)
    
        def __enter__(self):
            if self._clone == Tee.Source.STDOUT:
                sys.stdout = self
            else:
                sys.stderr = self
            self.seek(io.SEEK_END)
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            if self._clone == Tee.Source.STDOUT:
                sys.stdout = self._out
            else:
                sys.stderr = self._out
            self.seek(0)
            return False
    

    基本上,它与马克西姆·马尔可夫在评论中所说的完全相同,但有一点不同。我通常不想暂停任何输出,所以我写了这个 Tee 它捕获所有在stdout(或stderr)上运行的文本,立即将其打印并保存到缓冲区中供以后使用。它还负责“修复” sys.stdout with

    用法示例:

    if __name__ == "__main__":
        with Tee() as tee:
            print("Hello World!")
    
        print(tee.read())
    

    有一些缺点,比如没有额外的代码,你就不能使用 tee.read() with区块内。但在我的例子中,我总是需要处理整个块的输出。