fix(datadog_llm_obs): keep guardrail_cost_by_unit on redacted spans - #39848
Conversation
Greptile SummaryThis PR ensures redacted Datadog LLM Observability spans retain per-counter guardrail costs.
Confidence Score: 5/5The PR appears safe to merge; the new field has an audit-only numeric shape and the redaction path preserves it without weakening prompt redaction. The added allow-list entry aligns with the field’s numeric cost-accounting contract, uses the same counter keys as the already-retained usage map, and passes mapping values through unchanged.
|
| Filename | Overview |
|---|---|
| litellm/types/utils.py | Correctly classifies guardrail_cost_by_unit as audit metadata retained on redacted Datadog spans. |
Reviews (1): Last reviewed commit: "fix(datadog_llm_obs): keep guardrail_cos..." | Re-trigger Greptile
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit d4fd658. Configure here.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
df3b8a6
into
litellm_internal_staging
TLDR
Problem this solves:
integrations / Run testsjob fails on staging since 01:24Zguardrail_cost_by_unitwas never classified for redacted Datadog spansHow it solves it:
guardrail_cost_by_unitas an audit field, kept under redaction#39196 added
guardrail_cost_by_unitto the guardrail record and #39702 added the allow-list that decides what a redacted Datadog span keeps, plus a test that fails for any record field with no decision. Each PR's CI ran on a merge ref that predated the other, so staging only broke once both had landedUser Flow
Before: an operator who redacts prompts in Datadog LLM Observability sees each guardrail's total cost on the span but never its per-counter split
callbacks: ["datadog_llm_obs"],turn_off_message_logging: true, and a Bedrock guardrail that has pricing configuredguardrail_costandguardrail_usage, and the prompt-carrying fields readREDACTED_BY_LITELM, butguardrail_cost_by_unitis absent, so the cost cannot be reconciled per usage counterAfter: the same span carries the per-counter cost split next to the total
callbacks: ["datadog_llm_obs"],turn_off_message_logging: true, and a Bedrock guardrail that has pricing configuredguardrail_cost_by_unitwith one cost per usage counter alongsideguardrail_costandguardrail_usage, while the prompt-carrying fields still readREDACTED_BY_LITELMRelevant issues
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
test_a_redacted_span_carries_every_declared_guardrail_fieldfrom fix(datadog_llm_obs): keep the guardrail audit record under message redaction #39702 is what fails before this PR and passes after it)uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
The observable surface is the span JSON the Datadog logger serializes, which the existing test builds through the real logger with redaction on, so the run below is that serializer's output plus the CI job every PR now hits
Before (853fed8)
integrations / Run testson a merge ref carrying both feat(guardrails): roll up Bedrock guardrail cost per usage counter #39196 and fix(datadog_llm_obs): keep the guardrail audit record under message redaction #39702, and fails, e.g. fix(deps): raise the gitpython floor to 3.1.59 for four new advisories #39553 at b5e5212 (job):After (d4fd658)
This PR's own
integrations / Run testsjobs pass:integrations / Run testsshards on this PR: default, 3.10, 3.11, 3.13, 3.14, all passingThe same serializer at this tip locally, whole Datadog file:
Type
🐛 Bug Fix
Caveats (if any)
Low
proxy_store_model_in_db_testsis red on this PR attests/store_model_in_db_tests/test_openai_error_handling.py::test_chat_completion_bad_model_with_spend_logs(assert '' == 'non-existent-model'). It is red on 10 of the 15run-ciPRs updated today and is tracked as its own fix in test(store_model_in_db): assert the 400 contract in the unknown-model spend log test #39842, so it is unrelated to this changeFinal Attestation
Note
Low Risk
Single allow-list entry for observability redaction; no auth, spend logic, or prompt-field handling changes.
Overview
Adds
guardrail_cost_by_unittoAUDIT_GUARDRAIL_FIELDSinlitellm/types/utils.py, so Datadog LLM Observability redaction treats per-counter guardrail cost as non-prompt audit data and keeps it on redacted spans alongside totals likeguardrail_costandguardrail_usage.Updates the guardrail field-classification comment to reference
test_a_redacted_span_carries_every_declared_guardrail_field, which enforces that every declared guardrail field is either prompt-carrying or audit. Without this entry, redacted span serialization droppedguardrail_cost_by_unitand CI failed once that field existed on the guardrail record.Reviewed by Cursor Bugbot for commit d4fd658. Bugbot is set up for automated code reviews on this repo. Configure here.
AUDIT_GUARDRAIL_FIELDSis_CLASSIFIED_GUARDRAIL_FIELDSfeeding the redaction filter in datadog_llm_obs.py;PROMPT_CARRYING_GUARDRAIL_FIELDSand the spend-log redaction in spend_tracking_utils.py are untouched; the field's three producers (guardrail_cost.py, bedrock_guardrails.py, usage_tracking.py) and their tests are unchanged; on this tip tests/test_litellm/integrations/datadog/test_datadog_llm_obs.py goes from the one failing test at base to 68 passed; not verified live: Datadog intake of the redacted span, which already receives this field on unredacted spans