Skip to content

Commit d60e39c

Browse files
committed
gh-160936: Make logging setLevel() and disable() cost O(cached loggers)
Manager._clear_cache() walked every logger in loggerDict on each setLevel() or disable() call, so configuring N loggers one at a time was quadratic. Track loggers that have populated their isEnabledFor cache in a WeakSet and clear only those.
1 parent ef1fce0 commit d60e39c

2 files changed

Lines changed: 9 additions & 2 deletions

File tree

‎Lib/logging/__init__.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,6 +1356,8 @@ def __init__(self, rootnode):
13561356
self.disable = 0
13571357
self.emittedNoHandlerWarning = False
13581358
self.loggerDict = {}
1359+
# Loggers whose isEnabledFor cache may be populated; see _clear_cache.
1360+
self._cached_loggers = weakref.WeakSet()
13591361
self.loggerClass = None
13601362
self.logRecordFactory = None
13611363

@@ -1471,9 +1473,12 @@ def _clear_cache(self):
14711473
"""
14721474

14731475
with _lock:
1474-
for logger in self.loggerDict.values():
1475-
if isinstance(logger, Logger):
1476+
# Only loggers that have populated a cache are visited, so
1477+
# setLevel() costs O(loggers with cached results), not O(loggers).
1478+
for logger in list(self._cached_loggers):
1479+
if self.loggerDict.get(logger.name) is logger:
14761480
logger._cache.clear()
1481+
self._cached_loggers.discard(logger)
14771482
self.root._cache.clear()
14781483

14791484
#---------------------------------------------------------------------------
@@ -1799,6 +1804,7 @@ def isEnabledFor(self, level):
17991804
return self._cache[level]
18001805
except KeyError:
18011806
with _lock:
1807+
self.manager._cached_loggers.add(self)
18021808
if self.manager.disable >= level:
18031809
is_enabled = self._cache[level] = False
18041810
else:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Speed up :meth:`logging.Logger.setLevel` and :func:`logging.disable` when there are many loggers: only loggers that have cached results are now cleared, instead of every logger.

0 commit comments

Comments
 (0)