feat: add disable_content_logging option to OTel profiles to drop message/tool content from exported spans - #4064
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughAdds a per-profile ChangesOTEL Content Logging Control
Sequence Diagram(s)sequenceDiagram
participant UI
participant Inject
participant convertTraceToResourceSpan
participant convertSpanToOTELSpan
participant convertAttributesToKeyValues
participant convertSpanEvents
UI->>Inject: configure profile (disable_content_logging)
Inject->>convertTraceToResourceSpan: pass disableContentLogging
convertTraceToResourceSpan->>convertSpanToOTELSpan: pass disableContentLogging
convertSpanToOTELSpan->>convertAttributesToKeyValues: convert attributes (with flag)
convertSpanToOTELSpan->>convertSpanEvents: convert events (with flag)
convertSpanEvents->>convertAttributesToKeyValues: convert event attributes (with flag)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Comment |
This stack of pull requests is managed by Graphite. Learn more about stacking. |
disable_content_logging option to OTel profiles to drop message/tool content from exported spans
Confidence Score: 4/5Safe to merge after fixing the incomplete content filter — the infrastructure is correct but three attribute keys carrying real user content slip through when the flag is enabled. The plugins/otel/converter.go — the Important Files Changed
Reviews (4): Last reviewed commit: "feat: disable content logging on otel" | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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.
Inline comments:
In `@ui/app/workspace/observability/fragments/otelFormFragment.tsx`:
- Around line 444-461: The Switch in the FormField for name
`${base}.disable_content_logging` is missing a data-testid used by E2E tests;
add a stable data-testid prop to the Switch (e.g.,
data-testid="disable-content-logging-toggle" or similar) while leaving its
checked, onCheckedChange, and disabled props intact so tests can reliably select
this interactive element in otelFormFragment.tsx.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: aac7d06e-ab78-4378-b8ff-6318f66e87cb
📒 Files selected for processing (4)
plugins/otel/converter.goplugins/otel/main.goui/app/workspace/observability/fragments/otelFormFragment.tsxui/lib/types/schemas.ts
0072029 to
c74c501
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
ui/app/workspace/observability/fragments/otelFormFragment.tsx (1)
457-457:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse a unique
data-testidper OTEL profile toggle.
data-testid="disable-content-logging-toggle"is duplicated across profiles, which makes E2E selectors ambiguous when multiple profiles are present.Suggested fix
- <Switch checked={field.value} onCheckedChange={field.onChange} disabled={!hasOtelAccess} data-testid="disable-content-logging-toggle" /> + <Switch + checked={field.value} + onCheckedChange={field.onChange} + disabled={!hasOtelAccess} + data-testid={`otel-profile-${index}-content-logging-toggle`} + />As per coding guidelines: "Always use stable, unique keys in lists" and "E2E tests must use data-testid attributes for element selection."
🤖 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 `@ui/app/workspace/observability/fragments/otelFormFragment.tsx` at line 457, The Switch's data-testid ("disable-content-logging-toggle") is duplicated across OTEL profiles; update the Switch in otelFormFragment (the element with checked={field.value} onCheckedChange={field.onChange} disabled={!hasOtelAccess}) to emit a stable unique test id per profile—e.g., append the profile identifier or form field name/index (use profile.id, profile.name, or field.name/index) so the attribute becomes something like "disable-content-logging-toggle-{profileId}" to ensure uniqueness for E2E selectors.
🤖 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.
Inline comments:
In `@plugins/otel/converter.go`:
- Line 250: The code currently drops schemas.AttrToolCallID when content logging
is disabled; change the filtering in the attribute-building logic in
plugins/otel/converter.go (the block that builds the attributes list including
schemas.AttrToolName and schemas.AttrToolCallID) so that you only remove
content-bearing fields (tool definitions, arguments, results, and any
payload-specific attrs) and always retain schemas.AttrToolCallID (and other
correlation metadata like schemas.AttrToolName) so tool call IDs remain
available for correlation even when content logging is off.
- Around line 241-258: Add a small table-driven unit test for isContentAttribute
that enumerates each relevant schemas.Attr* key (both those currently expected
to return true and a few representative keys expected to return false) and
asserts the boolean result matches the contract; name the test to indicate it
protects the OTEL content-filtering privacy boundary, use a loop over test cases
with t.Run to isolate failures, and fail explicitly when the returned value
differs from the expected value so future additions to schemas.Attr* will be
caught.
---
Duplicate comments:
In `@ui/app/workspace/observability/fragments/otelFormFragment.tsx`:
- Line 457: The Switch's data-testid ("disable-content-logging-toggle") is
duplicated across OTEL profiles; update the Switch in otelFormFragment (the
element with checked={field.value} onCheckedChange={field.onChange}
disabled={!hasOtelAccess}) to emit a stable unique test id per profile—e.g.,
append the profile identifier or form field name/index (use profile.id,
profile.name, or field.name/index) so the attribute becomes something like
"disable-content-logging-toggle-{profileId}" to ensure uniqueness for E2E
selectors.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 31935830-59c3-45bc-9444-b5a5e11b0264
📒 Files selected for processing (4)
plugins/otel/converter.goplugins/otel/main.goui/app/workspace/observability/fragments/otelFormFragment.tsxui/lib/types/schemas.ts
c74c501 to
815992c
Compare
815992c to
e7be55c
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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.
Inline comments:
In `@helm-charts/bifrost/values.schema.json`:
- Around line 3453-3457: The new boolean property disable_content_logging was
added to otelProfileConfig but the outer compatibility wrapper
otelProfilesConfig still disallows that deprecated top-level key
(additionalProperties: false), causing validation failures during migration;
update otelProfilesConfig to accept the same deprecated disable_content_logging
key for compatibility—either add disable_content_logging to otelProfilesConfig's
allowed properties (mirroring otelProfileConfig) or relax the wrapper validation
to map/forward that deprecated top-level key into the profile entries so merged
values validate correctly.
In `@ui/app/workspace/observability/fragments/otelFormFragment.tsx`:
- Around line 444-461: The data-testid "disable-content-logging-toggle" is
static but this FormField is rendered per profile; update the test id to be
profile-unique (consistent with nearby toggles) by including the profile index
or profile identifier when rendering the Switch for the field named
`${base}.disable_content_logging` inside the FormField/Render block; ensure you
reuse the same naming pattern used elsewhere (e.g., append `-${profileIndex}` or
`${profileIndex}-...`) so the Switch's data-testid becomes unique per profile
while keeping the original base string for E2E tests.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2cc70d56-3758-44ca-b160-d5f52f3a4760
📒 Files selected for processing (7)
helm-charts/bifrost/values.schema.jsonhelm-charts/bifrost/values.yamlplugins/otel/converter.goplugins/otel/main.gotransports/config.schema.jsonui/app/workspace/observability/fragments/otelFormFragment.tsxui/lib/types/schemas.ts
e7be55c to
8da7bd1
Compare
Merge activity
|
…essage/tool content from exported spans (#4064) ## Summary Adds a `disable_content_logging` option to OTEL profiles that allows operators to strip message content from exported spans before they reach the collector. When enabled, only metadata (model, token counts, latency, etc.) is exported — input/output messages, tool definitions, tool call arguments, and tool call results are dropped from span attributes and events. ## Changes - Added `DisableContentLogging bool` field to the `Profile` and `otelTarget` structs, and included it in `profileForStorage` serialization/deserialization so the setting persists correctly. - Propagated `disableContentLogging` through `convertTraceToResourceSpan` → `convertSpanToOTELSpan` → `convertAttributesToKeyValues` and `convertSpanEvents`, so filtering applies to both span attributes and span event attributes. - Introduced `isContentAttribute(key string) bool` to centralize the list of attribute keys that carry message/tool content (`AttrInputMessages`, `AttrOutputMessages`, `AttrInputText`, `AttrInputSpeech`, `AttrTools`, `AttrRespTools`, `AttrToolName`, `AttrToolCallID`, `AttrToolCallArguments`, `AttrToolCallResult`, `AttrToolType`, `AttrToolChoiceType`, `AttrToolChoiceName`, `AttrRespToolChoiceType`, `AttrRespToolChoiceName`). - Added a **Disable Content Logging** toggle to the OTEL profile form in the UI, wired to the `disable_content_logging` field with appropriate label and description text. - Extended the Zod schema (`otelConfigSchema`) and the `StoredOtelProfile` TypeScript interface to include `disable_content_logging`. ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [x] UI (React) - [ ] Docs ## How to test ```sh # Core/Transports go test ./plugins/otel/... # UI cd ui pnpm i pnpm build ``` 1. Configure an OTEL profile in the UI and enable **Disable Content Logging**. 2. Send a request through Bifrost that produces a trace with input/output messages and tool calls. 3. Inspect the spans received by the OTEL collector and confirm that attributes such as `gen_ai.prompt`, `gen_ai.completion`, tool definitions, and tool call arguments/results are absent, while model, token count, and latency attributes are still present. 4. Disable the toggle and repeat — confirm content attributes reappear in the exported spans. **New config field:** | Field | Type | Default | Description | |---|---|---|---| | `disable_content_logging` | `bool` | `false` | When `true`, drops message content and tool data from exported OTEL spans. | ## Screenshots/Recordings A new toggle appears in the OTEL profile configuration section beneath the existing request headers field, labeled **Disable Content Logging** with a description explaining what is suppressed. ## Breaking changes - [x] No ## Related issues ## Security considerations This feature directly addresses PII and data-sensitivity concerns. Operators handling regulated data or operating under strict data-minimization requirements can enable `disable_content_logging` to ensure that raw prompt/completion content and tool payloads are never forwarded to the OTEL collector, reducing the risk of sensitive data exposure in observability pipelines. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [ ] I added/updated tests where appropriate - [ ] I updated documentation where needed - [ ] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a per-profile "Disable Content Logging" toggle for OTEL. When enabled, exported traces omit message content (inputs/outputs, embeddings, tool and tool-call details) while retaining metadata (model, tokens, latency). The option appears in the UI and is persisted per profile (defaults to off). * **Chores** * Configuration schemas and Helm values updated to expose and document the new per-profile setting. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## ✨ Features - **OpenAI Compaction** — Added OpenAI conversation compaction support across core, framework, logging, and the API surface (#4053) - **Multi-Customer & Org Hierarchy** — Logs and usage tracking now support multiple customers, teams, and business units, including business unit CRUD, team assignment, and governance endpoints in the OpenAPI spec (#4066, #4041, #4082) - **Provider-Level Governance** — Budgets & limits are now scope-aware and can be applied at the virtual-key top level and per provider, wired from the model configs table, with UI filters for scope and providers (#3938, #3937, #3939, #3981, #3962) - **Customer Budgets** — Customers support multiple budgets and `calendar_aligned` budget windows (#3998, #3997) - **Virtual Key Attribution & Controls** — Added a `created_by` user attribution column and a `blacklisted_models` column for virtual key provider configs (#3672, #3653) - **Request Header Capture** — OTel and Maxim observability plugins capture `request_headers` by pattern, with wildcard support (e.g. `x-custom-*`); logging gained the same wildcard header capture (#4012, #3958) - **OTel Content Controls & Collectors** — New `disable_content_logging` option drops message/tool content from exported spans, plus support for multiple OTel collectors (#4064, #3894) - **xAI x_search** — Added xAI `x_search` tool support (#3976) - **URL Validation** — Added fetch URL validation with private-network configuration and link-local blocking (#3947, #3991) - **File Scheme Pricing URLs** — Pricing source URLs now accept the `file://` scheme for air-gapped and self-hosted deployments (#4045) - **Paginated Virtual Keys** — Virtual key fetching is paginated to handle deployments with very large numbers of keys (#3957) - **Client IP Resolution** — Resolve client IP from `X-Forwarded-For`/`X-Real-IP` headers - **SCIM Provisioning** — Added `attributeType`/`attributeValue` SCIM provisioning fields - **Helm/Config Schema** — Added `roles` RBAC governance config and `per_user_oauth` MCP auth to the Helm chart and config schema (#4004, #4009) - **Log Navigation UI** — Added a "View logs" menu item to customer, team, and virtual key tables, clickable links in log detail views, a customer detail sheet, and a reusable `BudgetDisplay` component (#4073, #4054, #4026, #4055) - **Faster First Paint** — Added an inline loading shell to `#root` before React mounts (#4063) - **Materialized View Alias** — Added an `alias` column to the materialized view with filter support (#4078) ## 🐞 Fixed - **Fetch URL IP Checks** — Hardened fetch URL IP checks against SSRF (#4092) - **Mantle Model Matching** — Broadened Mantle model matching to all `gpt` variants (#4091) - **Empty Thinking Blocks** — Strip thinking blocks when the signature is empty (#4079) - **OpenAI Stream Usage** — Removed usage from the `responses.created` event in the OpenAI stream (#4080) - **Prompt Cache Key** — Set the prompt cache key from the Anthropic integration (#4086) - **Upstream Failure Status** — Map upstream connection failures to 502 instead of 400 (#3929) (thanks [@chris-colinsky](https://github.com/chris-colinsky)!) - **Gemini Schema Constraints** — Accept numeric schema integer constraints for Gemini (#3994) (thanks [@yanhao98](https://github.com/yanhao98)!) - **Files Provider Param** — Accept the `?provider=` query param on `GET /v1/files` (#3971) (thanks [@alexef](https://github.com/alexef)!) - **Optional Batch Model** — Made the `model` field optional on `POST /v1/batches` (#3973) (thanks [@alexef](https://github.com/alexef)!) - **Helm Azure Config** — Added missing `azure_key_config` fields to the Helm schema (#3996) (thanks [@axelray-dev](https://github.com/axelray-dev)!) - **Text Completion Chunk Model** — Added the missing `Model` field to `TextCompletionChunkResponse` (#3970) (thanks [@kuishou68](https://github.com/kuishou68)!) - **MCP Inline stdio Env** — MCP stdio server configs accept inline environment variable assignments (#3861) (thanks [@Shushmitaaaa](https://github.com/Shushmitaaaa)!) - **Orphaned Tool Results** — Orphaned tool results in the OpenAI to Anthropic conversion flow are no longer rejected by the Anthropic API (#3919) - **Node Usage Reconciliation** — Added a monotonic `inc_number` log cursor so node usage reconciliation does not skip late async log writes (#3664) - **Bedrock Output Assessments** — Corrected the type of `outputAssessments` in Bedrock responses (#4028) - **Model Pool Pricing Reloads** — Preserve non-pricing model pool entries across pricing reloads (#3999) - **Ghost Node Reconciliation** — Replicate the VK hierarchy flow for ghost node reconciliation (#4088) - **VK Double Usage Counting** — Fixed double usage counting when creating a virtual key (#4070) - **Model Config Lifecycle** — Cascade deletes for model configs and removal of stale in-memory model configs (#4051, #4043) - **FTS Index Cap** — Reduced the FTS index `left()` cap from 800k to 250k chars to stay within the tsvector limit (#4057) - **Sync Worker Drift** — Reduced the sync worker ticker period to 5m to prevent threshold drift (#4023) - **Passthrough** — Fixed passthrough budgets, gated passthrough models per VK, model extraction for Azure passthrough, and restricted fallbacks/provider selection to the VK boundary (#3941, #3988, #3983, #3924) - **Provider Response Headers** — Strip provider response headers and add a content-type filter (#3955, #4024) - **Stream Handling** — Drain non-SSE stream readers and retry stale connections (#3956, #3967) - **Azure Claude** — Strip Azure diagnostic property for Claude models (#3925) - **Compat max_tokens** — Preserve chat `max_tokens` during param filtering (#3992) - **Raw Request Flag** — Removed the raw request flag from providers that don't support it (#4058) - **UI Fixes** — Standardized page container layout, virtual key model configs UI, and dashboard chart tooltips (#4046, #4052, #4044) ## 🔧 Maintenance - **Dependency Upgrades** — Bumped transitive `golang.org/x` dependencies (crypto, net, sys, text) for Docker Scout CVE remediation and `recharts` to 3.8.1; cascaded version bumps across all modules (#3900, #4003)

Summary
Adds a
disable_content_loggingoption to OTEL profiles that allows operators to strip message content from exported spans before they reach the collector. When enabled, only metadata (model, token counts, latency, etc.) is exported — input/output messages, tool definitions, tool call arguments, and tool call results are dropped from span attributes and events.Changes
DisableContentLogging boolfield to theProfileandotelTargetstructs, and included it inprofileForStorageserialization/deserialization so the setting persists correctly.disableContentLoggingthroughconvertTraceToResourceSpan→convertSpanToOTELSpan→convertAttributesToKeyValuesandconvertSpanEvents, so filtering applies to both span attributes and span event attributes.isContentAttribute(key string) boolto centralize the list of attribute keys that carry message/tool content (AttrInputMessages,AttrOutputMessages,AttrInputText,AttrInputSpeech,AttrTools,AttrRespTools,AttrToolName,AttrToolCallID,AttrToolCallArguments,AttrToolCallResult,AttrToolType,AttrToolChoiceType,AttrToolChoiceName,AttrRespToolChoiceType,AttrRespToolChoiceName).disable_content_loggingfield with appropriate label and description text.otelConfigSchema) and theStoredOtelProfileTypeScript interface to includedisable_content_logging.Type of change
Affected areas
How to test
gen_ai.prompt,gen_ai.completion, tool definitions, and tool call arguments/results are absent, while model, token count, and latency attributes are still present.New config field:
disable_content_loggingboolfalsetrue, drops message content and tool data from exported OTEL spans.Screenshots/Recordings
A new toggle appears in the OTEL profile configuration section beneath the existing request headers field, labeled Disable Content Logging with a description explaining what is suppressed.
Breaking changes
Related issues
Security considerations
This feature directly addresses PII and data-sensitivity concerns. Operators handling regulated data or operating under strict data-minimization requirements can enable
disable_content_loggingto ensure that raw prompt/completion content and tool payloads are never forwarded to the OTEL collector, reducing the risk of sensitive data exposure in observability pipelines.Checklist
docs/contributing/README.mdand followed the guidelinesSummary by CodeRabbit