简体   繁体   English

如何在Python中异步记录stdout / stderr?

[英]How to asynchronously log stdout/stderr in Python?

I have a function (which I cannot change) and it prints data to stdout/stderr. 我有一个函数(无法更改),它将数据输出到stdout / stderr。 I need to log the output of this function. 我需要记录此函数的输出。 My first idea was to replace sys.stdout with a buffer in the form of StringIO() and then process its contents. 我的第一个想法是用StringIO()形式的缓冲区替换sys.stdout ,然后处理其内容。 That worked well, but the problem is, when the function fails, it prints the error message and exits the current process . 效果很好,但是问题是,当函数失败时,它会打印错误消息并退出当前进程 In that case, contents of the buffer are lost, because my code after function call is never executed. 在那种情况下,缓冲区的内容会丢失,因为函数调用后的代码永远不会执行。

So my idea was to somehow watch the buffer asynchronously and process its contents immediatelly when there are data to be read. 因此,我的想法是以某种方式异步监视缓冲区,并在有待读取的数据时立即处理缓冲区的内容。 I tried a solution with asyncio and its add_reader method, but that seems to not support StringIO() and not even a regular file. 我尝试了asyncio及其add_reader方法的解决方案,但似乎不支持StringIO()甚至不支持常规文件。

This is my first try to just asynchronously print the stdout: 这是我第一次异步打印标准输出的尝试:

import asyncio
import sys
from io import StringIO

async def f():
    print('Some output')

def logger(buffer):
    sys.__stdout__.write(buffer.read())

buffer = StringIO()
sys.stdout = buffer

loop = asyncio.get_event_loop()
loop.add_reader(buffer, logger, buffer)
loop.run_until_complete(f())

That fails with 失败与

ValueError: Invalid file object: <_io.StringIO object at 0x7f8a93e9aa68>

Is there any solution to this problem? 有什么解决办法吗? At least I need to clarify if my approach makes sense. 至少我需要澄清我的方法是否有意义。

UPDATE: I have discovered standard module atexit , which can call a function upon interpreter exit. 更新:我发现了标准模块atexit ,可以在解释器退出时调用一个函数。 This is another way to solve my problem. 这是解决我的问题的另一种方法。

You can create a custom subclass of io.TextIOBase and replace sys.stdout with an instance of your custom class. 您可以创建io.TextIOBase的自定义子类,并将sys.stdout替换为自定义类的实例。 The write() method of your class will be called whenever output is sent to sys.stdout . 每当将输出发送到sys.stdout时,将调用您类的write()方法。 Optionally you can forward all output to the original stdout: (可选)您可以将所有输出转发到原始标准输出:

class MyStdOut(io.TextIOBase):
    def __init__(self, orig_stdout=None):
        self.orig_stdout = orig_stdout
    def write(self, s):
        # Process output in whatever way you like
        process(s)
        # Write output to original stream, if desired
        if self.orig_stdout:
            self.orig_stdout.write(s)

sys.stdout = MyStdOut(sys.stdout)

This aproach wil be completely synchronous – no threads or asynchronous I/O needed. 此方法将完全同步–不需要线程或异步I / O。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM