5

I want to log the std output of a chunk of Python code to a file, using the 'with' statement:

with log_to_file('log'):
    # execute code

Is the easiest way to do this to define the log_to_file manually, e.g.:

import sys

class log_to_file():
    def __init__(self, filename):
        self.f = open(filename, 'wb')

    def __enter__(self):
        self.stdout = sys.stdout
        self.stderr = sys.stderr
        sys.stdout = self.f
        sys.stderr = self.f

    def __exit__(self, type, value, traceback):
        sys.stdout = self.stdout
        sys.stderr = self.stderr

or is there a built-in class that can do this already?

astrofrog
  • 32,883
  • 32
  • 90
  • 131
  • Take a look at [this](http://stackoverflow.com/questions/616645/how-do-i-duplicate-sys-stdout-to-a-log-file-in-python) question. It seems like what you're looking for. Note one of the answers uses the existing logging module, while others use multiprocessing. – thegrinner Dec 07 '11 at 16:44
  • 1
    Your approach is nice, even if you miss to close the file on `__exit__` :) I like it. – tito Dec 07 '11 at 16:53
  • 1
    What kind of answer do you expect? I will give it as a comment: No, there is no built-in class that does that. – Ferdinand Beyer Dec 07 '11 at 17:08
  • Neat. On similar lines, an `AssertPrints` context manager for testing: https://github.com/ipython/ipython/blob/master/IPython/testing/tools.py#L342 – Thomas K Dec 07 '11 at 17:16

1 Answers1

2

The only thing I could suggest is to use the contextmanager decorator but I'm not convinced this is really better.

from contextlib import contextmanager
@contextmanager
def stdouterrlog(logfile):
  with open(logfile, 'wb') as lf:
    stdout = sys.stdout
    stderr = sys.stderr
    sys.stdout = lf
    sys.stderr = lf
    yield lf  # support 'with stdouterrlog(x) as logfile'
    sys.stdout = stdout
    sys.stderr = stderr
wberry
  • 18,519
  • 8
  • 53
  • 85
  • Why not use the context manager inherent to `file` objects? That is, have the body of `stdouterrlog` be `with open(logfile, 'wb') as logfile: \n (do sys.stdout stuff...) \n yield logfile` \n (undo sys.stdout stuff...) – detly Dec 16 '11 at 02:03
  • Yeah, that would save one additional line. – wberry Dec 16 '11 at 15:53
  • 1
    ...except that you should probably also have the whole thing wrapped in a `try`/`finally` block too, otherwise an unhandled error will leave the log file open. – detly Dec 16 '11 at 17:20