mirror of
https://github.com/python/cpython.git
synced 2025-01-12 19:45:27 +08:00
bpo-30962: Added caching to Logger.isEnabledFor() (GH-2752)
This commit is contained in:
parent
caa1280d1e
commit
78c18a9b9a
@ -1244,6 +1244,19 @@ class Manager(object):
|
||||
alogger.parent = c.parent
|
||||
c.parent = alogger
|
||||
|
||||
def _clear_cache(self):
|
||||
"""
|
||||
Clear the cache for all loggers in loggerDict
|
||||
Called when level changes are made
|
||||
"""
|
||||
|
||||
_acquireLock()
|
||||
for logger in self.loggerDict.values():
|
||||
if isinstance(logger, Logger):
|
||||
logger._cache.clear()
|
||||
self.root._cache.clear()
|
||||
_releaseLock()
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Logger classes and functions
|
||||
#---------------------------------------------------------------------------
|
||||
@ -1274,12 +1287,14 @@ class Logger(Filterer):
|
||||
self.propagate = True
|
||||
self.handlers = []
|
||||
self.disabled = False
|
||||
self._cache = {}
|
||||
|
||||
def setLevel(self, level):
|
||||
"""
|
||||
Set the logging level of this logger. level must be an int or a str.
|
||||
"""
|
||||
self.level = _checkLevel(level)
|
||||
self.manager._clear_cache()
|
||||
|
||||
def debug(self, msg, *args, **kwargs):
|
||||
"""
|
||||
@ -1543,9 +1558,17 @@ class Logger(Filterer):
|
||||
"""
|
||||
Is this logger enabled for level 'level'?
|
||||
"""
|
||||
if self.manager.disable >= level:
|
||||
return False
|
||||
return level >= self.getEffectiveLevel()
|
||||
try:
|
||||
return self._cache[level]
|
||||
except KeyError:
|
||||
_acquireLock()
|
||||
if self.manager.disable >= level:
|
||||
is_enabled = self._cache[level] = False
|
||||
else:
|
||||
is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
|
||||
_releaseLock()
|
||||
|
||||
return is_enabled
|
||||
|
||||
def getChild(self, suffix):
|
||||
"""
|
||||
@ -1910,6 +1933,7 @@ def disable(level=CRITICAL):
|
||||
Disable all logging calls of severity 'level' and below.
|
||||
"""
|
||||
root.manager.disable = level
|
||||
root.manager._clear_cache()
|
||||
|
||||
def shutdown(handlerList=_handlerList):
|
||||
"""
|
||||
|
@ -135,7 +135,9 @@ class BaseTest(unittest.TestCase):
|
||||
logging._handlers.clear()
|
||||
logging._handlers.update(self.saved_handlers)
|
||||
logging._handlerList[:] = self.saved_handler_list
|
||||
loggerDict = logging.getLogger().manager.loggerDict
|
||||
manager = logging.getLogger().manager
|
||||
manager.disable = 0
|
||||
loggerDict = manager.loggerDict
|
||||
loggerDict.clear()
|
||||
loggerDict.update(self.saved_loggers)
|
||||
logger_states = self.logger_states
|
||||
@ -4094,6 +4096,62 @@ class LoggerTest(BaseTest):
|
||||
unpickled = pickle.loads(s)
|
||||
self.assertIs(unpickled, logger)
|
||||
|
||||
def test_caching(self):
|
||||
root = self.root_logger
|
||||
logger1 = logging.getLogger("abc")
|
||||
logger2 = logging.getLogger("abc.def")
|
||||
|
||||
# Set root logger level and ensure cache is empty
|
||||
root.setLevel(logging.ERROR)
|
||||
self.assertEqual(logger2.getEffectiveLevel(), logging.ERROR)
|
||||
self.assertEqual(logger2._cache, {})
|
||||
|
||||
# Ensure cache is populated and calls are consistent
|
||||
self.assertTrue(logger2.isEnabledFor(logging.ERROR))
|
||||
self.assertFalse(logger2.isEnabledFor(logging.DEBUG))
|
||||
self.assertEqual(logger2._cache, {logging.ERROR: True, logging.DEBUG: False})
|
||||
self.assertEqual(root._cache, {})
|
||||
self.assertTrue(logger2.isEnabledFor(logging.ERROR))
|
||||
|
||||
# Ensure root cache gets populated
|
||||
self.assertEqual(root._cache, {})
|
||||
self.assertTrue(root.isEnabledFor(logging.ERROR))
|
||||
self.assertEqual(root._cache, {logging.ERROR: True})
|
||||
|
||||
# Set parent logger level and ensure caches are emptied
|
||||
logger1.setLevel(logging.CRITICAL)
|
||||
self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
|
||||
self.assertEqual(logger2._cache, {})
|
||||
|
||||
# Ensure logger2 uses parent logger's effective level
|
||||
self.assertFalse(logger2.isEnabledFor(logging.ERROR))
|
||||
|
||||
# Set level to NOTSET and ensure caches are empty
|
||||
logger2.setLevel(logging.NOTSET)
|
||||
self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
|
||||
self.assertEqual(logger2._cache, {})
|
||||
self.assertEqual(logger1._cache, {})
|
||||
self.assertEqual(root._cache, {})
|
||||
|
||||
# Verify logger2 follows parent and not root
|
||||
self.assertFalse(logger2.isEnabledFor(logging.ERROR))
|
||||
self.assertTrue(logger2.isEnabledFor(logging.CRITICAL))
|
||||
self.assertFalse(logger1.isEnabledFor(logging.ERROR))
|
||||
self.assertTrue(logger1.isEnabledFor(logging.CRITICAL))
|
||||
self.assertTrue(root.isEnabledFor(logging.ERROR))
|
||||
|
||||
# Disable logging in manager and ensure caches are clear
|
||||
logging.disable()
|
||||
self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
|
||||
self.assertEqual(logger2._cache, {})
|
||||
self.assertEqual(logger1._cache, {})
|
||||
self.assertEqual(root._cache, {})
|
||||
|
||||
# Ensure no loggers are enabled
|
||||
self.assertFalse(logger1.isEnabledFor(logging.CRITICAL))
|
||||
self.assertFalse(logger2.isEnabledFor(logging.CRITICAL))
|
||||
self.assertFalse(root.isEnabledFor(logging.CRITICAL))
|
||||
|
||||
|
||||
class BaseFileTest(BaseTest):
|
||||
"Base class for handler tests that write log files"
|
||||
|
Loading…
Reference in New Issue
Block a user