Skip to content

Commit 96cf5a6

Browse files
authored
bpo-42378: fixed log truncation on logging shutdown (GH-27310)
Automerge-Triggered-By: GH:vsajip
1 parent 9751f85 commit 96cf5a6

File tree

4 files changed

+32
-6
lines changed

4 files changed

+32
-6
lines changed

Doc/library/logging.handlers.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ sends logging output to a disk file. It inherits the output functionality from
117117

118118
Outputs the record to the file.
119119

120+
Note that if the file was closed due to logging shutdown at exit and the file
121+
mode is 'w', the record will not be emitted (see :issue:`42378`).
122+
120123

121124
.. _null-handler:
122125

Lib/logging/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,7 @@ def __init__(self, level=NOTSET):
882882
self._name = None
883883
self.level = _checkLevel(level)
884884
self.formatter = None
885+
self._closed = False
885886
# Add the handler to the global _handlerList (for cleanup on shutdown)
886887
_addHandlerRef(self)
887888
self.createLock()
@@ -1000,6 +1001,7 @@ def close(self):
10001001
#get the module data lock, as we're updating a shared structure.
10011002
_acquireLock()
10021003
try: #unlikely to raise an exception, but you never know...
1004+
self._closed = True
10031005
if self._name and self._name in _handlers:
10041006
del _handlers[self._name]
10051007
finally:
@@ -1188,6 +1190,8 @@ def close(self):
11881190
finally:
11891191
# Issue #19523: call unconditionally to
11901192
# prevent a handler leak when delay is set
1193+
# Also see Issue #42378: we also rely on
1194+
# self._closed being set to True there
11911195
StreamHandler.close(self)
11921196
finally:
11931197
self.release()
@@ -1207,10 +1211,15 @@ def emit(self, record):
12071211
12081212
If the stream was not opened because 'delay' was specified in the
12091213
constructor, open it before calling the superclass's emit.
1214+
1215+
If stream is not open, current mode is 'w' and `_closed=True`, record
1216+
will not be emitted (see Issue #42378).
12101217
"""
12111218
if self.stream is None:
1212-
self.stream = self._open()
1213-
StreamHandler.emit(self, record)
1219+
if self.mode != 'w' or not self._closed:
1220+
self.stream = self._open()
1221+
if self.stream:
1222+
StreamHandler.emit(self, record)
12141223

12151224
def __repr__(self):
12161225
level = getLevelName(self.level)

Lib/test/test_logging.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5174,6 +5174,9 @@ def assertLogFile(self, filename):
51745174
msg="Log file %r does not exist" % filename)
51755175
self.rmfiles.append(filename)
51765176

5177+
def next_rec(self):
5178+
return logging.LogRecord('n', logging.DEBUG, 'p', 1,
5179+
self.next_message(), None, None, None)
51775180

51785181
class FileHandlerTest(BaseFileTest):
51795182
def test_delay(self):
@@ -5186,11 +5189,18 @@ def test_delay(self):
51865189
self.assertTrue(os.path.exists(self.fn))
51875190
fh.close()
51885191

5189-
class RotatingFileHandlerTest(BaseFileTest):
5190-
def next_rec(self):
5191-
return logging.LogRecord('n', logging.DEBUG, 'p', 1,
5192-
self.next_message(), None, None, None)
5192+
def test_emit_after_closing_in_write_mode(self):
5193+
# Issue #42378
5194+
os.unlink(self.fn)
5195+
fh = logging.FileHandler(self.fn, encoding='utf-8', mode='w')
5196+
fh.setFormatter(logging.Formatter('%(message)s'))
5197+
fh.emit(self.next_rec()) # '1'
5198+
fh.close()
5199+
fh.emit(self.next_rec()) # '2'
5200+
with open(self.fn) as fp:
5201+
self.assertEqual(fp.read().strip(), '1')
51935202

5203+
class RotatingFileHandlerTest(BaseFileTest):
51945204
def test_should_not_rollover(self):
51955205
# If maxbytes is zero rollover never occurs
51965206
rh = logging.handlers.RotatingFileHandler(
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fixes the issue with log file being overwritten when
2+
:class:`logging.FileHandler` is used in :mod:`atexit` with *filemode* set to
3+
``'w'``. Note this will cause the message in *atexit* not being logged if
4+
the log stream is already closed due to shutdown of logging.

0 commit comments

Comments
 (0)