mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-15 23:31:29 +00:00
Merge pull request #41059 from BerriAI/litellm_prometheus_pre_call_rate_limit_api_provider
fix(prometheus): label pre-call rate limit failures with the resolved api_provider
This commit is contained in:
commit
34fe9f71d5
2 changed files with 84 additions and 1 deletions
|
|
@ -41,6 +41,7 @@ from litellm.proxy._types import (
|
|||
LiteLLM_UserTable,
|
||||
UserAPIKeyAuth,
|
||||
)
|
||||
from litellm.proxy.hooks.rate_limiter_utils import PROXY_LLM_PROVIDER_FALLBACK
|
||||
from litellm.repositories.base_repository import BaseRepository
|
||||
from litellm.repositories.organization_repository import OrganizationRepository
|
||||
from litellm.repositories.team_repository import TeamRepository
|
||||
|
|
@ -2581,6 +2582,15 @@ class PrometheusLogger(CustomLogger):
|
|||
)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _extract_api_provider_from_exception(exception: Exception) -> str | None:
|
||||
if not isinstance(exception, litellm.exceptions.RateLimitError):
|
||||
return None
|
||||
llm_provider: Final = exception.llm_provider
|
||||
if not llm_provider or llm_provider == PROXY_LLM_PROVIDER_FALLBACK:
|
||||
return None
|
||||
return llm_provider
|
||||
|
||||
async def async_post_call_failure_hook(
|
||||
self,
|
||||
request_data: dict,
|
||||
|
|
@ -2616,7 +2626,9 @@ class PrometheusLogger(CustomLogger):
|
|||
_metadata: Final = request_data.get("metadata", {}) or {}
|
||||
model_id: Final = _metadata.get("model_info", {}).get("id") or request_data.get("model_info", {}).get("id")
|
||||
rate_limit_category, rate_limit_type = self._extract_rate_limit_labels(original_exception)
|
||||
api_provider: Final = self._extract_api_provider_from_request_data(request_data)
|
||||
api_provider: Final = self._extract_api_provider_from_request_data(
|
||||
request_data
|
||||
) or self._extract_api_provider_from_exception(original_exception)
|
||||
enum_values: Final = UserAPIKeyLabelValues(
|
||||
end_user=user_api_key_dict.end_user_id,
|
||||
user=user_api_key_dict.user_id,
|
||||
|
|
|
|||
|
|
@ -716,6 +716,77 @@ async def test_failure_hook_emits_api_provider_value_on_failed_requests_metric()
|
|||
_clear_prometheus_registry()
|
||||
|
||||
|
||||
async def _failed_requests_api_provider_labels(
|
||||
request_data: dict[str, object],
|
||||
original_exception: Exception,
|
||||
) -> list[str]:
|
||||
from litellm.integrations.prometheus import PrometheusLogger
|
||||
from litellm.proxy._types import UserAPIKeyAuth
|
||||
|
||||
_clear_prometheus_registry()
|
||||
try:
|
||||
await PrometheusLogger().async_post_call_failure_hook(
|
||||
request_data=request_data,
|
||||
original_exception=original_exception,
|
||||
user_api_key_dict=UserAPIKeyAuth(token="tok"),
|
||||
)
|
||||
return [
|
||||
s.labels.get("api_provider")
|
||||
for s in _collected_samples("litellm_proxy_failed_requests_metric_total")
|
||||
]
|
||||
finally:
|
||||
_clear_prometheus_registry()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_failure_hook_emits_api_provider_from_pre_call_rate_limit_error_for_router_alias():
|
||||
"""
|
||||
Pre-call limiters reject before a deployment lands on request_data and a
|
||||
router alias cannot be inferred from its name, so the provider the limiter
|
||||
resolved onto the exception is the only source for the label.
|
||||
"""
|
||||
from litellm.exceptions import RateLimitType
|
||||
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
|
||||
|
||||
err = ProxyRateLimitError(
|
||||
detail={"error": "rpm exceeded"},
|
||||
rate_limit_type=RateLimitType.REQUESTS,
|
||||
model="openai/gpt-5.4-mini",
|
||||
llm_provider="openai",
|
||||
)
|
||||
|
||||
assert await _failed_requests_api_provider_labels(
|
||||
{"model": "team-chat-model", "metadata": {}}, err
|
||||
) == ["openai"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_failure_hook_leaves_api_provider_unset_when_rate_limiter_could_not_resolve_provider():
|
||||
from litellm.proxy.common_utils.proxy_rate_limit_error import ProxyRateLimitError
|
||||
|
||||
err = ProxyRateLimitError(detail={"error": "rpm exceeded"}, model="unknown-alias")
|
||||
|
||||
assert await _failed_requests_api_provider_labels(
|
||||
{"model": "unknown-alias", "metadata": {}}, err
|
||||
) == ["None"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_failure_hook_prefers_request_data_provider_over_exception_provider():
|
||||
from litellm.exceptions import RateLimitError
|
||||
|
||||
err = RateLimitError(message="upstream 429", llm_provider="openai", model="gpt-4o")
|
||||
|
||||
assert await _failed_requests_api_provider_labels(
|
||||
{
|
||||
"model": "gpt-4o",
|
||||
"metadata": {},
|
||||
"litellm_params": {"custom_llm_provider": "azure"},
|
||||
},
|
||||
err,
|
||||
) == ["azure"]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_user_email_in_required_metrics()
|
||||
test_user_email_label_exists()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue