diff --git a/litellm/integrations/prometheus.py b/litellm/integrations/prometheus.py index 8a99daef02a..ce5ed7ee9dd 100644 --- a/litellm/integrations/prometheus.py +++ b/litellm/integrations/prometheus.py @@ -160,7 +160,7 @@ def _get_budget_metrics_per_request_timeout() -> float: class _LabeledGauge(Protocol): """Structural type shared by ``prometheus_client.Gauge`` and the no-op / label-excluding wrappers above.""" - def labels(self, **labels: str) -> _LabeledGauge: ... + def labels(self, *labelvalues: str) -> _LabeledGauge: ... def set(self, value: float) -> None: ... @@ -2171,13 +2171,14 @@ class PrometheusLogger(CustomLogger): enum_values=enum_values, label_context=label_context, ) + label_values: Final = tuple(labels.get(name, "") for name in labelnames) if value is not None: self._drop_superseded_team_series(gauge=gauge, labelnames=labelnames, labels=labels) - gauge.labels(**labels).set(value) + gauge.labels(*label_values).set(value) return try: - gauge.remove(*(labels.get(name, "") for name in labelnames)) + gauge.remove(*label_values) except KeyError: # No child series for this labelset, which is the common case: # the team never had a limit for this model. diff --git a/tests/test_litellm/integrations/test_prometheus_team_rate_limit_metrics.py b/tests/test_litellm/integrations/test_prometheus_team_rate_limit_metrics.py index 0a59b720133..cbbcd9bba66 100644 --- a/tests/test_litellm/integrations/test_prometheus_team_rate_limit_metrics.py +++ b/tests/test_litellm/integrations/test_prometheus_team_rate_limit_metrics.py @@ -128,10 +128,9 @@ def test_labels_carry_team_and_requested_model(): _set_team_metrics(logger, _payload_with_headers(dict(ALL_TEAM_HEADERS))) for metric_name in TEAM_RATE_LIMIT_METRICS: - labels_kwargs = getattr(logger, metric_name).labels.call_args.kwargs - assert labels_kwargs["team"] == "team-abc" - assert labels_kwargs["team_alias"] == "research" - assert labels_kwargs["model"] == "gpt-4o-mini" + labelnames = PrometheusMetricLabels.get_labels(metric_name) + label_values = getattr(logger, metric_name).labels.call_args.args + assert dict(zip(labelnames, label_values, strict=True)) == TEAM_LABELS def test_emits_nothing_when_team_has_no_configured_limits(): @@ -353,10 +352,14 @@ def test_excluded_label_wrapper_cannot_remove_when_every_label_is_excluded(): def test_noop_metric_remove_is_inert(): + """A disabled metric answers every call without recording or raising.""" metric = NoOpMetric() - metric.labels(**TEAM_LABELS).set(60) - metric.remove(*TEAM_LABELS.values()) + child = metric.labels(*TEAM_LABELS.values()) + + assert child is metric + assert child.set(60) is None + assert metric.remove(*TEAM_LABELS.values()) is None def test_retires_the_old_series_when_a_team_is_renamed():