Skip to content

Conversation

@billyvg
Copy link
Member

@billyvg billyvg commented Oct 28, 2025

In order to support moving our custom rrweb events to EAP, we need to send timestamps w/ trace ids so that we can identify which trace the event belongs to.

In order to avoid breaking changes, we should not change the current type of trace_ids field in the replay event, instead we add a new field traces_by_timestamp w/ type [transaction.start_timestamp, traceId][].

Previously, we would clear all trace ids after each replay segment. so if there is not a new transaction, segments would not have a trace id associated at all. I've changed this so that we always keep the most recent trace id in between segments.

Also previously, in order to associate a replay with a trace, we wait until after a type: transaction event is sent successfully. it's possible that the replay integration is loaded after this event is sent and never gets associated with any trace ids. in this case, I've changed it so that we take the trace id from current scope and propagation context, and I use -1 for the timestamp here, but could also change to use current ts.

In order to support moving our custom rrweb events to EAP, we need to send timestamps w/ trace ids so that we can identify which trace the event belongs to.

In order to avoid breaking changes, we should not change the current type of trace_ids field in the replay event, instead we add a new field traces_by_timestamp
@linear
Copy link

linear bot commented Oct 28, 2025

@github-actions
Copy link
Contributor

github-actions bot commented Oct 28, 2025

size-limit report 📦

Path Size % Change Change
@sentry/browser 24.64 kB - -
@sentry/browser - with treeshaking flags 23.13 kB - -
@sentry/browser (incl. Tracing) 40.98 kB - -
@sentry/browser (incl. Tracing, Profiling) 45.26 kB - -
@sentry/browser (incl. Tracing, Replay) 79.41 kB +0.12% +88 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 69.1 kB +0.12% +76 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 84.12 kB +0.11% +87 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 96.29 kB +0.1% +90 B 🔺
@sentry/browser (incl. Feedback) 41.31 kB - -
@sentry/browser (incl. sendFeedback) 29.31 kB - -
@sentry/browser (incl. FeedbackAsync) 34.24 kB - -
@sentry/react 26.32 kB - -
@sentry/react (incl. Tracing) 42.97 kB - -
@sentry/vue 29.13 kB - -
@sentry/vue (incl. Tracing) 42.79 kB - -
@sentry/svelte 24.65 kB - -
CDN Bundle 26.9 kB - -
CDN Bundle (incl. Tracing) 41.63 kB - -
CDN Bundle (incl. Tracing, Replay) 77.99 kB +0.11% +85 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 83.47 kB +0.11% +87 B 🔺
CDN Bundle - uncompressed 78.89 kB - -
CDN Bundle (incl. Tracing) - uncompressed 123.47 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 238.99 kB +0.13% +297 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 251.75 kB +0.12% +297 B 🔺
@sentry/nextjs (client) 45.12 kB - -
@sentry/sveltekit (client) 41.4 kB - -
@sentry/node-core 50.81 kB - -
@sentry/node 157.88 kB -0.01% -1 B 🔽
@sentry/node - without tracing 92.69 kB -0.01% -1 B 🔽
@sentry/aws-serverless 106.42 kB +0.01% +2 B 🔺

View base workflow run

@github-actions
Copy link
Contributor

github-actions bot commented Oct 28, 2025

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 9,122 - 8,934 +2%
GET With Sentry 1,281 14% 1,387 -8%
GET With Sentry (error only) 6,034 66% 6,232 -3%
POST Baseline 1,175 - 1,217 -3%
POST With Sentry 512 44% 528 -3%
POST With Sentry (error only) 1,062 90% 1,072 -1%
MYSQL Baseline 3,284 - 3,382 -3%
MYSQL With Sentry 496 15% 492 +1%
MYSQL With Sentry (error only) 2,743 84% 2,790 -2%

View base workflow run

@billyvg
Copy link
Member Author

billyvg commented Oct 28, 2025

@sentry review

@billyvg
Copy link
Member Author

billyvg commented Oct 29, 2025

@sentry review

@billyvg billyvg marked this pull request as ready for review October 29, 2025 22:24
@billyvg billyvg requested a review from a team as a code owner October 29, 2025 22:24
@billyvg billyvg requested a review from chargome October 29, 2025 22:24
trace_ids: uniqueTraceIds,
traces_by_timestamp: traceIds
.filter(([_ts, traceId]) => uniqueTraceIds.includes(traceId))
.map(([ts, traceId]) => [ts, traceId]),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Redundant Filter Causes Unnecessary Performance Overhead

The filter for traces_by_timestamp is redundant. Since uniqueTraceIds is derived directly from traceIds, every trace ID in traceIds will always be present in uniqueTraceIds. This makes the filter a no-op, always returning true, and introduces unnecessary O(n²) performance overhead.

Fix in Cursor Fix in Web

if (event.contexts?.trace?.trace_id && replayContext.traceIds.size < 100) {
replayContext.traceIds.add(event.contexts.trace.trace_id);
if (event.contexts?.trace?.trace_id && event.start_timestamp && replayContext.traceIds.length < 100) {
replayContext.traceIds.push([event.start_timestamp, event.contexts.trace.trace_id]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Timestamp Handling Ignores Valid Zero Value

The event.start_timestamp check in handleTransactionEvent uses a truthy evaluation, which causes trace IDs to not be recorded for transactions with a start_timestamp of 0. Although rare, 0 is a valid Unix epoch timestamp.

Fix in Cursor Fix in Web

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.

2 participants