mirror of https://github.com/python/cpython
bpo-42378: fixed log truncation on logging shutdown (GH-27310)
Automerge-Triggered-By: GH:vsajip
This commit is contained in:
parent
9751f85914
commit
96cf5a63d2
|
@ -117,6 +117,9 @@ sends logging output to a disk file. It inherits the output functionality from
|
|||
|
||||
Outputs the record to the file.
|
||||
|
||||
Note that if the file was closed due to logging shutdown at exit and the file
|
||||
mode is 'w', the record will not be emitted (see :issue:`42378`).
|
||||
|
||||
|
||||
.. _null-handler:
|
||||
|
||||
|
|
|
@ -882,6 +882,7 @@ class Handler(Filterer):
|
|||
self._name = None
|
||||
self.level = _checkLevel(level)
|
||||
self.formatter = None
|
||||
self._closed = False
|
||||
# Add the handler to the global _handlerList (for cleanup on shutdown)
|
||||
_addHandlerRef(self)
|
||||
self.createLock()
|
||||
|
@ -1000,6 +1001,7 @@ class Handler(Filterer):
|
|||
#get the module data lock, as we're updating a shared structure.
|
||||
_acquireLock()
|
||||
try: #unlikely to raise an exception, but you never know...
|
||||
self._closed = True
|
||||
if self._name and self._name in _handlers:
|
||||
del _handlers[self._name]
|
||||
finally:
|
||||
|
@ -1188,6 +1190,8 @@ class FileHandler(StreamHandler):
|
|||
finally:
|
||||
# Issue #19523: call unconditionally to
|
||||
# prevent a handler leak when delay is set
|
||||
# Also see Issue #42378: we also rely on
|
||||
# self._closed being set to True there
|
||||
StreamHandler.close(self)
|
||||
finally:
|
||||
self.release()
|
||||
|
@ -1207,10 +1211,15 @@ class FileHandler(StreamHandler):
|
|||
|
||||
If the stream was not opened because 'delay' was specified in the
|
||||
constructor, open it before calling the superclass's emit.
|
||||
|
||||
If stream is not open, current mode is 'w' and `_closed=True`, record
|
||||
will not be emitted (see Issue #42378).
|
||||
"""
|
||||
if self.stream is None:
|
||||
self.stream = self._open()
|
||||
StreamHandler.emit(self, record)
|
||||
if self.mode != 'w' or not self._closed:
|
||||
self.stream = self._open()
|
||||
if self.stream:
|
||||
StreamHandler.emit(self, record)
|
||||
|
||||
def __repr__(self):
|
||||
level = getLevelName(self.level)
|
||||
|
|
|
@ -5174,6 +5174,9 @@ class BaseFileTest(BaseTest):
|
|||
msg="Log file %r does not exist" % filename)
|
||||
self.rmfiles.append(filename)
|
||||
|
||||
def next_rec(self):
|
||||
return logging.LogRecord('n', logging.DEBUG, 'p', 1,
|
||||
self.next_message(), None, None, None)
|
||||
|
||||
class FileHandlerTest(BaseFileTest):
|
||||
def test_delay(self):
|
||||
|
@ -5186,11 +5189,18 @@ class FileHandlerTest(BaseFileTest):
|
|||
self.assertTrue(os.path.exists(self.fn))
|
||||
fh.close()
|
||||
|
||||
class RotatingFileHandlerTest(BaseFileTest):
|
||||
def next_rec(self):
|
||||
return logging.LogRecord('n', logging.DEBUG, 'p', 1,
|
||||
self.next_message(), None, None, None)
|
||||
def test_emit_after_closing_in_write_mode(self):
|
||||
# Issue #42378
|
||||
os.unlink(self.fn)
|
||||
fh = logging.FileHandler(self.fn, encoding='utf-8', mode='w')
|
||||
fh.setFormatter(logging.Formatter('%(message)s'))
|
||||
fh.emit(self.next_rec()) # '1'
|
||||
fh.close()
|
||||
fh.emit(self.next_rec()) # '2'
|
||||
with open(self.fn) as fp:
|
||||
self.assertEqual(fp.read().strip(), '1')
|
||||
|
||||
class RotatingFileHandlerTest(BaseFileTest):
|
||||
def test_should_not_rollover(self):
|
||||
# If maxbytes is zero rollover never occurs
|
||||
rh = logging.handlers.RotatingFileHandler(
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Fixes the issue with log file being overwritten when
|
||||
:class:`logging.FileHandler` is used in :mod:`atexit` with *filemode* set to
|
||||
``'w'``. Note this will cause the message in *atexit* not being logged if
|
||||
the log stream is already closed due to shutdown of logging.
|
Loading…
Reference in New Issue