Skip to content

feat(prometheus): add api_provider label to token, latency, request and cache metrics - #32126

Merged
yucheng-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_prometheus_api_provider_labels
Jul 4, 2026
Merged

feat(prometheus): add api_provider label to token, latency, request and cache metrics#32126
yucheng-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_prometheus_api_provider_labels

Conversation

@yucheng-berri

@yucheng-berri yucheng-berri commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

LIT-4178

Linear ticket

Pre-Submission checklist

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Screenshots / Proof of Fix

Before
Screenshot 2026-07-03 at 12 41 06 PM
Screenshot 2026-07-03 at 12 40 57 PM

After
Screenshot 2026-07-03 at 12 33 52 PM
Screenshot 2026-07-03 at 12 34 27 PM

Type

🐛 Bug Fix

Changes

A subset of Prometheus metrics carried no api_provider label even though sibling metrics emitted from the same call sites (litellm_spend_metric, litellm_requests_metric) already did, so there was no way to break token usage, latency, request counts or cache hits down by upstream provider. This adds api_provider to the token metrics (litellm_input_tokens_metric, litellm_output_tokens_metric, litellm_total_tokens_metric), the latency metrics (litellm_llm_api_latency_metric, litellm_llm_api_time_to_first_token_metric, litellm_request_total_latency_metric, litellm_request_queue_time_seconds), the proxy request counters (litellm_proxy_total_requests_metric, litellm_proxy_failed_requests_metric) and the cache metrics.

The cache label is added to the shared _cache_metric_labels list, so the change covers all five metrics that use it: litellm_cache_hits_metric, litellm_cache_misses_metric, litellm_cached_tokens_metric, litellm_provider_cache_read_input_tokens_metric and litellm_provider_cache_creation_input_tokens_metric. The label-presence test asserts every one of them.

On the success path no new plumbing is needed; enum_values.api_provider is already populated from standard_logging_payload["custom_llm_provider"], so the value flows through as soon as the label is in the metric's list. For the client-side failure path, where a request can fail before a deployment resolves, the provider is derived best-effort from litellm_params.custom_llm_provider, then a partial standard_logging_object, then inference from the requested model name via litellm.get_llm_provider, falling back to empty rather than guessing.

Credit

Adopted from #32043 by @shivijain2323. Mirrored onto a litellm_ branch so CircleCI and the internal lint workflow run. All commits preserve the original author metadata. A new oss-adoption label was added to this PR to mark it as an adopted external contribution.

Summary by CodeRabbit

  • New Features

    • Prometheus metrics now include api_provider labels where available, improving visibility into which provider handled a request.
    • Provider values can now be inferred more reliably when they aren’t explicitly set.
  • Bug Fixes

    • Failure-path metrics now populate api_provider instead of leaving it blank.
    • Broadened label coverage so related metrics stay consistent across latency, tokens, cache, and queue events.

Note

Medium Risk
Prometheus metric label schemas change at logger init, which can affect dashboards and series cardinality; runtime risk is low because provider inference is best-effort and errors are swallowed.

Overview
Adds api_provider to Prometheus label sets for token, latency, proxy request, and cache metrics so they align with spend/request metrics and can be sliced by upstream provider (LIT-4178).

On success, values already flow from custom_llm_provider via UserAPIKeyLabelValues; this PR only extends each metric’s allowed labels (including shared _cache_metric_labels). On client-side failure, a new _extract_api_provider_from_request_data helper sets the label from litellm_params.custom_llm_provider, partial standard_logging_object, or get_llm_provider(model) inference, returning empty when unknown so labeling never breaks the failure path.

Tests cover label definitions, factory wiring, the extractor, and end-to-end emits on success and failure hooks.

Reviewed by Cursor Bugbot for commit be63de1. Bugbot is set up for automated code reviews on this repo. Configure here.

…nd cache metrics

The token (input/output/total), latency (llm_api, time_to_first_token,
request_total, request_queue_time), proxy request (total/failed) and cache
metrics were emitted from the same call sites as litellm_spend_metric and
litellm_requests_metric, which already carry api_provider, yet these were
missing it. That left no way to break tokens, latency, request counts or cache
hits down by upstream provider even though the provider is already on the
payload as custom_llm_provider.

Add api_provider to each metric's label allow-list. The success path already
populates enum_values.api_provider from standard_logging_payload, so those
metrics emit it with no further plumbing. The cache label is added to the
shared _cache_metric_labels list, so alongside litellm_cache_hits_metric and
litellm_cache_misses_metric it also covers litellm_cached_tokens_metric and the
provider prompt-cache read/creation token metrics; the label-presence test
asserts all of them. For the client-side failure path, where a deployment may
not have been resolved, derive it best-effort from
litellm_params.custom_llm_provider, a partial standard_logging_object, or
inference from the requested model name via litellm.get_llm_provider, falling
back to empty rather than guessing.

Resolves LIT-4178
@yucheng-berri yucheng-berri added the oss-adoption PR mirrors an external contributor's PR onto a litellm_ branch label Jul 4, 2026
@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an api_provider label to Prometheus metrics. A new helper infers the provider from request data (custom_llm_provider or model lookup) and is wired into the failure hook. Default label sets for latency, queue, token, request, and cache metrics are extended with API_PROVIDER, plus corresponding tests.

Changes

API Provider Label Propagation

Layer / File(s) Summary
Provider extraction and failure hook wiring
litellm/integrations/prometheus.py
Adds _extract_api_provider_from_request_data to resolve provider from litellm_params, standard_logging_object, or model inference (with BadRequestError swallowing); wires the result into async_post_call_failure_hook's UserAPIKeyLabelValues.
Default label list updates
litellm/types/integrations/prometheus.py
Adds API_PROVIDER to default label lists for latency/queue, proxy request, token (input/total/output), and shared cache metric label sets.
Tests for extraction and metric emission
tests/test_litellm/integrations/test_prometheus_labels.py
Adds registry helpers and tests validating label presence across metrics, label factory value propagation, extraction resolution/error handling, and end-to-end success/failure hook emission with api_provider="openai".

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Proxy
  participant PrometheusLogger
  participant LiteLLM as litellm.get_llm_provider

  Proxy->>PrometheusLogger: async_post_call_failure_hook(request_data)
  PrometheusLogger->>PrometheusLogger: _extract_api_provider_from_request_data(request_data)
  alt custom_llm_provider present
    PrometheusLogger-->>PrometheusLogger: resolve from litellm_params/standard_logging_object
  else model name present
    PrometheusLogger->>LiteLLM: get_llm_provider(model)
    LiteLLM-->>PrometheusLogger: provider or BadRequestError (swallowed)
  end
  PrometheusLogger->>PrometheusLogger: build UserAPIKeyLabelValues(api_provider)
  PrometheusLogger-->>Proxy: emit litellm_proxy_failed_requests_metric, litellm_proxy_total_requests_metric
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main change: adding api_provider labels to Prometheus token, latency, request, and cache metrics.
Description check ✅ Passed The PR description matches the template and includes issues, checklist, screenshots, type, and change summary, with Linear intentionally blank.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch litellm_prometheus_api_provider_labels

Comment @coderabbitai help to get the list of available commands.

@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@coderabbitai help

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai rate limit to show your current review rate limit status.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai emit path instructions to emit generated path-specific review instructions for this repository.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds the api_provider label to a set of Prometheus metrics (token, latency, proxy request counters, cache) that were previously missing it, while sibling metrics emitted from the same call sites already carried it. A new _extract_api_provider_from_request_data helper handles the failure path with a priority chain and safe fallbacks.

  • Label additions (litellm/types/integrations/prometheus.py): api_provider appended to litellm_llm_api_latency_metric, litellm_llm_api_time_to_first_token_metric, litellm_request_total_latency_metric, litellm_request_queue_time_seconds, litellm_proxy_total_requests_metric, litellm_proxy_failed_requests_metric, the three token metrics, and the shared _cache_metric_labels list (covering all five cache metrics).
  • Failure-path plumbing (litellm/integrations/prometheus.py): _extract_api_provider_from_request_data resolves the provider from litellm_params.custom_llm_provider, a partial standard_logging_object, or litellm.get_llm_provider inference, returning None rather than guessing when nothing maps.
  • Tests: both label-list assertions and full end-to-end emit tests added; existing enterprise mock tests updated to supply the new api_provider argument.

Confidence Score: 5/5

The code changes are logically correct and well-tested; prior review threads have already surfaced and discussed the label-schema migration concern at length, so the maintainer is informed on that front.

The new helper method has a sound priority chain and safe fallbacks, all branches are exercised by unit tests, and the label-list additions are consistent with how the rest of the file is structured. The concerns raised in previous review rounds are tracked and the author is aware of them.

No files require additional attention beyond what was discussed in prior threads.

Important Files Changed

Filename Overview
litellm/types/integrations/prometheus.py Adds api_provider to label lists for 10+ long-lived metrics; correct but this is a breaking label-schema change for existing deployments (covered in prior review threads)
litellm/integrations/prometheus.py Adds _extract_api_provider_from_request_data with well-structured priority chain (litellm_params → standard_logging_object → model inference) and safe fallback; populates api_provider in the failure hook enum_values
tests/enterprise/litellm_enterprise/enterprise_callbacks/test_prometheus_logging_callbacks.py Existing mock-based tests updated to include api_provider="openai" where required by the new label signature; changes are additive and don't weaken existing assertions
tests/test_litellm/integrations/test_prometheus_labels.py New end-to-end tests drive the real logger and assert api_provider in collected samples; registry teardown uses a private prometheus_client attribute (flagged in prior threads)

Reviews (4): Last reviewed commit: "fix(prometheus): satisfy ruff BLE001 bud..." | Re-trigger Greptile

@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds the api_provider label to a set of Prometheus metrics that previously lacked it — covering latency, token, proxy request-counter, and cache metrics — so that all metrics emitted from the same call sites as litellm_spend_metric and litellm_requests_metric now share consistent label cardinality. A new _extract_api_provider_from_request_data helper provides best-effort provider resolution on the failure path when a request aborts before a deployment is selected.

  • Label additions in prometheus.py types: api_provider is appended to litellm_llm_api_latency_metric, litellm_llm_api_time_to_first_token_metric, litellm_request_total_latency_metric, litellm_request_queue_time_seconds, litellm_proxy_total_requests_metric, litellm_proxy_failed_requests_metric, litellm_input_tokens_metric, litellm_total_tokens_metric, litellm_output_tokens_metric, and the shared _cache_metric_labels list (covering five cache metrics).
  • Failure-path plumbing: New _extract_api_provider_from_request_data static method resolves the provider from litellm_params, then a partial standard_logging_object, then model-name inference via litellm.get_llm_provider, falling back to None to emit an empty label rather than a guess.
  • Tests: New unit and async integration tests cover label-list presence, factory value plumbing, the extraction helper's fallback chain, and end-to-end emit wiring for both the success and failure hooks.

Confidence Score: 3/5

Merging as-is will silently break existing Grafana dashboards and alert rules the moment the first scrape arrives after upgrade, because adding labels to existing Prometheus metrics creates new time series while old data retains the original label set.

The failure-path helper and the test suite are well-constructed, but the label additions to 10+ live metrics are unconditional. The project already has a documented opt-in mechanism for exactly this situation — the rate-limit and stream labels are both gated behind module-level flags specifically to preserve existing dashboard compatibility across upgrades.

litellm/types/integrations/prometheus.py — all the label-list additions should be reviewed against the opt-in flag pattern before merge.

Important Files Changed

Filename Overview
litellm/types/integrations/prometheus.py Adds api_provider to 10+ existing metric label lists unconditionally, including latency, token, request-counter, and cache metrics. This changes the cardinality of long-lived series and will break existing dashboards on upgrade without an opt-in flag.
litellm/integrations/prometheus.py Adds _extract_api_provider_from_request_data static method with a well-ordered fallback chain and wires the result into the failure hook's UserAPIKeyLabelValues. Logic is clean and error-safe.
tests/test_litellm/integrations/test_prometheus_labels.py Comprehensive test additions covering label-list presence, factory plumbing, failure-path extraction, and end-to-end emit wiring. The _clear_prometheus_registry helper uses a private prometheus_client attribute.

Reviews (1): Last reviewed commit: "feat(prometheus): add api_provider label..." | Re-trigger Greptile

UserAPIKeyLabelNames.END_USER.value,
UserAPIKeyLabelNames.USER.value,
UserAPIKeyLabelNames.MODEL_ID.value,
UserAPIKeyLabelNames.API_PROVIDER.value,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Backward-incompatible label addition without an opt-in flag

Adding api_provider to these established metrics (token, latency, proxy request counters, cache) changes their label cardinality. In Prometheus, a metric's label set is fixed at registration time — upgrading litellm registers new timeseries that carry the extra label, while the old labelset timeseries stop receiving data. Any existing Grafana panel or PromQL alert that queries litellm_llm_api_latency_metric, litellm_total_tokens_metric, litellm_proxy_failed_requests_metric, or the cache metrics by their current label set will show a gap at the upgrade boundary, and aggregations will silently produce incorrect totals until dashboards are updated.

Other label additions in this codebase (stream label, rate-limit labels) were gated behind litellm.prometheus_emit_stream_label / litellm.prometheus_emit_rate_limit_labels precisely to let operators adopt the new cardinality on their own schedule. The same mechanism should apply here — a litellm.prometheus_emit_api_provider_label (defaulting to False) would let get_labels_for_metric include api_provider only when explicitly enabled, keeping existing dashboards intact until users are ready to migrate.

Rule Used: What: avoid backwards-incompatible changes without... (source)

Comment on lines +14 to +20
from prometheus_client import REGISTRY

for collector in list(REGISTRY._collector_to_names.keys()):
try:
REGISTRY.unregister(collector)
except Exception:
pass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Private registry attribute used in test helper

REGISTRY._collector_to_names is a private implementation detail of prometheus_client, not part of the public API. Its name and structure have changed across minor releases and could change again. If the attribute is renamed or its type changes, this helper silently becomes a no-op (the try/except swallows any AttributeError), leaving metrics registered and causing subsequent tests to fail with ValueError: Duplicated timeseries. Using a per-test CollectorRegistry instance passed explicitly to metric constructors would be more robust.

Comment on lines 285 to 287
UserAPIKeyLabelNames.MODEL_ID.value,
UserAPIKeyLabelNames.API_PROVIDER.value,
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Unconditional label addition breaks existing dashboards on upgrade

The project already has an established pattern for exactly this scenario: litellm.prometheus_emit_rate_limit_labels and litellm.prometheus_emit_stream_label are opt-in flags used precisely because "existing dashboards keyed on this metric's historical label set [must] keep matching after upgrade" (see the comment in litellm_proxy_failed_requests_metric). Adding api_provider unconditionally to 10+ long-lived metrics — including litellm_llm_api_latency_metric, litellm_total_tokens_metric, litellm_cache_hits_metric and the others — changes their time-series fingerprint on the first scrape after upgrade. Every Grafana panel, alert rule, and recording rule that references these metrics by label equality will immediately start matching nothing (old series have no api_provider label; new series carry it), causing silent gaps or broken alerting for all existing deployments. The same label addition should be gated on an opt-in flag (e.g. litellm.prometheus_emit_api_provider_label, defaulting to False) and wired through PrometheusMetricLabels.get_labels the same way the rate-limit and stream labels are today.

Rule Used: What: avoid backwards-incompatible changes without... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +13 to +20
def _clear_prometheus_registry() -> None:
from prometheus_client import REGISTRY

for collector in list(REGISTRY._collector_to_names.keys()):
try:
REGISTRY.unregister(collector)
except Exception:
pass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Private internal attribute accessed in test helper

REGISTRY._collector_to_names is a private implementation detail of prometheus_client — the leading underscore signals it is not part of the public API and may be renamed or removed without notice. The prometheus_client library does expose CollectorRegistry.unregister, so the teardown logic itself is sound; only the attribute used to enumerate collectors is fragile.

@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds api_provider to nine previously-unlabelled Prometheus metrics (token, latency, request-counter, and cache metrics) so they are consistent with litellm_spend_metric and litellm_requests_metric, which already carry it. A new static helper _extract_api_provider_from_request_data supplies the value on the client-side failure path via a litellm_params → standard_logging_object → model-name-inference fallback chain.

  • litellm/types/integrations/prometheus.pyapi_provider appended to the label lists for the latency, token, request-counter, and _cache_metric_labels groups (covering all five cache metrics).
  • litellm/integrations/prometheus.py — new _extract_api_provider_from_request_data static method wires the provider into async_post_call_failure_hook; the success path required no new plumbing because enum_values.api_provider already reads from the standard logging payload.
  • tests/test_litellm/integrations/test_prometheus_labels.py — six new tests covering label-list assertions, factory value flow, helper extraction logic, error-swallowing behaviour, and end-to-end emit wiring for both the success and failure hooks.

Confidence Score: 4/5

Safe to merge with awareness that adding new labels to long-running metrics causes a time-series gap in existing Prometheus deployments; the code logic and test coverage are solid.

The provider extraction helper is well-structured with a sensible fallback chain and correct exception handling. The nine metrics that gain api_provider are all in the label-schema category, not the core request path, and the success-path wiring required no new production plumbing. The main concern is that existing Prometheus/Grafana deployments will see old time series (without api_provider) stop receiving data and fresh series appear after upgrading, producing a visible gap in dashboards and potentially causing alert flap during the transition window. A changelog entry or feature flag to opt out would reduce the risk for existing users.

litellm/types/integrations/prometheus.py — the label additions affect nine metrics and the time-series discontinuity impact is concentrated here.

Important Files Changed

Filename Overview
litellm/integrations/prometheus.py Adds _extract_api_provider_from_request_data static method and wires api_provider into the failure-path enum_values; logic is correct with proper fallback chain and exception handling.
litellm/types/integrations/prometheus.py Adds api_provider label to 9 metrics (latency, token, request counter, and cache metrics via shared _cache_metric_labels); the change is a breaking label-schema update for existing Prometheus deployments.
tests/test_litellm/integrations/test_prometheus_labels.py Adds 6 new unit tests covering label presence, value flow through the factory, failure-path extraction, and end-to-end emit wiring; tests are mock-only with no real network calls, but the registry helper accesses a private prometheus_client attribute.

Reviews (3): Last reviewed commit: "feat(prometheus): add api_provider label..." | Re-trigger Greptile

Comment on lines +13 to +20
def _clear_prometheus_registry() -> None:
from prometheus_client import REGISTRY

for collector in list(REGISTRY._collector_to_names.keys()):
try:
REGISTRY.unregister(collector)
except Exception:
pass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Private internal attribute used in test helper

REGISTRY._collector_to_names is an undocumented private attribute of prometheus_client's CollectorRegistry. It has changed in past minor releases and could silently break these tests if prometheus_client is upgraded. A more version-stable alternative is to use a fresh CollectorRegistry per test (pass it to PrometheusLogger if the constructor supports it) or iterate over list(REGISTRY._names_to_collectors.values()) and unregister by collector reference — but both of those are still private. The safest pattern is to instantiate an isolated CollectorRegistry(auto_describe=False) and pass it through rather than mutating the global singleton.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines 283 to 285
UserAPIKeyLabelNames.END_USER.value,
UserAPIKeyLabelNames.USER.value,
UserAPIKeyLabelNames.MODEL_ID.value,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Label schema change causes time-series discontinuity in existing deployments

Adding api_provider to metrics that have been emitting without it (e.g. litellm_llm_api_latency_metric, litellm_proxy_total_requests_metric, the token metrics) is a breaking change for any deployment that has been scraping litellm's Prometheus endpoint. Prometheus identifies a time series by its metric name plus its full label set, so every existing series for these metrics will stop receiving new data points after the upgrade and a fresh set of series (with api_provider included) will begin. Dashboards and alert rules that reference the old series will see a data gap at the upgrade boundary. Per the repo's backwards-compatibility policy, a feature flag (e.g. litellm.prometheus_emit_api_provider_label) that defaults to True for new installs but can be set to False for existing ones would let current users opt out of the label addition until they are ready to migrate their dashboards. At minimum, this change should be prominently called out in the changelog as a breaking label-schema change.

Rule Used: What: avoid backwards-incompatible changes without... (source)

@codecov

codecov Bot commented Jul 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/test_litellm/integrations/test_prometheus_labels.py (1)

159-172: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer constructing/injecting a real object over binding methods onto a MagicMock.

prometheus_logger is a bare MagicMock() with _cached_metric_labels/label_filters set manually and get_labels_for_metric bound via __get__. Any attribute the real method touches that isn't explicitly stubbed silently resolves to another MagicMock instead of failing, which can mask future integration breakage. A minimal real instance (bypassing __init__ side effects) or a small dependency-injected fake would be more faithful to the production object.

As per path instructions, "Prefer dependency injection over monkeypatching class attributes in tests; pass mocked dependencies into classes instead."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_litellm/integrations/test_prometheus_labels.py` around lines 159 -
172, Replace the bare MagicMock-based setup for prometheus_logger in
test_prometheus_labels with a minimal real PrometheusLogger instance or a small
injected fake, so get_labels_for_metric is exercised against a faithful object
instead of a mock that auto-creates missing attributes. Keep the test focused on
PrometheusLogger.get_labels_for_metric and prometheus_label_factory, and
initialize only the specific dependencies/state the real method needs rather
than binding the method onto MagicMock via __get__.

Source: Path instructions

litellm/types/integrations/prometheus.py (1)

334-371: 🚀 Performance & Scalability | 🔵 Trivial

New api_provider label is unconditional, unlike the neighboring rate-limit labels on the same metric.

The comment directly above (lines 362-365) explains that rate_limit_category/rate_limit_type were deliberately kept opt-in on litellm_proxy_failed_requests_metric specifically to avoid changing this metric's historical label set for existing dashboards/alerts. api_provider is added unconditionally here instead, so litellm_proxy_total_requests_metric and litellm_proxy_failed_requests_metric (two of the highest-volume metrics) get a new label dimension by default on upgrade — this is presumably intentional per the PR's goal, but worth calling out for anyone relying on a fixed label/cardinality set for these two metrics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@litellm/types/integrations/prometheus.py` around lines 334 - 371, The new
api_provider label is being added unconditionally to
litellm_proxy_total_requests_metric and litellm_proxy_failed_requests_metric,
which changes the existing label set for these high-volume metrics. Update the
metric label definitions in prometheus.py so api_provider follows the same
opt-in pattern as the rate-limit labels, and only gets appended in get_labels()
when explicitly enabled. Keep the existing symbol names aligned with
UserAPIKeyLabelNames and the two metric lists so dashboards and alerts retain
their historical cardinality by default.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@litellm/types/integrations/prometheus.py`:
- Around line 334-371: The new api_provider label is being added unconditionally
to litellm_proxy_total_requests_metric and litellm_proxy_failed_requests_metric,
which changes the existing label set for these high-volume metrics. Update the
metric label definitions in prometheus.py so api_provider follows the same
opt-in pattern as the rate-limit labels, and only gets appended in get_labels()
when explicitly enabled. Keep the existing symbol names aligned with
UserAPIKeyLabelNames and the two metric lists so dashboards and alerts retain
their historical cardinality by default.

In `@tests/test_litellm/integrations/test_prometheus_labels.py`:
- Around line 159-172: Replace the bare MagicMock-based setup for
prometheus_logger in test_prometheus_labels with a minimal real PrometheusLogger
instance or a small injected fake, so get_labels_for_metric is exercised against
a faithful object instead of a mock that auto-creates missing attributes. Keep
the test focused on PrometheusLogger.get_labels_for_metric and
prometheus_label_factory, and initialize only the specific dependencies/state
the real method needs rather than binding the method onto MagicMock via __get__.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cba8b9f9-54ac-41ff-bfc5-59802ee64f27

📥 Commits

Reviewing files that changed from the base of the PR and between 47f493a and 9658382.

📒 Files selected for processing (3)
  • litellm/integrations/prometheus.py
  • litellm/types/integrations/prometheus.py
  • tests/test_litellm/integrations/test_prometheus_labels.py

…el assertions

- Suppress the strict-rule BLE001 budget breach with a justified noqa;
  the broad except in the failure-path provider extraction is
  intentional defense-in-depth (covered by
  test_extract_api_provider_swallows_unknown_model_but_logs_unexpected_errors),
  not dead code to delete
- Update tests/enterprise assertions for litellm_tokens_metric,
  litellm_input_tokens_metric, litellm_output_tokens_metric, the three
  latency metrics, and the proxy request counters to expect the new
  api_provider label, matching what litellm_mapped_enterprise_tests
  caught in CI
@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@yucheng-berri

Copy link
Copy Markdown
Contributor Author

ci/circleci: image_gen_testing is failing here, but it is also failing on the current tip of litellm_internal_staging (commit 47f493a, which this branch is based on and rebased onto), with an identical failure. This PR does not touch any image-generation code, so this is a pre-existing base-branch failure, not something introduced here.

@yucheng-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit be63de1. Configure here.

try:
return litellm.get_llm_provider(model=model)[1] or None
except litellm.exceptions.BadRequestError:
return None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failure path misses provider fields

Medium Severity

_extract_api_provider_from_request_data only reads custom_llm_provider from nested litellm_params and from a top-level standard_logging_object. On the proxy client failure path, post_call_failure_hook drops litellm_logging_obj without copying that payload onto request_data, so resolved provider data that still lives on the logging object never reaches the extractor and api_provider can stay empty when model-name inference fails.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit be63de1. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of scope

@mateo-berri mateo-berri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; thanks!

@yucheng-berri
yucheng-berri merged commit 7a6a070 into litellm_internal_staging Jul 4, 2026
127 checks passed
@yucheng-berri
yucheng-berri deleted the litellm_prometheus_api_provider_labels branch July 4, 2026 22:16
Bungic added a commit to Bungic/litellm-fork that referenced this pull request Jul 26, 2026
Chat completions, embeddings, image generation and audio all land in the same
litellm_requests_metric and litellm_spend_metric series today. Embedding traffic
is usually orders of magnitude higher volume and orders of magnitude lower cost
than chat, so mixing them makes both the request rate and the spend series hard
to reason about. The value is already on standard_logging_payload as call_type,
so this is label plumbing rather than new collection.

Async and sync entry points report different call types for the same operation,
acompletion against completion, and the proxy is async while the SDK usually is
not. Emitting both spellings would split every proxy's chat traffic in two, so
each async call type is collapsed onto its sync twin. The alias table is derived
from CallTypes at import time and matches on member names rather than values:
stripping a leading "a" from the value would turn add_message into dd_message
and anthropic_messages into nthropic_messages, both of which are sync call types
that legitimately start with one.

16 metrics gain the label. Remaining-quota gauges and the configured tpm/rpm
limits deliberately do not, since headroom belongs to a deployment rather than
to a call type and splitting it would emit several series each claiming to
describe the same number. A test pins that exclusion.

Same shape as BerriAI#32126, which added api_provider to the metrics emitted from call
sites that already held the value.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

oss-adoption PR mirrors an external contributor's PR onto a litellm_ branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants