3

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.

2
  • You need to replace sys.stdout with your own wrapper which log everything written there and passthrough to original sys.stdout. Commented Aug 2, 2017 at 1:42
  • @MaksymMarkov Yes I think that is the real solution, it's kind of what I was getting at with the code snippet in my question. Though I was hoping something like this was already written and matured or was already a built-in function of Python. Commented Aug 2, 2017 at 16:10

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.