From 845d7ea89b466363efba83e67c94a27b10a09a71 Mon Sep 17 00:00:00 2001 From: RaresKeY <158580472+RaresKeY@users.noreply.github.com> Date: Sat, 18 Jul 2026 12:43:11 +0000 Subject: [PATCH] fix(logging): apply log level to uvicorn entrypoints --- app.py | 2 ++ core/log_safety.py | 12 ++++++++++++ tests/test_log_safety.py | 20 ++++++++++++++++++++ tests/test_model_capability_diagnostics.py | 1 + 4 files changed, 35 insertions(+) diff --git a/app.py b/app.py index bae972452..da511384d 100644 --- a/app.py +++ b/app.py @@ -87,12 +87,14 @@ from core.log_safety import ( CAPABILITY_DIAGNOSTICS_LOGGER, ScopedDiagnosticsFilter, application_log_settings, + configure_uvicorn_log_levels, ) _root_logger = logging.getLogger() _log_level_name = os.getenv("LOG_LEVEL", "INFO").strip().upper() _application_log_level, _capability_debug = application_log_settings(_log_level_name) _root_logger.setLevel(_application_log_level) +configure_uvicorn_log_levels(_application_log_level) logging.getLogger(CAPABILITY_DIAGNOSTICS_LOGGER).setLevel( logging.DEBUG if _capability_debug else logging.NOTSET ) diff --git a/core/log_safety.py b/core/log_safety.py index a314e1e98..b0bab625d 100644 --- a/core/log_safety.py +++ b/core/log_safety.py @@ -15,6 +15,7 @@ from urllib.parse import urlparse, urlunparse CAPABILITY_DIAGNOSTICS_LOGGER = "src.model_capability_readers" +UVICORN_LOGGER_NAMES = ("uvicorn", "uvicorn.error", "uvicorn.access") _LOG_LEVELS = { "DEBUG": logging.DEBUG, @@ -41,6 +42,17 @@ def application_log_settings(value: object) -> tuple[int, bool]: return max(requested, logging.INFO), requested == logging.DEBUG +def configure_uvicorn_log_levels(application_level: int) -> None: + """Apply the mapped app level to Uvicorn's non-propagating loggers. + + External entrypoints configure these loggers before importing ``app`` and + otherwise bypass the root logger's level and scoped diagnostics filter. + """ + + for logger_name in UVICORN_LOGGER_NAMES: + logging.getLogger(logger_name).setLevel(application_level) + + class ScopedDiagnosticsFilter(logging.Filter): """Allow normal application records plus one explicitly scoped DEBUG log.""" diff --git a/tests/test_log_safety.py b/tests/test_log_safety.py index a4de26666..47f5611ab 100644 --- a/tests/test_log_safety.py +++ b/tests/test_log_safety.py @@ -6,6 +6,7 @@ from core.log_safety import ( CAPABILITY_DIAGNOSTICS_LOGGER, ScopedDiagnosticsFilter, application_log_settings, + configure_uvicorn_log_levels, redact_url, ) @@ -65,6 +66,25 @@ def test_application_log_settings_scope_debug_and_fail_closed( ) +def test_configure_uvicorn_log_levels_clamps_non_propagating_loggers(): + logger_names = ("uvicorn", "uvicorn.error", "uvicorn.access") + previous_levels = { + name: logging.getLogger(name).level for name in logger_names + } + try: + for name in logger_names: + logging.getLogger(name).setLevel(logging.DEBUG) + + configure_uvicorn_log_levels(logging.ERROR) + + assert all( + logging.getLogger(name).level == logging.ERROR for name in logger_names + ) + finally: + for name, level in previous_levels.items(): + logging.getLogger(name).setLevel(level) + + def _record(name: str, level: int) -> logging.LogRecord: return logging.LogRecord(name, level, __file__, 1, "message", (), None) diff --git a/tests/test_model_capability_diagnostics.py b/tests/test_model_capability_diagnostics.py index 7b1969430..e6b2c7487 100644 --- a/tests/test_model_capability_diagnostics.py +++ b/tests/test_model_capability_diagnostics.py @@ -62,6 +62,7 @@ def test_web_app_logging_uses_existing_log_level_environment_toggle(): assert 'os.getenv("LOG_LEVEL", "INFO")' in source assert "application_log_settings(_log_level_name)" in source assert "_root_logger.setLevel(_application_log_level)" in source + assert "configure_uvicorn_log_levels(_application_log_level)" in source assert "_console_h.addFilter(_diagnostics_filter)" in source assert "_file_h.addFilter(_diagnostics_filter)" in source assert "log_level=_application_log_level" in source