I have a function (which I cannot change) and it prints data to 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. 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.
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. This is another way to solve my problem.