Cap urllib3.connectionpool at INFO in the default logging config

The root logger runs at DEBUG, so urllib3.connectionpool emitted a
record per pooled HTTP request. Keep its INFO+ output while dropping
the per-connection chatter.
This commit is contained in:
2026-09-28 04:38:28 +08:00
parent 3cf7e2e257
commit bcd1371019
2 changed files with 19 additions and 1 deletions
@@ -2,7 +2,9 @@
Configured once at app import time (see :mod:`tavolo.app`). By default a Configured once at app import time (see :mod:`tavolo.app`). By default a
single console handler at DEBUG level is installed, formatting records as single console handler at DEBUG level is installed, formatting records as
``{asctime} [{levelname}] ({processName}/{threadName}) - {name} - {message}``. ``{asctime} [{levelname}] ({processName}/{threadName}) - {name} - {message}``;
``urllib3.connectionpool`` is capped at INFO so its per-request DEBUG
chatter does not drown the log.
Point the ``LOGGING_CONFIG`` environment variable at a YAML file to take Point the ``LOGGING_CONFIG`` environment variable at a YAML file to take
over the configuration entirely; the file follows the over the configuration entirely; the file follows the
:data:`logging.config.dictConfig` schema, e.g.:: :data:`logging.config.dictConfig` schema, e.g.::
@@ -55,6 +57,13 @@ DEFAULT_CONFIG = {
"level": "DEBUG", "level": "DEBUG",
"handlers": ["console"], "handlers": ["console"],
}, },
"loggers": {
# Every pooled HTTP request is a DEBUG record; keep the logger's
# INFO+ output, drop the per-connection noise.
"urllib3.connectionpool": {
"level": "INFO",
},
},
} }
+9
View File
@@ -18,12 +18,15 @@ class LoggingConfigTest(unittest.TestCase):
self._root_level = root.level self._root_level = root.level
tavolo = logging.getLogger("tavolo") tavolo = logging.getLogger("tavolo")
self._tavolo_level = tavolo.level self._tavolo_level = tavolo.level
pool = logging.getLogger("urllib3.connectionpool")
self._pool_level = pool.level
def tearDown(self) -> None: def tearDown(self) -> None:
root = logging.getLogger() root = logging.getLogger()
root.handlers = self._root_handlers root.handlers = self._root_handlers
root.level = self._root_level root.level = self._root_level
logging.getLogger("tavolo").level = self._tavolo_level logging.getLogger("tavolo").level = self._tavolo_level
logging.getLogger("urllib3.connectionpool").level = self._pool_level
def test_default_config_when_unset(self) -> None: def test_default_config_when_unset(self) -> None:
configure_logging(None) configure_logging(None)
@@ -33,6 +36,12 @@ class LoggingConfigTest(unittest.TestCase):
any(isinstance(h, logging.StreamHandler) for h in root.handlers), any(isinstance(h, logging.StreamHandler) for h in root.handlers),
"default config installs a console stream handler", "default config installs a console stream handler",
) )
# The noisy per-request HTTP logger is capped at INFO while the
# root stays at DEBUG.
self.assertEqual(
logging.INFO,
logging.getLogger("urllib3.connectionpool").getEffectiveLevel(),
)
def test_yaml_config_is_applied(self) -> None: def test_yaml_config_is_applied(self) -> None:
with tempfile.TemporaryDirectory() as tmp: with tempfile.TemporaryDirectory() as tmp: