From 914830523889618e63c03ad3775a3d75d123733d Mon Sep 17 00:00:00 2001 From: Anas Khan <83116240+anxkhn@users.noreply.github.com> Date: Mon, 6 Jul 2026 15:40:35 +0530 Subject: [PATCH] fix(logging): parse JSON_LOGS env var so JSON_LOGS=False disables JSON logs json_logs was derived with bool(os.getenv("JSON_LOGS", False)). os.getenv returns a string (or None), never the bool default, so bool() is truthy for every non-empty value including "False", "0", and "no". Once a user followed the docs and set JSON_LOGS to enable it, there was no value (other than empty string) that would turn it back off, and the flag also propagates to litellm.json_logs which litellm-proxy-extras reads, corrupting its formatting too. Parse it case-insensitively so only "true" enables JSON logging, matching the existing litellm_proxy_extras/_logging.py fallback. The parse is extracted into a small pure helper so it is unit-testable without import-time side effects, and inlining avoids a circular import with str_to_bool in secret_managers.main (which imports from this module). --- litellm/_logging.py | 6 +++++- tests/test_litellm/test_logging.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/litellm/_logging.py b/litellm/_logging.py index 5f3c483869d..58f3435dcd5 100644 --- a/litellm/_logging.py +++ b/litellm/_logging.py @@ -77,7 +77,11 @@ class SecretRedactionFilter(logging.Filter): _secret_filter = SecretRedactionFilter() -json_logs = bool(os.getenv("JSON_LOGS", False)) +def _env_flag_enabled(value: Optional[str]) -> bool: + return (value or "").strip().lower() == "true" + + +json_logs = _env_flag_enabled(os.getenv("JSON_LOGS")) # Create a handler for the logger (you may need to adapt this based on your needs) log_level = os.getenv("LITELLM_LOG", "DEBUG") numeric_level: str = getattr(logging, log_level.upper()) diff --git a/tests/test_litellm/test_logging.py b/tests/test_litellm/test_logging.py index fbed044445b..9e694282fc1 100644 --- a/tests/test_litellm/test_logging.py +++ b/tests/test_litellm/test_logging.py @@ -16,6 +16,7 @@ import litellm from litellm._logging import ( ALL_LOGGERS, JsonFormatter, + _env_flag_enabled, _initialize_loggers_with_handler, _turn_on_json, verbose_logger, @@ -66,6 +67,33 @@ def test_json_mode_emits_one_record_per_logger(capfd): assert "timestamp" in obj, "`timestamp` key missing" +@pytest.mark.parametrize( + "value, expected", + [ + ("True", True), + ("true", True), + ("TRUE", True), + (" true ", True), + ("1", False), + ("False", False), + ("false", False), + ("0", False), + ("no", False), + ("off", False), + ("", False), + (None, False), + ], +) +def test_env_flag_enabled_only_true_enables(value, expected): + """ + Regression: JSON_LOGS is a boolean env flag, so only "true" (case-insensitive) + may enable it. The previous bool(os.getenv("JSON_LOGS", False)) turned any + non-empty string, including "False"/"0"/"no", into True, so JSON logging could + never be disabled via the documented env var. + """ + assert _env_flag_enabled(value) is expected + + def test_json_formatter_parses_embedded_json_message(): """ Test that JsonFormatter parses embedded JSON in the message field and promotes