12

I have a long python script that uses print statements often, I was wondering if it was possible to add some code that would log all of the print statements into a text file or something like that. I still want all of the print statements to go to the command line as the user gets prompted throughout the program. If possible logging the user's input would be beneficial as well.

I found this which somewhat answers my question but makes it where the "print" statement no longer prints to the command line

Redirect Python 'print' output to Logger

3
  • 1
    @Robᵩ ha ha ha Commented Jul 25, 2013 at 19:12
  • 1
    @Stephan - I don't think I'm funny. I'm trying to understand what OP actually wants from us. Commented Jul 25, 2013 at 19:14
  • @Robᵩ i think he's asking how make print "hi" go to two different places with 1 statement Commented Jul 25, 2013 at 19:15

5 Answers 5

19

You can add this to your script:

import sys
sys.stdout = open('logfile', 'w')

This will make the print statements write to logfile.

If you want the option of printing to stdout and a file, you can try this:

class Tee(object):
    def __init__(self, *files):
        self.files = files
    def write(self, obj):
        for f in self.files:
            f.write(obj)

f = open('logfile', 'w')
backup = sys.stdout
sys.stdout = Tee(sys.stdout, f)

print "hello world"  # this should appear in stdout and in file

To revert to just printing to console, just restore the "backup"

sys.stdout = backup
Sign up to request clarification or add additional context in comments.

Comments

10

Here is a program that does what you describe:

#! /usr/bin/python3

class Tee:
    def write(self, *args, **kwargs):
        self.out1.write(*args, **kwargs)
        self.out2.write(*args, **kwargs)
    def __init__(self, out1, out2):
        self.out1 = out1
        self.out2 = out2

import sys
sys.stdout = Tee(open("/tmp/log.txt", "w"), sys.stdout)

print("hello")

4 Comments

why did you both use a class, and why are they both called Tee?
I used a class because print will eventually invoke sys.stdout.write(). Since I am replacing sys.stdout, my replacement needs to have a .write(). I called it Tee after the unix tee program, which is itself named after the plumbing fixture of the same name.
Interesting. Did you also run my program standalone, without any of your code? Did it produce a non-empty /tmp/log.txt then?
@reddman - You might try adding self.out1.flush() and self.out2.flush() to Tee.write():.
5

When trying the best answer accepted on python 3.7 I had the following exception:

    Exception ignored in: <__main__.Logger object at 0x7f04083760f0>
    AttributeError: 'Logger' object has no attribute 'flush'

I added the following function to make it work:

    def flush(self):
        pass

Comments

3

If you use the built in logging module you can configure your loggers with as many outputs as you need: to file, to databases, to emails, etc. However it sounds like you're mixing print for two different uses: logging (recording program flow for later inspection) and prompts. The real work will be to split out those two uses of 'print' into different functions so you get what you need in each place.

A lot of people replace python's generic sys.stdout and sys.stderr to automatically do stuff to text which is being sent to the console. The real console output always lives in sys.__stdout__ and sys.__stderr__ (so you don't need to worry about somehow 'losing' it) but if you stick any object with the same methods as a file into the variables sys.stdout and sys.stderr you can do whatever you like with the output process.

Comments

-2

hm... is it hard to implement your own print() function and decorator that will log anything that is passed to your print function?

def logger(func):
    def inner(*args, **kwargs):
        log(*args, **kwargs)  # your logging logic
        return func(*args, **kwargs)
    return inner

@logger
def lprint(string_to_print):
    print(string_to_print)   

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.