I'm writing a daemon and needed a method of redirecting anything that gets sent to the standard out and standard error file descriptors (stdout and stderr) to a logging facility. I googled around a bit, but couldn't find a satisfactory solution, so I came up with this.
import logging import sys class StreamToLogger(object): """ Fake file-like stream object that redirects writes to a logger instance. """ def __init__(self, logger, log_level=logging.INFO): self.logger = logger self.log_level = log_level self.linebuf = '' def write(self, buf): for line in buf.rstrip().splitlines(): self.logger.log(self.log_level, line.rstrip()) logging.basicConfig( level=logging.DEBUG, format='%(asctime)s:%(levelname)s:%(name)s:%(message)s', filename="out.log", filemode='a' ) stdout_logger = logging.getLogger('STDOUT') sl = StreamToLogger(stdout_logger, logging.INFO) sys.stdout = sl stderr_logger = logging.getLogger('STDERR') sl = StreamToLogger(stderr_logger, logging.ERROR) sys.stderr = sl print "Test to standard out" raise Exception('Test to standard error')
We define a custom file-like object called StreamToLogger object which sends anything written to it to a logger instead. We then create two instances of that object and replace sys.stdout and sys.stderr with our fake file-like instances.
The output logfile looks like this:
2011-08-14 14:46:20,573:INFO:STDOUT:Test to standard out 2011-08-14 14:46:20,573:ERROR:STDERR:Traceback (most recent call last): 2011-08-14 14:46:20,574:ERROR:STDERR: File "redirect.py", line 33, in
2011-08-14 14:46:20,574:ERROR:STDERR:raise Exception('Test to standard error') 2011-08-14 14:46:20,574:ERROR:STDERR:Exception 2011-08-14 14:46:20,574:ERROR:STDERR:: 2011-08-14 14:46:20,574:ERROR:STDERR:Test to standard error