Skip to content

feat: support OpenTelemetry span customizers - #2615

Draft
Andrew Kent (realark) wants to merge 1 commit into
ark/SDK-472-customizer-error-handlingfrom
ark/SDK-473-otel-span-customizers
Draft

Andrew Kent (realark) wants to merge 1 commit into
ark/SDK-472-customizer-error-handlingfrom
ark/SDK-473-otel-span-customizers

Conversation

@realark

Copy link
Copy Markdown
Contributor

Summary

Implements SDK-473.

Stacked on SDK-472: depends on #2614; base is ark/SDK-472-customizer-error-handling, not main. This is one new feature commit on that branch.

  • Reuse configureInstrumentation({ spanCustomizers }) and synchronous onSpanExport through a shared internal SDK runner; remove the compatibility-mode registration/setup guards.
  • Native records keep their existing shape. OTel hooks receive isolated plain snapshots containing attributes, name, kind, status, events, links, resource, instrumentationScope, object-valued spanContext, parent context/ID and OTel time arrays. Replacements are not implicitly merged.
  • Customize public processors/exporters after AI filtering and origin enrichment, and after pending resource attributes settle. Preserve original IDs, parent relationships, timing and Braintrust routing; do not mutate spans shared with other exporters.
  • Apply SDK-472 fail-closed policy before real OTLP serialization: invalid returns/shapes and thrown hooks stop the chain and retain only identity/timing/routing plus braintrust.context_json exactly {"customizer_error":true}. Strip origin, payload, resource/scope metadata, events, links and status descriptions. Native and OTel failures share one safe diagnostic across ESM/CJS bundles.
  • Prevent double invocation when processors/exporters compose. HTTP retries reuse already-customized data; resubmitting the original span is a new export.
  • Document the payload shapes and redaction example; add a Conventional Commit changeset for both publishable packages.

Compatibility / release

@braintrust/otel now requires braintrust >=3.38.0, the next minor selected by this changeset, for the shared policy API. There is deliberately no silent fallback to uncustomized export with an older SDK. The two isolated OTel fixture lockfiles were updated; package versions were not manually edited. Native logging remains native in OTel compatibility mode.

Verification

  • Built braintrust and @braintrust/otel (ESM, CJS and declarations).
  • Both packages' check:typings (source and test declarations) passed.
  • Native focused suites: 173 passed (span-customizer, logger, span-origin).
  • OTel v1 (SDK 1.9.0, OTLP HTTP 0.57.2): 151 passed.
  • OTel v2 (SDK 2.0.0, OTLP HTTP 0.200.0): 151 passed.
  • 26 permanent customizer boundary tests per OTel matrix use the real OTLP serializer/HTTP exporter with a local HTTP receiver, including 503 retry, redaction/replacement, routing/timing/parent preservation, invalid serializer shapes, async resources, unchanged shared spans, mixed logger/experiment/OTel compatibility paths, no double invocation, cross-realm/null-prototype returns, ESM bootstrap → CJS export and native/OTel once-only diagnostics in both failure orders.
  • Changeset summary validator tests: 4 passed; both changeset summaries validate; release planner selects minor releases for both packages. Full PR changeset requirement checked against the stacked base.
  • Formatting check passed.

The matrix was installed with pinned pnpm@10.33.0 --ignore-workspace; CI was unset for the local matrix because this environment globally sets it and an existing environment-detection test expects a non-CI process. No live Braintrust endpoint or provider credentials were needed; transport evidence is local HTTP, not a mocked serializer.

@realark
Andrew Kent (realark) force-pushed the ark/SDK-473-otel-span-customizers branch from d29b783 to 17a4bd0 Compare October 12, 2026 19:36
@realark

Andrew Kent (realark) commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor Author

Amended the single SDK-473 commit to 17a4bd0: removed the obsolete isOtelCompatMode helper and made the standalone ESM/CJS export smoke use node:util promisify rather than Promise.withResolvers, which Node 20 does not implement. Both OTel matrices pass all 151 tests locally under Node 20.20.2, including real HTTP exports. All hosted CI checks now pass, including the full OTel v1/v2 × Node 20/22/24/26 matrix, native Linux/Windows suites, build/type/lint/dead-code checks, smoke tests, e2e, and changeset validation: https://github.com/braintrustdata/braintrust-sdk-javascript/actions/runs/38298754195

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant