title: How to log everything that occurs in a Python interactive shell session?
body: <p>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:</p>
  
  <pre><code>&gt;&gt;&gt; 5 * 7
  35
  &gt;&gt;&gt; print("Hello, world!")
  Hello, world!
  &gt;&gt;&gt; "Hello, world!"
  'Hello, world!'
  </code></pre>
  
  <p>I'd like to see the following in a log file:</p>
  
  <pre><code>&gt; 5 * 7
  35
  &gt; print("Hello, world!")
  Hello, world!
  &gt; "Hello, world!"
  'Hello, world!'
  </code></pre>
  
  <p>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.</p>
  
  <p>What I have learned so far trying to accomplish this:</p>
  
  <p>Python's <code>code</code> module allows me to create an <code>InteractiveConsole</code> object, the <code>raw_input</code> method of which I can redefine to log to a file, like so:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>Furthermore, <code>InteractiveConsole</code> uses a built-in <code>write</code> method to log errors, which I can redefine to:</p>
  
  <pre><code>def write(self, data):
    sys.stderr.write(data)
    self.file.write(data+'\n')
  </code></pre>
  
  <p>I've also learned that the following snippet will log all stdout:</p>
  
  <pre><code>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()
  </code></pre>
  
  <p>My (broken) attempt to bring this all together was to then create a <code>LoggedConsole</code> object, and pass it <code>Tee</code> in locals.</p>
  
  <pre><code>console = LoggedConsole(locals={sys.stdout:LoggedExec()})
  console.interact()
  </code></pre>
  
  <p>(I've not passed locals before, so perhaps I'm doing it incorrectly here, but I don't receive an error.)</p>
  
  <p>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.</p>
  
  <p>Also, is there a way for all of this to occur <em>during</em> the session? Currently all logging takes place once the session is closed.</p>
  
  <p>Thanks for your time, sorry for the wall of text.</p>
  
  <p>edit:
  I'd like to be able to accomplish this in the standard Python interpreter for portability purposes.</p>
  
  <p>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?</p>
  
  <p>edit3:
  <strong>Figured it out :). The final, working snippet:</strong></p>
  
  <pre><code>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()
  </code></pre>