Skip to content
Open
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
47 changes: 25 additions & 22 deletions Lib/logging/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import threading
import traceback

from bisect import bisect_left
from socketserver import ThreadingTCPServer, StreamRequestHandler


Expand Down Expand Up @@ -197,6 +198,21 @@ def _handle_existing_loggers(existing, child_loggers, disable_existing):
else:
logger.disabled = disable_existing

def _discard_existing_logger(name, existing, existing_set, child_loggers):
"""Discard a configured logger and record its existing children."""
if name in existing_set:
prefixed = name + "."
i = bisect_left(existing, prefixed)
num_existing = len(existing)
while i < num_existing:
child = existing[i]
if not child.startswith(prefixed):
break
if child in existing_set:
child_loggers.add(child)
i += 1
existing_set.remove(name)

def _install_loggers(cp, handlers, disable_existing):
"""Create and install loggers"""

Expand Down Expand Up @@ -235,25 +251,17 @@ def _install_loggers(cp, handlers, disable_existing):
#named loggers. With a sorted list it is easier
#to find the child loggers.
existing.sort()
existing_set = set(existing)
#We'll keep the list of existing loggers
#which are children of named loggers here...
child_loggers = []
child_loggers = set()
#now set up the new ones...
for log in llist:
section = cp["logger_%s" % log]
qn = section["qualname"]
propagate = section.getint("propagate", fallback=1)
logger = logging.getLogger(qn)
if qn in existing:
i = existing.index(qn) + 1 # start with the entry after qn
prefixed = qn + "."
pflen = len(prefixed)
num_existing = len(existing)
while i < num_existing:
if existing[i][:pflen] == prefixed:
child_loggers.append(existing[i])
i += 1
existing.remove(qn)
_discard_existing_logger(qn, existing, existing_set, child_loggers)
if "level" in section:
level = section["level"]
logger.setLevel(level)
Expand Down Expand Up @@ -281,6 +289,7 @@ def _install_loggers(cp, handlers, disable_existing):
# logger.propagate = 1
# elif disable_existing_loggers:
# logger.disabled = 1
existing = [name for name in existing if name in existing_set]
_handle_existing_loggers(existing, child_loggers, disable_existing)


Expand Down Expand Up @@ -638,22 +647,15 @@ def configure(self):
#named loggers. With a sorted list it is easier
#to find the child loggers.
existing.sort()
existing_set = set(existing)
#We'll keep the list of existing loggers
#which are children of named loggers here...
child_loggers = []
child_loggers = set()
#now set up the new ones...
loggers = config.get('loggers', EMPTY_DICT)
for name in loggers:
if name in existing:
i = existing.index(name) + 1 # look after name
prefixed = name + "."
pflen = len(prefixed)
num_existing = len(existing)
while i < num_existing:
if existing[i][:pflen] == prefixed:
child_loggers.append(existing[i])
i += 1
existing.remove(name)
_discard_existing_logger(name, existing, existing_set,
child_loggers)
try:
self.configure_logger(name, loggers[name])
except Exception as e:
Expand All @@ -673,6 +675,7 @@ def configure(self):
# logger.propagate = True
# elif disable_existing:
# logger.disabled = True
existing = [name for name in existing if name in existing_set]
_handle_existing_loggers(existing, child_loggers,
disable_existing)

Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -4173,6 +4173,26 @@ def test_90195(self):
# Logger should be enabled, since explicitly mentioned
self.assertFalse(logger.disabled)

def test_disable_existing_loggers_preserves_children(self):
parent = logging.getLogger('many')
child = logging.getLogger('many.child')
cousin = logging.getLogger('many-child')
for i in range(20):
logging.getLogger(f'many-sibling-{i}')

self.apply_config({
'version': 1,
'loggers': {
'many': {
'level': 'INFO',
},
},
})

self.assertFalse(parent.disabled)
self.assertFalse(child.disabled)
self.assertTrue(cousin.disabled)

def test_111615(self):
# See gh-111615
import_helper.import_module('_multiprocessing') # see gh-113692
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Speed up :func:`logging.config.fileConfig` and
:func:`logging.config.dictConfig` when handling many existing loggers.
Loading