Reputation: 7148
I would like to capture the console output at the end of a Python script. That is, I want to both print to console as normal and, at the end of execution, save the console output to a file.
I have seen various related SO questions 1, 2, 3 though they either simply redirect the output and not display it or use logging
. From what I can tell from reading the logging
doc you can only log output from the code you've written.
The issue with all the links above is console output from code you have not written that also prints to console. I want the entire console output of the program at the end of execution.
My first instinct was something along the lines of
logFile = open('LogFile.txt', 'w')
def print_log(msg):
print(msg)
logFile.write(msg)
print_log('Hello World!')
logFile.close()
But this would still fail to capture console output from other code and libraries in use. Is there a way to save a python script's console output at the end of execution? I feel like there should be a simple way to do this but all my research has led to no appropriate solution.
Upvotes: 3
Views: 996
Reputation: 1970
I've used this one in one of my projects:
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
Basically it does exactly what Maksym Markov said in the comment with one difference. I usually don't wanna stall any outputs so I've written this Tee
which capture all text going on stdout (or stderr) immediately prints it and save into the buffer for later usage. It also take care about "fixing" the sys.stdout
when the code exits the with
block.
The example of usage:
if __name__ == "__main__":
with Tee() as tee:
print("Hello World!")
print(tee.read())
There are some drawbacks like without additional code you can't use tee.read()
inside the with block. But in my case I always need process the output of the whole block.
Upvotes: 1