[issue6333] logging: ValueError: I/O operation on closed file
report at bugs.python.org
Thu Mar 8 17:49:27 CET 2012
Vinay Sajip <vinay_sajip at yahoo.co.uk> added the comment:
Re. the fix to #9501, the swallowing of exceptions was done for specific reasons noted in the comments in the exception clause which does the swallowing. This only happens during application shutdown - not all ValueErrors on flush() or close() are swallowed. In general, swallowing these will mask logic errors which close a stream prematurely.
If you pass a stream to a logging.StreamHandler, make sure you remove the handler from any loggers you attached it to, then close it. Otherwise (if you just close the underlying stream) the StreamHandler might still try to use it, leading to the error. Unattaching the handler and closing it tells logging you're done with writing to that stream, so subsequent logging calls won't try to write to that stream.
I'm not aware that every file-like object (including duck-typed ones) will have a 'closed' attribute, so checking for that may not help.
If you want to set sys.stderr to a StringIO() and then create a StreamHandler from it, that's fine. The sequence should be:
set sys.stderr to StringIO instance
create a StreamHandler with sys.stderr
add that handler to a logger
remove that handler from a logger
close the handler (StreamHandler does not close the underlying stream)
close the StringIO instance
access the contents of the StringIO instance using getvalue()
If things are not done in that order, it's possible for arbitrary code (e.g. in a 3rd-party library) to log an event, because of which logging then tries to write to the stream. If that stream is closed, you get the ValueError - that's a warning that something isn't being done correctly, and the answer is not to just swallow that exception.
Re. your proposed fix - it may be fine in your specific scenario, but I wouldn't recommend it in general because it may mask logic errors in a program.
Regarding your preference for sys.__stderr__ rather than sys.stderr, that's all it is - a preference. You can easily pass the exact stream that you want to StreamHandler, including sys.__stderr__, so the fact that it picks sys.stderr by default shouldn't bother you - just be explicit.
Of course, that default - whatever the rights and wrongs of it - cannot be changed without breaking existing code, so it has to stay that way.
Python tracker <report at bugs.python.org>
More information about the Python-bugs-list