Skip to content

Commit 5a89172

Browse files
committed
Move TLS into class variable and add tests
1 parent e9f6079 commit 5a89172

File tree

2 files changed

+32
-6
lines changed

2 files changed

+32
-6
lines changed

Lib/logging/__init__.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,9 +1459,6 @@ def _clear_cache(self):
14591459
# Logger classes and functions
14601460
#---------------------------------------------------------------------------
14611461

1462-
_tls = threading.local()
1463-
_tls.in_progress = False
1464-
14651462
class Logger(Filterer):
14661463
"""
14671464
Instances of the Logger class represent a single logging channel. A
@@ -1477,6 +1474,8 @@ class Logger(Filterer):
14771474
level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels.
14781475
There is no arbitrary limit to the depth of nesting.
14791476
"""
1477+
_tls = threading.local()
1478+
14801479
def __init__(self, name, level=NOTSET):
14811480
"""
14821481
Initialize the logger with a name and an optional level.
@@ -1676,7 +1675,7 @@ def handle(self, record):
16761675
if self._is_disabled():
16771676
return
16781677

1679-
_tls.in_progress = True
1678+
self._tls.in_progress = True
16801679
try:
16811680
maybe_record = self.filter(record)
16821681
if not maybe_record:
@@ -1685,7 +1684,7 @@ def handle(self, record):
16851684
record = maybe_record
16861685
self.callHandlers(record)
16871686
finally:
1688-
_tls.in_progress = False
1687+
self._tls.in_progress = False
16891688

16901689
def addHandler(self, hdlr):
16911690
"""
@@ -1824,7 +1823,9 @@ def _hierlevel(logger):
18241823
_hierlevel(item) == 1 + _hierlevel(item.parent))
18251824

18261825
def _is_disabled(self):
1827-
return self.disabled or getattr(_tls, 'in_progress', False)
1826+
# We need to use getattr as it will only be set the first time a log
1827+
# message is recorded on any given thread
1828+
return self.disabled or getattr(self._tls, 'in_progress', False)
18281829

18291830
def __repr__(self):
18301831
level = getLevelName(self.getEffectiveLevel())

Lib/test/test_logging.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4174,6 +4174,31 @@ def __init__(self, *args, **kwargs):
41744174
handler = logging.getHandlerByName('custom')
41754175
self.assertEqual(handler.custom_kwargs, custom_kwargs)
41764176

4177+
# See gh-91555 and gh-90321
4178+
@support.requires_subprocess()
4179+
def test_deadlock_in_queue(self):
4180+
queue = multiprocessing.Queue()
4181+
handler = logging.handlers.QueueHandler(queue)
4182+
logger = multiprocessing.get_logger()
4183+
level = logger.level
4184+
try:
4185+
logger.setLevel(logging.DEBUG)
4186+
logger.addHandler(handler)
4187+
logger.debug("deadlock")
4188+
finally:
4189+
logger.setLevel(level)
4190+
logger.removeHandler(handler)
4191+
4192+
def test_recursion_in_custom_handler(self):
4193+
class BadHandler(logging.Handler):
4194+
def __init__(self):
4195+
super().__init__()
4196+
def emit(self, record):
4197+
logger.debug("recurse")
4198+
logger = logging.getLogger("test_recursion_in_custom_handler")
4199+
logger.addHandler(BadHandler())
4200+
logger.setLevel(logging.DEBUG)
4201+
logger.debug("boom")
41774202

41784203
class ManagerTest(BaseTest):
41794204
def test_manager_loggerclass(self):

0 commit comments

Comments
 (0)