Skip to content

Commit e35430b

Browse files
[3.10] bpo-42378: fixed log truncation on logging shutdown (GH-27310) (GH-30468)
Co-authored-by: andrei kulakov <[email protected]>
1 parent ed2656a commit e35430b

File tree

4 files changed

+32
-6
lines changed

4 files changed

+32
-6
lines changed

Doc/library/logging.handlers.rst

+3
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

+11-2
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,7 @@ def __init__(self, level=NOTSET):
878878
self._name = None
879879
self.level = _checkLevel(level)
880880
self.formatter = None
881+
self._closed = False
881882
# Add the handler to the global _handlerList (for cleanup on shutdown)
882883
_addHandlerRef(self)
883884
self.createLock()
@@ -996,6 +997,7 @@ def close(self):
996997
#get the module data lock, as we're updating a shared structure.
997998
_acquireLock()
998999
try: #unlikely to raise an exception, but you never know...
1000+
self._closed = True
9991001
if self._name and self._name in _handlers:
10001002
del _handlers[self._name]
10011003
finally:
@@ -1184,6 +1186,8 @@ def close(self):
11841186
finally:
11851187
# Issue #19523: call unconditionally to
11861188
# prevent a handler leak when delay is set
1189+
# Also see Issue #42378: we also rely on
1190+
# self._closed being set to True there
11871191
StreamHandler.close(self)
11881192
finally:
11891193
self.release()
@@ -1203,10 +1207,15 @@ def emit(self, record):
12031207
12041208
If the stream was not opened because 'delay' was specified in the
12051209
constructor, open it before calling the superclass's emit.
1210+
1211+
If stream is not open, current mode is 'w' and `_closed=True`, record
1212+
will not be emitted (see Issue #42378).
12061213
"""
12071214
if self.stream is None:
1208-
self.stream = self._open()
1209-
StreamHandler.emit(self, record)
1215+
if self.mode != 'w' or not self._closed:
1216+
self.stream = self._open()
1217+
if self.stream:
1218+
StreamHandler.emit(self, record)
12101219

12111220
def __repr__(self):
12121221
level = getLevelName(self.level)

Lib/test/test_logging.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -5168,6 +5168,9 @@ def assertLogFile(self, filename):
51685168
msg="Log file %r does not exist" % filename)
51695169
self.rmfiles.append(filename)
51705170

5171+
def next_rec(self):
5172+
return logging.LogRecord('n', logging.DEBUG, 'p', 1,
5173+
self.next_message(), None, None, None)
51715174

51725175
class FileHandlerTest(BaseFileTest):
51735176
def test_delay(self):
@@ -5180,11 +5183,18 @@ def test_delay(self):
51805183
self.assertTrue(os.path.exists(self.fn))
51815184
fh.close()
51825185

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

5197+
class RotatingFileHandlerTest(BaseFileTest):
51885198
def test_should_not_rollover(self):
51895199
# If maxbytes is zero rollover never occurs
51905200
rh = logging.handlers.RotatingFileHandler(
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)