Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions Lib/logging/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1397,18 +1397,28 @@ def __init__(self, name, level=NOTSET):
"""
Filterer.__init__(self)
self.name = name
self.level = _checkLevel(level)
self._level = _checkLevel(level)
self.parent = None
self.propagate = True
self.handlers = []
self.disabled = False
self._cache = {}

@property
def level(self):
return self._level

@level.setter
def level(self, level):
warnings.warn("Use the setLevel() method to set the log level",
DeprecationWarning, stacklevel=2)
self.setLevel(level)

def setLevel(self, level):
"""
Set the logging level of this logger. level must be an int or a str.
"""
self.level = _checkLevel(level)
self._level = _checkLevel(level)
self.manager._clear_cache()

def debug(self, msg, *args, **kwargs):
Expand Down Expand Up @@ -1671,8 +1681,8 @@ def getEffectiveLevel(self):
"""
logger = self
while logger:
if logger.level:
return logger.level
if logger._level:
return logger._level
logger = logger.parent
return NOTSET

Expand Down
7 changes: 4 additions & 3 deletions Lib/logging/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,10 @@ def _handle_existing_loggers(existing, child_loggers, disable_existing):
for log in existing:
logger = root.manager.loggerDict[log]
if log in child_loggers:
logger.level = logging.NOTSET
logger.handlers = []
logger.propagate = True
if not isinstance(logger, logging.PlaceHolder):
logger.setLevel(logging.NOTSET)
logger.handlers = []
logger.propagate = True
else:
logger.disabled = disable_existing

Expand Down
11 changes: 10 additions & 1 deletion Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -4315,7 +4315,7 @@ def cleanup(self):
logging._handlers.clear()
logging._handlers.update(self.saved_handlers)
logging._handlerList[:] = self.saved_handler_list
logging.root.level = self.original_logging_level
logging.root.setLevel(self.original_logging_level)

def test_no_kwargs(self):
logging.basicConfig()
Expand Down Expand Up @@ -4906,6 +4906,15 @@ def test_caching(self):
# Ensure logger2 uses parent logger's effective level
self.assertFalse(logger2.isEnabledFor(logging.ERROR))

# Ensure setting level directly still clears cache
self.assertEqual(logger2._cache, {logging.ERROR: False})
with warnings.catch_warnings(record=True) as w:
logger2.level = logging.ERROR
self.assertEqual(1, len(w))
self.assertEqual(logger2._cache, {})
self.assertTrue(logger2.isEnabledFor(logging.ERROR))
self.assertEqual(logger2._cache, {logging.ERROR: True})

# Set level to NOTSET and ensure caches are empty
logger2.setLevel(logging.NOTSET)
self.assertEqual(logger2.getEffectiveLevel(), logging.CRITICAL)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Setting the ``level`` attribute of a ``logger.Logger`` (instead of calling
``setLevel()``) no longer causes cache inconsistency.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Setting the ``level`` attribute of a ``logger.Logger`` is deprecated. The
log level should only ever be set using the ``setLevel()`` method.