How to log everything that occurs in a Python interactive shell session?
Question: I'd like to have real-time access to both interpreter input and error and
standard output. Preferably this information would be written to a file, so
that I can poll the file for changes after every interpreter command has been
entered. For example, given an interpreter session:

    
    
    >>> 5 * 7
    35
    >>> print("Hello, world!")
    Hello, world!
    >>> "Hello, world!"
    'Hello, world!'
    

I'd like to see the following in a log file:

    
    
    > 5 * 7
    35
    > print("Hello, world!")
    Hello, world!
    > "Hello, world!"
    'Hello, world!'
    

The formatting is not important; what is important is that I can search the
file for key words to trigger interactive events during the session.

What I have learned so far trying to accomplish this:

Python's `code` module allows me to create an `InteractiveConsole` object, the
`raw_input` method of which I can redefine to log to a file, like so:

    
    
    import code
    class LoggedConsole(code.InteractiveConsole):
      def __init__(self, locals):
        super(LoggedConsole, self).__init__(locals)
        self.file = open('consolelog.dat', 'a')
    
      def __del__(self):
        self.file.close()
    
      def raw_input(self, prompt=""):
        data = input(prompt)
        self.file.write(data+'\n')
        return data
    

Furthermore, `InteractiveConsole` uses a built-in `write` method to log
errors, which I can redefine to:

    
    
    def write(self, data):
      sys.stderr.write(data)
      self.file.write(data+'\n')
    

I've also learned that the following snippet will log all stdout:

    
    
    class Tee(object):
      def __init__(self):
        self.file = open('consolelog.dat', 'a')
        self.stdout = sys.stdout
    
      def __del__(self):
        sys.stdout = self.stdout
        self.file.close()
    
      def write(self, data):
        self.file.write(data)
        self.stdout.write(data)
    
    sys.stdout = Tee()
    

My (broken) attempt to bring this all together was to then create a
`LoggedConsole` object, and pass it `Tee` in locals.

    
    
    console = LoggedConsole(locals={sys.stdout:LoggedExec()})
    console.interact()
    

(I've not passed locals before, so perhaps I'm doing it incorrectly here, but
I don't receive an error.)

Anyways, this will open a new Interactive Console, and will log (after
closing) all input and errors, but not output. I've been banging my head
against this for a while, and I feel like I'm close, but maybe not even.

Also, is there a way for all of this to occur _during_ the session? Currently
all logging takes place once the session is closed.

Thanks for your time, sorry for the wall of text.

edit: I'd like to be able to accomplish this in the standard Python
interpreter for portability purposes.

edit2: Jaime's snippet works very well for logging everything I need. Any way,
though, that I can have it do so in real time, instead of waiting for the
session to close?

edit3: **Figured it out :). The final, working snippet:**

    
    
    import code
    import sys
    
    class Tee(object):
      def __init__(self, log_fname, mode='a'):
        self.log = open(log_fname, mode)
    
      def __del__(self):
        # Restore sin, so, se
        sys.stdout = sys.__stdout__
        sys.stdir = sys.__stdin__
        sys.stderr = sys.__stderr__
        self.log.close()
    
      def write(self, data):
        self.log.write(data)
        self.log.flush()
        sys.__stdout__.write(data)
        sys.__stdout__.flush()
    
      def readline(self):
        s = sys.__stdin__.readline()
        sys.__stdin__.flush()
        self.log.write(s)
        self.log.flush()
        return s
    
      def flush(foo):
        return
    
    sys.stdout = sys.stderr = sys.stdin = Tee('consolelog.dat', 'w')
    
    console = code.InteractiveConsole()
    console.interact()
    


Answer: I've only tested this in python2.7. I don't have 3 handy.

    
    
    import code
    import sys
    
    class Tee(object):
    
      def __init__(self, log_fname, mode='a'):
        self.log = open(log_fname, mode)
    
      def __del__(self):
        # Restore sin, so, se
        sys.stdout = sys.__stdout__
        sys.stdir = sys.__stdin__
        sys.stderr = sys.__stderr__
        self.log.close()
    
      def write(self, data):
        self.log.write(data)
        sys.__stdout__.write(data)
    
      def readline(self):
        s = sys.__stdin__.readline()
        self.log.write(s)
        return s
    
    # Tie the ins and outs to Tee.
    sys.stdout = sys.stderr = sys.stdin = Tee('consolelog.dat', 'w')
    
    console = code.InteractiveConsole()
    console.interact()
    

