#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2006
    Posts
    63
    Rep Power
    10

    How to redirect stdout and stderr to a file?


    I'd like to redirect stderr to a file so if a program crashes there's a text file record of it. I gather this involves subclassing stdout but I don't know how to do that.

    Anyone feel like steering me in the right direction?

    Thanks for any help.
  2. #2
  3. Commie Mutant Traitor
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Jun 2004
    Location
    Alpharetta, GA
    Posts
    1,806
    Rep Power
    1570
    Just as a matter of clarification: did you need to redirect stderr (send the output to file instead of to the terminal) or log it (duplicate the output into a file)? Also, does this need to redirect/log all error messages (including those from the interpreter) or only those from your own program?

    If all you needed was to have the program's error messages redirected to a file, and don't expect to need to set it back to the console, then it is straightforward: sys.stderr is a variable, and can in fact be reassigned to a different output stream. See here for details (section 10.10). Alternately, you can assign your own variable to stderr, using it instead of standard error for posting error messages, and then reassign it to a file as needed.

    For logging, you might want to look into the Logger class, which gives better structuring and control over error messages than writing directly to sys.stderr in any case. This blog page gives an example of the use of the logging tools.
    Last edited by Schol-R-LEA; January 10th, 2008 at 05:17 PM.
    Rev First Speaker Schol-R-LEA;2 JAM LCF ELF KoR KCO BiWM TGIF
    #define KINSEY (rand() % 7) λ Scheme is the Red Pill
    Scheme in Short Understanding the C/C++ Preprocessor
    Taming Python A Highly Opinionated Review of Programming Languages for the Novice, v1.1

    FOR SALE: One ShapeSystem 2300 CMD, extensively modified for human use. Includes s/w for anthro, transgender, sex-appeal enhance, & Gillian Anderson and Jason D. Poit clone forms. Some wear. $4500 obo. tverres@et.ins.gov
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Feb 2004
    Location
    London, England
    Posts
    1,585
    Rep Power
    1373
    You don't need to subclass anything. Here are the steps you need:

    1) import sys
    2) open the file you want to write to
    3) assign the file to sys.stderr

    If you want to restore stderr back to the terminal then you will need to save the original stderr object before you assign to it.
    e.g.
    python Code:
     
    import sys
    f = open("myfile.log", "w")
    original_stderr = sys.stderr
    sys.stderr = f
     
    ... do stuff
     
    sys.stderr = original_stderr
    f.close()


    Alternatively look at the logging module for a better way of writing out debug and diagnostic information.

    Dave
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2006
    Posts
    63
    Rep Power
    10
    Thanks, this works well for redirecting to a file.

    I was wondering if it might be possible to redirect it to a function? That way I could, for example, send it to a text control in a GUI program.

    For example, suppose I had a queue that I'd like to append the error to. Something like:

    msgQueue = Queue.Queue() # defined elsewhere, used for other messages too

    sys.stderr = msgQueue.put(error)

    Of course, in the put statement above I'm not referencing the error properly, it's just to get the point across.

    Any tips on how I might accomplish this?
    Last edited by wrybread; January 11th, 2008 at 07:12 AM.
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Feb 2004
    Location
    London, England
    Posts
    1,585
    Rep Power
    1373
    You can replace stderr with any object that has the same methods as a file. The only one you really need to implement is write - the others you can replace with do-nothing stubs, or leave them off altogether if they never get called. Something like this (warning, untested code ahead):

    python Code:
    class QueueWriter:
        def __init__(self, queue):
            self.queue = queue
     
        def write(self, string):
            self.queue.put(string)
     
        def close(self):
            pass
        def flush(self):
            pass
        # etc
     
    sys.stderr = QueueWriter(msgQueue)
    ...


    Dave
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2006
    Posts
    63
    Rep Power
    10
    Thanks, works perfectly.

    I don't exactly understand why though. Is it possible to explain why the write() function is triggered? And how "string" got passed to it?

    And are close() and flush() ever executed?

    And for anyone else coming down this path, here's the code I'm using to redirect stderr. This prints the text of any unhandled exceptions to the console as usual, saves to a text file, and pops open a wx dialog window.

    Code:
    class ErrorHandler:
    
        def __init__(self):
            pass
    
        def write(self, string):
            
            # write error to console
            print string
    
            # write error to file
            fname = "crash report (" + time.strftime("%Y-%m-%d %I-%M%p") + ").txt"
            handler = open(fname, "w")
            handler.write(string)
            handler.close()
    
            # write error to popup dialog
            dlg = wx.MessageDialog(None, string, "Crash Report", wx.ICON_HAND)
            dlg.ShowModal()
            dlg.Destroy()
            #os._exit(1) # close the program
            
        # not sure if these are necessary:
        def close(self):
            pass
    
        def flush(self):
            pass
    
    original_stderr = sys.stderr # stored in case want to revert
    sys.stderr = ErrorHandler()
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jan 2008
    Location
    At the start of every array...
    Posts
    15
    Rep Power
    0
    It works because of 'duck typing' in Python. All Python cares about about the sys.stdout and sys.stderr objects is that they have the neccesary methods.

    (Duck typing: if it quakes like a duck, and looks like a duck, its a duck.)

IMN logo majestic logo threadwatch logo seochat tools logo