ref: Migrate internal spanToJSON callers to spanToStreamedSpanJSON - #23237
ref: Migrate internal spanToJSON callers to spanToStreamedSpanJSON#23237Lms24 wants to merge 5 commits into
spanToJSON callers to spanToStreamedSpanJSON#23237Conversation
`spanToJSON` now returns the intermediate `StreamedSpanJSON` representation instead of the legacy `SpanJSON`. The previous behaviour is still available as `spanToStaticSpanJSON`, and the old `spanToStreamedSpanJSON` export is gone (it *is* `spanToJSON` now). Field mapping for call sites: `description` -> `name`, `data` -> `attributes`, `timestamp` -> `end_timestamp`, and `op`/`origin` move into `attributes` under `sentry.op` / `sentry.origin`. `status` is narrowed to `'ok' | 'error'`. `end_timestamp` is optional on `StreamedSpanJSON` and only required on `SerializedStreamedSpan`, so the guarantee we actually care about — every span we *send* has an end timestamp — is enforced at the single serialization boundary (`streamedSpanJsonToSerializedSpan`) rather than baked into every span representation. That keeps `end_timestamp` usable as the "has this span ended?" signal it already was, so the open-span checks in `browserTracingIntegration`, `idleSpan` and the React Router instrumentation stay simple field reads.
Moves all SDK-internal consumers off the static `SpanJSON` shape and onto the already-existing `spanToStreamedSpanJSON`, which returns `StreamedSpanJSON`. This is the semantically interesting half of the `spanToJSON` swap: `op`, `origin` and `description` become attribute lookups (`sentry.op`, `sentry.origin`) and `name`, and `timestamp` becomes `end_timestamp`. No public API changes — `spanToJSON` keeps returning `SpanJSON`, so this is a non-breaking change that can land on its own. The rename that makes `spanToJSON` return the streamed shape follows separately. Also included, since the migration depends on them: - `StreamedSpanJSON.attributes` is now always set, and `end_timestamp` is optional (only present once a span has ended). OTEL reports `[0, 0]` for unended spans, which is now normalized to `undefined`. - `SerializedStreamedSpan` re-requires `end_timestamp`, falling back to `start_timestamp`, so spans on the wire always carry an end timestamp. - `RawAttributes` is exported from `@sentry/core` for consumers that need to type attribute bags. - `applyOtelSpanData` reads the status message from the static representation, since the streamed shape only narrows to `'ok' | 'error'`. - Redis cache and `setHttpServerSpanRouteAttribute` use `@sentry/conventions` attribute constants instead of string literals. Fixes a stale mock in the Remix `instrumentServer` test that returned `description` where the code reads `name`, silently dropping the method-prefix branch from coverage. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
spanToJSON callers to spanToStreamedSpanJSON
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f38f841. Configure here.
| () => (window as unknown as WindowWithSpan).thirdWaitingSpan.description, | ||
| () => (window as unknown as WindowWithSpan).secondWaitingSpan.name, | ||
| ); | ||
| const thirdWaitingSpanName = await page.evaluate(() => (window as unknown as WindowWithSpan).thirdWaitingSpan.name); |
There was a problem hiding this comment.
Async-spans test reads wrong fields
Medium Severity
The test now reads .name from the waiting spans, but subject.js still stores spanToJSON(...) results that expose .description. Those assertions will get undefined and fail.
Triggered by project rule: PR Review Guidelines for Cursor Bot
Reviewed by Cursor Bugbot for commit f38f841. Configure here.
| // a cancelled span is reported as `ok`, with the raw status kept as an attribute | ||
| expect(spanJsonAfter.status).toBe('ok'); | ||
| expect(attributes_after['sentry.status.message']).toBeUndefined(); | ||
| expect(attributes_after['sentry.cancellation_reason']).toBe('document.hidden'); |
There was a problem hiding this comment.
Background-tab test fixture mismatch
Medium Severity
The test types and asserts on StreamedSpanJSON fields like name and attributes, but window.getSpanJson() still returns Sentry.spanToJSON(...). Cancelled-status expectations also diverge from the legacy payload shape.
Triggered by project rule: PR Review Guidelines for Cursor Bot
Reviewed by Cursor Bugbot for commit f38f841. Configure here.
size-limit report 📦
|


This PR is prework for #23238:
spanToJSONcall to the already-exportedspanToStreamedSpanJSONfunction.op,originanddescriptionbecome attribute lookups (sentry.op,sentry.origin) andnametimestampbecomesend_timestamp.Three type/behavior changes are included because the migration depends on them:
StreamedSpanJSON.attributesis now always set (so we/users don't need optional chaining)end_timestampbecame optional since we depend on checking the end timestamp for un-ended spansSerializedStreamedSpanre-requiresend_timestampwith astart_timestampfallback so spans on the wire always carry one.applyOtelSpanDatareads its status from the static representation, since the streamed shape only narrows to'ok' | 'error'.Minor additional chainges
RawAttributesis exported from@sentry/corefor typing attribute bagssetHttpServerSpanRouteAttributeuse@sentry/conventionsconstants instead of string literalsinstrumentServertest that returneddescriptionwhere the code readsname, which silently dropped the method-prefix branch from coverage