I'm trying to find out a way in python to redirect the script execution log to a file as well as stdout
in a pythonic way. Is there any easy way of achieving this?

- 119,623
- 25
- 170
- 301

- 1,501
- 3
- 18
- 27
-
Well, what have you got so far? – Joel Cornett Jul 04 '12 at 08:15
-
4on the linux console this is `script | tee logfilename` – Karoly Horvath Jul 04 '12 at 08:16
-
Did you mean something like that? [Python output buffering][1] [1]: http://stackoverflow.com/questions/107705/python-output-buffering – user1065951 Jul 04 '12 at 08:16
-
1Use python logging library!!! its my favorite lib in python :D. – aisbaa Jul 04 '12 at 08:37
8 Answers
Use logging module (http://docs.python.org/library/logging.html):
import logging
logger = logging.getLogger('scope.name')
file_log_handler = logging.FileHandler('logfile.log')
logger.addHandler(file_log_handler)
stderr_log_handler = logging.StreamHandler()
logger.addHandler(stderr_log_handler)
# nice output format
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_log_handler.setFormatter(formatter)
stderr_log_handler.setFormatter(formatter)
logger.info('Info message')
logger.error('Error message')

- 828
- 1
- 8
- 13
I came up with this [untested]
import sys
class Tee(object):
def __init__(self, *files):
self.files = files
def write(self, obj):
for f in self.files:
f.write(obj)
f.flush() # If you want the output to be visible immediately
def flush(self) :
for f in self.files:
f.flush()
f = open('out.txt', 'w')
original = sys.stdout
sys.stdout = Tee(sys.stdout, f)
print "test" # This will go to stdout and the file out.txt
#use the original
sys.stdout = original
print "This won't appear on file" # Only on stdout
f.close()
print>>xyz
in python will expect a write()
function in xyz
. You could use your own custom object which has this. Or else, you could also have sys.stdout refer to your object, in which case it will be tee-ed even without >>xyz
.

- 334
- 2
- 11

- 43,308
- 12
- 81
- 104
-
Awesome. This works the way I expected.. since i'm new to programming, trying to understand a bit.. how is the class Tee is called when using the command Tee(sys.stdout,f) as the class def involves only an object (could be a file object) ? please advice – user596922 Jul 04 '12 at 14:02
-
If you are asking how exactly is `write` invoked.. `print` operations end up as `sys.stdout.write(..)`. Making `sys.stdout` point to an object that has `.write(..)` defined would just fine. – UltraInstinct Jul 04 '12 at 14:28
-
@Thrustmaster My simpler, but more versatile implementation is http://pastebin.com/7V4AmrUe. Only difference is that you need to pass in a sequence to the constructor, rather than relying on argument packing, but once it's done, you get easy, and intuitive, access to the tee'd streams. – RoadieRich Jun 28 '13 at 13:11
-
please take a look at the standard logging facility in Python 2.7.5 > http://docs.python.org/2/library/logging.html – Chris Jul 31 '13 at 12:30
-
1I find this especially helpful for writing quick LaTeX generators. @Thrustmaster I made another small modification, posted a [Gist](https://gist.github.com/eacousineau/10427097). Thank you for posting this! – eacousineau Apr 10 '14 at 21:56
-
Useful ! But you may need a flush method in Tee definition ` def flush(self): for f in self.files: f.flush() ` – Covich Jun 12 '15 at 16:06
-
1This works great, except when using subprocess. In my main function I do this, then call a function outside main, which calls subprocess, and the output from the subprocess is not written to the file (though it is written to stdout, as normal) – Eliezer Miron Jun 30 '16 at 17:18
-
You should really support all of the methods users would expect to be able to use on sys.stderr or sys.stdout. For example, don't forget to support isatty(). – Jim Sep 08 '16 at 23:55
-
1Couldn't you restore `sys.stdout` with `sys.__stdout__` instead of saving it out to a variable? – Erik Anderson Apr 20 '17 at 21:41
-
1At the `f.close()` instruction, in the end of my script, I get the following error: `Exception ignored in: <__main__.Tee object at 0x7f715e77e760> Traceback (most recent call last): File "constellation_test.py", line 40, in flush f.flush() ValueError: I/O operation on closed file.` Why? – Alfredo Capobianchi Jan 03 '22 at 15:38
-
@RoadieRich would give an example on how to use your solution? Thanks – Alfredo Capobianchi Jan 03 '22 at 15:48
I just want to build upon Serpens answer and add the line:
logger.setLevel('DEBUG')
This will allow you to chose what level of message gets logged.
For example in Serpens example,
logger.info('Info message')
Will not get recorded as it defaults to only recording Warnings and above.
More about levels used can be read about here

- 185
- 1
- 9
Probably the shortest solution:
def printLog(*args, **kwargs):
print(*args, **kwargs)
with open('output.out','a') as file:
print(*args, **kwargs, file=file)
printLog('hello world')
Writes 'hello world' to sys.stdout
and to output.out
and works exactly the same way as print().
Note:
Please do not specify the file argument for the printLog function. Calls like printLog('test',file='output2.out')
are not supported.

- 9,341
- 4
- 63
- 58
-
is there any performance drawbacks? i mean open/close file repeatedly? – Lei Yang Jun 07 '19 at 00:00
-
depends on your use case. if you put `printLog` into an often repeated loop this will have strong impact on performance. But putting `print` there is not a good idea, either! What might be an idea is to add some buffer an just write 100 lines at once in the log file. This somehow might be against the idea of your logger – Markus Dutschke Jun 07 '19 at 07:36
-
To specify the filename, just wrap `printLog` with another function that takes a filename: `def print_log(msg, filename):` and inside it define your `printLog` (can name it `_print_log` to indicate privacy), and inside `print_log`, call `_print_log(msg)`. This way your inner function also have access to the `filename` parameter from the outer `print_log` function. So it can use it instead of `output.out`. – Alaa M. Feb 24 '21 at 14:26
Here's a small improvement that to @UltraInstinct's Tee class, modified to be a context manager and also captures any exceptions.
import traceback
import sys
# Context manager that copies stdout and any exceptions to a log file
class Tee(object):
def __init__(self, filename):
self.file = open(filename, 'w')
self.stdout = sys.stdout
def __enter__(self):
sys.stdout = self
def __exit__(self, exc_type, exc_value, tb):
sys.stdout = self.stdout
if exc_type is not None:
self.file.write(traceback.format_exc())
self.file.close()
def write(self, data):
self.file.write(data)
self.stdout.write(data)
def flush(self):
self.file.flush()
self.stdout.flush()
To use the context manager:
print("Print")
with Tee('test.txt'):
print("Print+Write")
raise Exception("Test")
print("Print")

- 426
- 5
- 14
You should use the logging
library, which has this capability built in. You simply add handlers to a logger to determine where to send the output.

- 588,541
- 66
- 880
- 895
The easiest solution is to redirect the standard output. In your python program file use the following:
if __name__ == "__main__":
sys.stdout = open('file.log', 'w')
#sys.stdout = open('/dev/null', 'w')
main()
Any std output (e.g. the output of print 'hi there'
) will be redirected to file.log
or if you uncomment the second line, any output will just be suppressed.

- 437
- 3
- 14
-
12This directs the output only to a file.. I want the logs to be displayed both to the file and to the console... – user596922 Jul 04 '12 at 13:50
Create an output file and custom function:
outputFile = open('outputfile.log', 'w')
def printing(text):
print(text)
if outputFile:
outputFile.write(str(text))
Then instead of print(text) in your code, call printing function.
printing("START")
printing(datetime.datetime.now())
printing("COMPLETE")
printing(datetime.datetime.now())

- 616
- 1
- 8
- 17