Feat - Add organization into the metrics metadata for org_id & org_alias - #24440
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR adds Key observations:
Confidence Score: 3/5Caution advised — the org label injection unconditionally changes the cardinality of 11 existing Prometheus metrics, which is a breaking change for any user already consuming these metrics. The functional implementation is sound (DB query, model field, metadata propagation, and safe .get() reads are all correct). However, the unconditional addition of two new label dimensions to 11 existing, widely-used Prometheus metrics without a feature flag violates the project's backwards-compatibility policy and will silently break existing dashboards and alerting rules for current users on upgrade. Gating the new labels behind a flag (similar to prometheus_emit_stream_label) would resolve this concern and raise the score to 4-5. litellm/types/integrations/prometheus.py — the _org_label_metrics frozenset approach needs a feature flag before this can be considered safe to merge for existing deployments.
|
| Filename | Overview |
|---|---|
| litellm/integrations/prometheus.py | Adds org_id and org_alias to UserAPIKeyLabelValues construction in both success and failure emission paths; uses .get() safely for metadata reads |
| litellm/proxy/_types.py | Adds organization_alias: Optional[str] = None to LiteLLM_VerificationTokenView, making it available on UserAPIKeyAuth instances via inheritance |
| litellm/proxy/litellm_pre_call_utils.py | Adds user_api_key_org_alias to StandardLoggingUserAPIKeyMetadata construction via user_api_key_dict.organization_alias |
| litellm/proxy/proxy_server.py | Adds user_api_key_org_alias unconditionally to request metadata in chat_completion, completion, and embeddings handlers — inconsistent with conditional org_id pattern |
| litellm/proxy/utils.py | Extends the verification token SQL query to fetch organization_alias from LiteLLM_OrganizationTable, enabling DB-backed population of the new field |
| litellm/types/integrations/prometheus.py | Introduces _org_label_metrics frozenset that unconditionally appends org_id/org_alias to 11 existing metrics via get_labels(), a backwards-incompatible label schema change without a feature flag |
| litellm/types/utils.py | Adds user_api_key_org_alias: Optional[str] to StandardLoggingUserAPIKeyMetadata TypedDict, correctly extending the schema |
| tests/test_litellm/integrations/test_prometheus_user_team_metrics.py | New test verifies org labels appear in per-request metrics and are absent from non-org metrics; also checks deduplication with custom_prometheus_metadata_labels |
| tests/test_litellm/integrations/test_prometheus_client_ip_user_agent.py | Existing test updated to include the two new TypedDict keys (org_id/org_alias as None) in the metadata fixture — necessary schema update, no coverage regression |
Sequence Diagram
sequenceDiagram
participant Client
participant ProxyServer
participant PreCallUtils
participant DB
participant Prometheus
Client->>ProxyServer: POST /chat/completions
ProxyServer->>DB: get_data(token) with org alias JOIN
DB-->>ProxyServer: UserAPIKeyAuth (organization_alias populated)
ProxyServer->>ProxyServer: set org_alias in request metadata
ProxyServer->>PreCallUtils: get_sanitized_user_information_from_key()
PreCallUtils->>PreCallUtils: build StandardLoggingUserAPIKeyMetadata (includes user_api_key_org_alias)
PreCallUtils-->>ProxyServer: standard_logging_payload with org metadata
ProxyServer->>Prometheus: async_log_success_event(payload)
Prometheus->>Prometheus: read org_alias via metadata.get()
Prometheus->>Prometheus: build UserAPIKeyLabelValues with org fields
Prometheus->>Prometheus: get_labels() appends org_id and org_alias for metrics in _org_label_metrics frozenset
Prometheus->>Prometheus: emit litellm_requests_metric with org labels
ProxyServer->>Prometheus: async_log_failure_event(user_api_key_dict)
Prometheus->>Prometheus: read org fields from user_api_key_dict directly
Prometheus->>Prometheus: emit litellm_proxy_failed_requests_metric with org labels
Comments Outside Diff (1)
-
litellm/proxy/proxy_server.py, line 7015 (link)Inconsistent conditional guard for
org_aliasvsorg_iduser_api_key_org_idis only written todata["metadata"]when it is notNone(guarded by bothhasattrand a not-Nonecheck), butuser_api_key_org_aliasis written unconditionally — even whenorganization_aliasisNone. This means the metadata dict will sometimes contain the key"user_api_key_org_alias"with valueNonewhile the key"user_api_key_org_id"is entirely absent. The same pattern is repeated in all three handlers (chat_completion,completion,embeddings).This is inconsistent and can be surprising for any custom callback that reads from
data["metadata"]expecting the same presence/absence semantics for both fields. Consider aligning the guard:The same fix should be applied at the corresponding lines in the
completion(~line 7190) andembeddings(~line 7433) handlers as well.
Reviews (15): Last reviewed commit: "fix: write org_alias to metadata uncondi..." | Re-trigger Greptile
| user_api_key_project_id=user_api_key_dict.project_id, | ||
| user_api_key_user_id=user_api_key_dict.user_id, | ||
| user_api_key_org_id=user_api_key_dict.org_id, | ||
| user_api_key_org_alias=None, |
There was a problem hiding this comment.
org_alias is always hardcoded to None
user_api_key_org_alias is unconditionally set to None here. UserAPIKeyAuth (and its parents LiteLLM_VerificationTokenView / LiteLLM_VerificationToken) do not have an org_alias field — the org alias is only extracted transiently from JWT tokens in handle_jwt.py and is used solely to resolve an org_id via a DB lookup, but never stored in UserAPIKeyAuth.
As a result, the org_alias Prometheus label will always be None for every metric emission, making the feature effectively a no-op. To fix this:
- Add an
org_alias: Optional[str]field toLiteLLM_VerificationTokenView(orUserAPIKeyAuth). - Populate it during JWT auth in
handle_jwt.pywhereorg_aliasis resolved (around line 1151). - Then use
user_api_key_dict.org_aliashere instead ofNone.
| UserAPIKeyLabelNames.API_KEY_ALIAS.value, | ||
| UserAPIKeyLabelNames.TEAM.value, | ||
| UserAPIKeyLabelNames.TEAM_ALIAS.value, | ||
| UserAPIKeyLabelNames.ORG_ID.value, | ||
| UserAPIKeyLabelNames.ORG_ALIAS.value, | ||
| UserAPIKeyLabelNames.REQUESTED_MODEL.value, | ||
| UserAPIKeyLabelNames.END_USER.value, | ||
| UserAPIKeyLabelNames.USER.value, |
There was a problem hiding this comment.
Breaking change to existing Prometheus metric label schemas
Adding org_id and org_alias to all of these existing metric label lists (across litellm_llm_api_latency_metric, litellm_requests_metric, litellm_spend_metric, litellm_total_tokens_metric, etc.) is a backwards-incompatible change for anyone already running LiteLLM with Prometheus.
In Prometheus, a metric's identity is defined by its name and its complete set of label names. When label names change, the old time-series become orphaned and any existing dashboards or alerting rules that query these metrics by label set will break silently. This violates the pattern of avoiding backwards-incompatible changes without user-controlled flags (e.g. a litellm.prometheus_emit_org_labels feature flag, similar to how litellm.prometheus_emit_stream_label controls the stream label).
Consider gating the new labels behind a feature flag, similar to the existing prometheus_emit_stream_label pattern visible in prometheus.py.
| user_api_key_org_id = standard_logging_payload["metadata"]["user_api_key_org_id"] | ||
| user_api_key_org_alias = standard_logging_payload["metadata"][ | ||
| "user_api_key_org_alias" | ||
| ] |
There was a problem hiding this comment.
Direct key access for new field risks
KeyError
user_api_key_org_alias is accessed with ["user_api_key_org_alias"] (direct dict access) rather than .get("user_api_key_org_alias"). Any StandardLoggingPayload whose metadata was not built through litellm_pre_call_utils.get_sanitized_user_information_from_key (e.g. pass-through endpoints, cost-tracking callback) will not have this key in the dict, raising a KeyError that silently swallows the entire Prometheus metric recording.
Using .get() is the safer approach here and matches how other optional fields are read elsewhere in this class:
| user_api_key_org_id = standard_logging_payload["metadata"]["user_api_key_org_id"] | |
| user_api_key_org_alias = standard_logging_payload["metadata"][ | |
| "user_api_key_org_alias" | |
| ] | |
| user_api_key_org_id = standard_logging_payload["metadata"].get("user_api_key_org_id") | |
| user_api_key_org_alias = standard_logging_payload["metadata"].get( | |
| "user_api_key_org_alias" | |
| ) |
…e .get() for org metadata
…orphaned budget label defs, add test teardown
@J-Byron why is this feature flagged? cc: @shivamrawat1 was this part of the user request? Ideally we avoid more user flags - as it requires more building - e.g. how does a user on the ui enable this? |
|
@J-Byron @krrish-berri-2 is right. They should be added by default in the metrics. We already have advanced settings if more granular control of labels is needed. https://docs.litellm.ai/docs/proxy/prometheus#configuring-metrics-and-labels https://docs.litellm.ai/docs/proxy/prometheus#configuring-metrics-and-labels please fix to follow the same pattern |
…n all metadata paths
@krrish-berri-2 @shivamrawat1
|
4ca7a99
into
BerriAI:litellm_oss_staging_04_02_2026_p1
…ias (#24440) * Add org_id and org_alias label names to Prometheus metric definitions * Add user_api_key_org_alias to StandardLoggingUserAPIKeyMetadata * Populate user_api_key_org_alias in pre-call metadata * Pass org_id and org_alias into per-request Prometheus metric labels * Add test for org labels on per-request Prometheus metrics * chore: resolve test mockdata * Address review: populate org_alias from DB view, add feature flag, use .get() for org metadata * Add org labels to failure path and verify flag behavior in test * Fix test: build flag-off enum_values without org fields * Gate org labels behind feature flag in get_labels() instead of static metric lists * Scope org label injection to metrics that carry team context, remove orphaned budget label defs, add test teardown * Use explicit metric allowlist for org label injection instead of team heuristic * Fix duplicate org label guard, move _org_label_metrics to class constant * Reset custom_prometheus_metadata_labels after duplicate label assertion * fix: emit org labels by default, remove flag, fix missing org_alias in all metadata paths * fix: emit org labels by default, no opt-in flag required * fix: write org_alias to metadata unconditionally in proxy_server.py
* fix(vertex_ai): support pluggable (executable) credential_source for WIF auth (#24700) The WIF credential dispatch in load_auth() only handled identity_pool and aws credential types. When credential_source.executable was present (used for Azure Managed Identity via Workload Identity Federation), it fell through to identity_pool.Credentials which rejected it with MalformedError. Add dispatch to google.auth.pluggable.Credentials for executable-type credential sources, following the same pattern as the existing identity_pool and aws helpers. Fixes authentication for Azure Container Apps → GCP Vertex AI via WIF with executable credential sources. * feat(logging): add component and logger fields to JSON logs for 3rd p… (#24447) * feat(logging): add component and logger fields to JSON logs for 3rd party filtering * Let user-supplied extra fields win over auto-generated component/logger, tighten test assertions * Feat - Add organization into the metrics metadata for org_id & org_alias (#24440) * Add org_id and org_alias label names to Prometheus metric definitions * Add user_api_key_org_alias to StandardLoggingUserAPIKeyMetadata * Populate user_api_key_org_alias in pre-call metadata * Pass org_id and org_alias into per-request Prometheus metric labels * Add test for org labels on per-request Prometheus metrics * chore: resolve test mockdata * Address review: populate org_alias from DB view, add feature flag, use .get() for org metadata * Add org labels to failure path and verify flag behavior in test * Fix test: build flag-off enum_values without org fields * Gate org labels behind feature flag in get_labels() instead of static metric lists * Scope org label injection to metrics that carry team context, remove orphaned budget label defs, add test teardown * Use explicit metric allowlist for org label injection instead of team heuristic * Fix duplicate org label guard, move _org_label_metrics to class constant * Reset custom_prometheus_metadata_labels after duplicate label assertion * fix: emit org labels by default, remove flag, fix missing org_alias in all metadata paths * fix: emit org labels by default, no opt-in flag required * fix: write org_alias to metadata unconditionally in proxy_server.py * fix: 429s from batch creation being converted to 500 (#24703) * add us gov models (#24660) * add us gov models * added max tokens * Litellm dev 04 02 2026 p1 (#25052) * fix: replace hardcoded url * fix: Anthropic web search cost not tracked for Chat Completions The ModelResponse branch in response_object_includes_web_search_call() only checked url_citation annotations and prompt_tokens_details, missing Anthropic's server_tool_use.web_search_requests field. This caused _handle_web_search_cost() to never fire for Anthropic Claude models. Also routes vertex_ai/claude-* models to the Anthropic cost calculator instead of the Gemini one, since Claude on Vertex uses the same server_tool_use billing structure as the direct Anthropic API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(anthropic): pass logging_obj to client.post for litellm_overhead_time_ms (#24071) When LITELLM_DETAILED_TIMING=true, litellm_overhead_time_ms was null for Anthropic because the handler did not pass logging_obj to client.post(), so track_llm_api_timing could not set llm_api_duration_ms. Pass logging_obj=logging_obj at all four post() call sites (make_call, make_sync_call, acompletion, completion). Add test to ensure make_call passes logging_obj to client.post. Made-with: Cursor * sap - add additional parameters for grounding - additional parameter for grounding added for the sap provider * sap - fix models * (sap) add filtering, masking, translation SAP GEN AI Hub modules * (sap) add tests and docs for new SAP modules * (sap) add support of multiple modules config * (sap) code refactoring * (sap) rename file * test(): add safeguard tests * (sap) update tests * (sap) update docs, solve merge conflict in transformation.py * (sap) linter fix * (sap) Align embedding request transformation with current API * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) mock commit * (sap) run black formater * (sap) add literals to models, add negative tests, fix test for tool transformation * (sap) fix formating * (sap) fix models * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) commit for rerun bot review * (sap) minor improve * (sap) fix after bot review * (sap) lint fix * docs(sap): update documentation * fix(sap): change creds priority * fix(sap): change creds priority * fix(sap): fix sap creds unit test * fix(sap): linter fix * fix(sap): linter fix * linter fix * (sap) update logic of fetching creds, add additional tests * (sap) clean up code * (sap) fix after review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) add a possibility to put the service key by both variants * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) update test * (sap) update service key resolve function * (sap) run black formater * (sap) fix validate credentials, add negative tests for credential fetching * (sap) fix validate credentials, add negative tests for credential fetching * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) lint fix * (sap) lint fix * feat: support service_tier in gemini * chore: add a service_tier field mapping from openai to gemini * fix: use x-gemini-service-tier header in response * docs: add service_tier to gemini docs * chore: add defaut/standard mapping, and some tests * chore: tidying up some case insensitivity * chore: remove unnecessary guard * fix: remove redundant test file * fix: handle 'auto' case-insensitively * fix: return service_tier on final steamed chunk * chore: black * feat: enable supports_service_tier to gemini models * Fix get_standard_logging_metadata tests * Fix test_get_model_info_bedrock_models * Fix test_get_model_info_bedrock_models * Fix remaining tests * Fix mypy issues * Fix tests * Fix merge conflicts * Fix code qa * Fix code qa * Fix code qa * Fix greptile review --------- Co-authored-by: michelligabriele <gabriele.michelli@icloud.com> Co-authored-by: Josh <36064836+J-Byron@users.noreply.github.com> Co-authored-by: mubashir1osmani <mubashir.osmani777@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: milan-berri <milan@berri.ai> Co-authored-by: Alperen Kömürcü <alperen.koemuercue@sap.com> Co-authored-by: Vasilisa Parshikova <vasilisa.parshikova@sap.com> Co-authored-by: Lin Xu <lin.xu03@sap.com> Co-authored-by: Mark McDonald <macd@google.com> Co-authored-by: Sameer Kankute <sameer@berri.ai>
* fix(vertex_ai): support pluggable (executable) credential_source for WIF auth (BerriAI#24700) The WIF credential dispatch in load_auth() only handled identity_pool and aws credential types. When credential_source.executable was present (used for Azure Managed Identity via Workload Identity Federation), it fell through to identity_pool.Credentials which rejected it with MalformedError. Add dispatch to google.auth.pluggable.Credentials for executable-type credential sources, following the same pattern as the existing identity_pool and aws helpers. Fixes authentication for Azure Container Apps → GCP Vertex AI via WIF with executable credential sources. * feat(logging): add component and logger fields to JSON logs for 3rd p… (BerriAI#24447) * feat(logging): add component and logger fields to JSON logs for 3rd party filtering * Let user-supplied extra fields win over auto-generated component/logger, tighten test assertions * Feat - Add organization into the metrics metadata for org_id & org_alias (BerriAI#24440) * Add org_id and org_alias label names to Prometheus metric definitions * Add user_api_key_org_alias to StandardLoggingUserAPIKeyMetadata * Populate user_api_key_org_alias in pre-call metadata * Pass org_id and org_alias into per-request Prometheus metric labels * Add test for org labels on per-request Prometheus metrics * chore: resolve test mockdata * Address review: populate org_alias from DB view, add feature flag, use .get() for org metadata * Add org labels to failure path and verify flag behavior in test * Fix test: build flag-off enum_values without org fields * Gate org labels behind feature flag in get_labels() instead of static metric lists * Scope org label injection to metrics that carry team context, remove orphaned budget label defs, add test teardown * Use explicit metric allowlist for org label injection instead of team heuristic * Fix duplicate org label guard, move _org_label_metrics to class constant * Reset custom_prometheus_metadata_labels after duplicate label assertion * fix: emit org labels by default, remove flag, fix missing org_alias in all metadata paths * fix: emit org labels by default, no opt-in flag required * fix: write org_alias to metadata unconditionally in proxy_server.py * fix: 429s from batch creation being converted to 500 (BerriAI#24703) * add us gov models (BerriAI#24660) * add us gov models * added max tokens * Litellm dev 04 02 2026 p1 (BerriAI#25052) * fix: replace hardcoded url * fix: Anthropic web search cost not tracked for Chat Completions The ModelResponse branch in response_object_includes_web_search_call() only checked url_citation annotations and prompt_tokens_details, missing Anthropic's server_tool_use.web_search_requests field. This caused _handle_web_search_cost() to never fire for Anthropic Claude models. Also routes vertex_ai/claude-* models to the Anthropic cost calculator instead of the Gemini one, since Claude on Vertex uses the same server_tool_use billing structure as the direct Anthropic API. --------- * fix(anthropic): pass logging_obj to client.post for litellm_overhead_time_ms (BerriAI#24071) When LITELLM_DETAILED_TIMING=true, litellm_overhead_time_ms was null for Anthropic because the handler did not pass logging_obj to client.post(), so track_llm_api_timing could not set llm_api_duration_ms. Pass logging_obj=logging_obj at all four post() call sites (make_call, make_sync_call, acompletion, completion). Add test to ensure make_call passes logging_obj to client.post. Made-with: Cursor * sap - add additional parameters for grounding - additional parameter for grounding added for the sap provider * sap - fix models * (sap) add filtering, masking, translation SAP GEN AI Hub modules * (sap) add tests and docs for new SAP modules * (sap) add support of multiple modules config * (sap) code refactoring * (sap) rename file * test(): add safeguard tests * (sap) update tests * (sap) update docs, solve merge conflict in transformation.py * (sap) linter fix * (sap) Align embedding request transformation with current API * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) mock commit * (sap) run black formater * (sap) add literals to models, add negative tests, fix test for tool transformation * (sap) fix formating * (sap) fix models * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) commit for rerun bot review * (sap) minor improve * (sap) fix after bot review * (sap) lint fix * docs(sap): update documentation * fix(sap): change creds priority * fix(sap): change creds priority * fix(sap): fix sap creds unit test * fix(sap): linter fix * fix(sap): linter fix * linter fix * (sap) update logic of fetching creds, add additional tests * (sap) clean up code * (sap) fix after review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) add a possibility to put the service key by both variants * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) update test * (sap) update service key resolve function * (sap) run black formater * (sap) fix validate credentials, add negative tests for credential fetching * (sap) fix validate credentials, add negative tests for credential fetching * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) fix after bot review * (sap) lint fix * (sap) lint fix * feat: support service_tier in gemini * chore: add a service_tier field mapping from openai to gemini * fix: use x-gemini-service-tier header in response * docs: add service_tier to gemini docs * chore: add defaut/standard mapping, and some tests * chore: tidying up some case insensitivity * chore: remove unnecessary guard * fix: remove redundant test file * fix: handle 'auto' case-insensitively * fix: return service_tier on final steamed chunk * chore: black * feat: enable supports_service_tier to gemini models * Fix get_standard_logging_metadata tests * Fix test_get_model_info_bedrock_models * Fix test_get_model_info_bedrock_models * Fix remaining tests * Fix mypy issues * Fix tests * Fix merge conflicts * Fix code qa * Fix code qa * Fix code qa * Fix greptile review --------- Co-authored-by: michelligabriele <gabriele.michelli@icloud.com> Co-authored-by: Josh <36064836+J-Byron@users.noreply.github.com> Co-authored-by: mubashir1osmani <mubashir.osmani777@gmail.com> Co-authored-by: milan-berri <milan@berri.ai> Co-authored-by: Alperen Kömürcü <alperen.koemuercue@sap.com> Co-authored-by: Vasilisa Parshikova <vasilisa.parshikova@sap.com> Co-authored-by: Lin Xu <lin.xu03@sap.com> Co-authored-by: Mark McDonald <macd@google.com> Co-authored-by: Sameer Kankute <sameer@berri.ai>

Relevant issues
Resolves #24251
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
tests/test_litellm/directory, Adding at least 1 test is a hard requirement - see detailsmake test-unit@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewDelays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
CI (LiteLLM team)
Branch creation CI run
Link:
CI run for the last commit
Link:
Merge / cherry-pick CI run
Links:
Type