This commit is contained in:
chjnett 2026-09-03 09:35:48 +08:00 committed by GitHub
commit 9c8539f09e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 42 additions and 3 deletions

View file

@ -1425,7 +1425,7 @@ def _has_attribute_error_in_chain(exc: Exception) -> bool:
_CLIENT_DISCONNECT_DETAIL: Final = "Client disconnected the request"
def _log_llm_api_exception(e: Exception) -> None:
def _log_llm_api_exception(e: Exception, litellm_call_id: str | None = None) -> None:
if getattr(e, "status_code", None) == 499 and getattr(e, "detail", None) == _CLIENT_DISCONNECT_DETAIL:
verbose_proxy_logger.info(
"litellm.proxy.proxy_server._handle_llm_api_exception(): client disconnected, upstream LLM request cancelled"
@ -1436,7 +1436,11 @@ def _log_llm_api_exception(e: Exception) -> None:
if is_expected_client_error(e) and not litellm.log_client_error_tracebacks
else verbose_proxy_logger.exception
)
log_fn("litellm.proxy.proxy_server._handle_llm_api_exception(): Exception occured - %s", e)
log_fn(
"litellm.proxy.proxy_server._handle_llm_api_exception(): Exception occured - %s",
e,
extra=({"litellm_call_id": litellm_call_id} if litellm_call_id is not None else None),
)
async def _cancel_llm_call_on_client_disconnect(
@ -3299,7 +3303,7 @@ class ProxyBaseLLMRequestProcessing:
version: str | None = None,
):
"""Raises ProxyException (OpenAI API compatible) if an exception is raised"""
_log_llm_api_exception(e)
_log_llm_api_exception(e, self.data.get("litellm_call_id"))
# Allow callbacks to transform the error response
transformed_exception: Final = await proxy_logging_obj.post_call_failure_hook(
user_api_key_dict=user_api_key_dict,

View file

@ -7719,3 +7719,38 @@ def test_log_llm_api_exception_traceback_only_for_unexpected_errors(exc, expect_
records = [r for r in caplog.records if "_handle_llm_api_exception(): Exception occured" in r.getMessage()]
assert len(records) == 1
assert (records[0].exc_info is not None) is expect_traceback
def test_log_llm_api_exception_includes_litellm_call_id(caplog):
"""Regression for #37532: proxy error log lines carry litellm_call_id so a
logged exception can be correlated back to the request that failed."""
from litellm._logging import verbose_proxy_logger
from litellm.proxy.common_request_processing import _log_llm_api_exception
verbose_proxy_logger.propagate = True
try:
with caplog.at_level("ERROR", logger="LiteLLM Proxy"):
_log_llm_api_exception(ValueError("boom"), "abc-123")
finally:
verbose_proxy_logger.propagate = False
records = [r for r in caplog.records if "_handle_llm_api_exception(): Exception occured" in r.getMessage()]
assert len(records) == 1
assert records[0].litellm_call_id == "abc-123"
def test_log_llm_api_exception_without_call_id_omits_field(caplog):
"""When no call id is available, the record still logs without the extra field."""
from litellm._logging import verbose_proxy_logger
from litellm.proxy.common_request_processing import _log_llm_api_exception
verbose_proxy_logger.propagate = True
try:
with caplog.at_level("ERROR", logger="LiteLLM Proxy"):
_log_llm_api_exception(ValueError("boom"))
finally:
verbose_proxy_logger.propagate = False
records = [r for r in caplog.records if "_handle_llm_api_exception(): Exception occured" in r.getMessage()]
assert len(records) == 1
assert not hasattr(records[0], "litellm_call_id")