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