"""Live e2e: Prometheus request metrics grow one series per virtual key. The proxy exposes ``/metrics`` (prometheus is in the callbacks and ``require_auth_for_metrics_endpoint`` is off in the e2e config). The counter ``litellm_requests_metric_total`` carries an ``api_key_alias`` label, so driving traffic through keys with distinct aliases must produce a distinct labeled series per alias. This is the per-key cardinality contract: a regression that stops stamping ``api_key_alias`` (or collapses every key onto one series) would drop the aliases and fail here. Scraping goes through ``transport.probe`` (raw text) and is parsed with prometheus_client. ``/metrics`` is per-pod behind a round-robin LB and the metric is eventually consistent (it increments on the success-logging callback), so the poll unions the aliases seen across scrapes until the deadline: counters persist on whichever pod served the driver call, so repeated scrapes converge without re-sending any billable traffic. """ from __future__ import annotations import time import pytest from prometheus_client.parser import text_string_to_metric_families from e2e_config import unique_marker from lifecycle import ResourceManager from logging_client import LoggingClient pytestmark = pytest.mark.e2e DRIVER_MODEL = "gemini-2.5-flash" REQUESTS_METRIC = "litellm_requests_metric_total" ALIAS_LABEL = "api_key_alias" DISTINCT_KEYS = 3 def _aliases_in_metric(exposition: str, metric: str, label: str) -> frozenset[str]: """The set of ``label`` values present on ``metric`` samples in a scrape.""" return frozenset( sample.labels[label] for family in text_string_to_metric_families(exposition) for sample in family.samples if sample.name == metric and label in sample.labels ) class TestPrometheusPerKeyCardinality: @pytest.mark.covers("logging.prometheus.success.exports_metric", exercised_on=[]) def test_distinct_key_aliases_produce_distinct_series( self, client: LoggingClient, resources: ResourceManager ) -> None: aliases = tuple(f"e2e-prom-{unique_marker()}" for _ in range(DISTINCT_KEYS)) for alias in aliases: key = client.key_with_alias(alias, models=[DRIVER_MODEL]) resources.defer(lambda k=key: client.delete_key(k)) response = client.chat(key, DRIVER_MODEL, f"reply with one word {alias}") assert response.model, f"driver call for {alias} returned no model: {response}" wanted = frozenset(aliases) deadline = time.monotonic() + client.proxy.poll_timeout seen: frozenset[str] = frozenset() while time.monotonic() < deadline: seen = seen | _aliases_in_metric(client.scrape_metrics(), REQUESTS_METRIC, ALIAS_LABEL) if wanted <= seen: break time.sleep(client.proxy.poll_interval) missing = wanted - seen assert not missing, ( f"{REQUESTS_METRIC} never exposed a per-key series for aliases {sorted(missing)} " f"on any scraped pod within the deadline; " f"each distinct {ALIAS_LABEL} must grow its own series" )