[Python-ideas] Logging: a more perseverent version of the StreamHandler?

liam marsh liam.marsh.home at gmail.com
Fri Jan 26 15:46:51 EST 2018

Some time ago, I set up some logging using stdout in a program with the 
`stdout_redirected()` context manager, which had to close and reopen 
stdout to work.
Unsurprisingly, the StreamHandler didn't take it well.

So I made a Handler class which is able to reload the stream (AKA get 
the new sys.stdout) whenever the old one wasn't writable.
But there might be some more legit use cases for stubborn StreamHandlers 
like that (that are not ugly-looking, hopefully temporary patches).

The way I see it for now is a StreamHandler subclass which, instead of 
having a `stream` argument, would have |`getStream`|,|`reloadStream`| 
and |`location`|, and would be used this way:
On initialisation, it would load the stream object, then act as a 
regular StreamHandler, but checking that the stream is writable at each 
`handler.emit()` call. If it is not, then reload it.

If given, the |`getStream`| (a callable object which returns a 
ready-to-use stream) argument is used to load/reload the underlying 
stream, else it would be fetched at the location described by 
`location`, and, if it is still not writable, call |`reloadStream()` 
|(which should put a usable stream object at |`location`|) then try to 
fetch it again.

Here is the current implementation I have:

from .config import _resolve as resolve  # will (uglily) be used later

|class ReloadingHandler(StreamHandler):|
|    """|
|    A stream handler which reloads the stream object from one place if 
an error occurs|
|    """|
|    def __init__(self, getStream=None, reloadStream=None, location=None):|
|        """|
|        Initialize the handler.|
|        If stream is not specified, sys.stderr is used.|
|        """

         self.getStream = getStream
         self.stream = None  # to be overwritten later
         if getStream is None:|
||            if location is None:
                 self.location = 'sys.stderr'  # note the lack of 'ext://'
                 self.reloadStream = None
|                self.reloadStream = reloadStream
                 self.location = location

         stream = self.reload()  # gets the stream
         StreamHandler.__init__(self, stream||)
     def reload(self):
         if self.getStream is not None:
             stream = self.getStream()
                 stream = resolve(self.location)
                 exc = None
             except Exception as err:
                 exc = err  # is this really needed?
                 stream = None  # just retry for now
             if stream is None or not stream.writable():
                 if self.reloadStream is None:
                     if exc:
                         raise exc
                         raise ValueError("ReloadingHandler couldn't 
reload a valid stream")

                 stream = resolve(self.location)  # if it fails this 
time, do not catch exception here

         return stream
|    def emit(self, record):|
|        """|
|        Emit a record.|
|        If a formatter is specified, it is used to format the record.|
|        The record is then written to the stream with a trailing 
newline.  If|
|        exception information is present, it is formatted using|
|        traceback.print_exception and appended to the stream.  If the 
|        has an 'encoding' attribute, it is used to determine how to do the|
|        output to the stream.|
|        """|
|        if not self.stream.writable():|
|            self.reload()|
|        StreamHandler.emit(self, record)|
What do you think? (about the idea, the implementation, and the way I 
wrote this email)|

L'absence de virus dans ce courrier électronique a été vérifiée par le logiciel antivirus Avast.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180126/cf0de2c5/attachment.html>

More information about the Python-ideas mailing list