Logging: a more perseverent version of the StreamHandler?

Hello, 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 else: | 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() else: try: 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 else: 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 stream| | 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. https://www.avast.com/antivirus

On Fri, Jan 26, 2018 at 09:46:51PM +0100, liam marsh wrote:
[...]
What do you think? (about the idea, the implementation, and the way I wrote this email)|
I'll admit that I'm not actually very interested in the problem you're solving, I've never hit that problem so I'll leave it for those who have to comment on the idea and implementation. But I'll comment on the email: for some reason, the implementation you give has extraneous pipes | at the start and end of each line, e.g.: |class ReloadingHandler(StreamHandler):| | """| | A stream handler which reloads the stream object from one place if an error occurs| | """| Between the extraneous pipes and the lines being line-wrapped, the code has ended up severely mangled. (Code being emailed probably needs to stay below 78 characters per line to avoid being wrapped at the ends of lines.) -- Steve

Hello, and sorry for the late answer, Le 29/01/2018 à 01:41, Steven D'Aprano a écrit :
Oh, and something I forgot in my last e-mail: credit for the |`stdout_redirected()`| contextmanager: https://stackoverflow.com/questions/4675728/redirect-stdout-to-a-file-in-pyt....

On Wed, Jan 31, 2018 at 6:43 AM, liam marsh <liam.marsh.home@gmail.com> wrote:
When I reply to your email, it comes out looking like the above. There _is_ some non-text formatting happening here. (HTML, to be specific.) To be sure of how your emails will be read, I recommend disabling HTML (sometimes called "rich text", because someone saw some of the eyesores that get sent that way and said "You call that text?? That's rich!!"), so you see it the exact same way everyone else will. ChrisA

On Fri, Jan 26, 2018 at 09:46:51PM +0100, liam marsh wrote:
[...]
What do you think? (about the idea, the implementation, and the way I wrote this email)|
I'll admit that I'm not actually very interested in the problem you're solving, I've never hit that problem so I'll leave it for those who have to comment on the idea and implementation. But I'll comment on the email: for some reason, the implementation you give has extraneous pipes | at the start and end of each line, e.g.: |class ReloadingHandler(StreamHandler):| | """| | A stream handler which reloads the stream object from one place if an error occurs| | """| Between the extraneous pipes and the lines being line-wrapped, the code has ended up severely mangled. (Code being emailed probably needs to stay below 78 characters per line to avoid being wrapped at the ends of lines.) -- Steve

Hello, and sorry for the late answer, Le 29/01/2018 à 01:41, Steven D'Aprano a écrit :
Oh, and something I forgot in my last e-mail: credit for the |`stdout_redirected()`| contextmanager: https://stackoverflow.com/questions/4675728/redirect-stdout-to-a-file-in-pyt....

On Wed, Jan 31, 2018 at 6:43 AM, liam marsh <liam.marsh.home@gmail.com> wrote:
When I reply to your email, it comes out looking like the above. There _is_ some non-text formatting happening here. (HTML, to be specific.) To be sure of how your emails will be read, I recommend disabling HTML (sometimes called "rich text", because someone saw some of the eyesores that get sent that way and said "You call that text?? That's rich!!"), so you see it the exact same way everyone else will. ChrisA
participants (3)
-
Chris Angelico
-
liam marsh
-
Steven D'Aprano