Skip to content

feat(cloudflare): Propagate traceparent to RPC calls - via fetch#19991

Open
JPeer264 wants to merge 1 commit intodevelopfrom
jp/rpc-instrument
Open

feat(cloudflare): Propagate traceparent to RPC calls - via fetch#19991
JPeer264 wants to merge 1 commit intodevelopfrom
jp/rpc-instrument

Conversation

@JPeer264
Copy link
Copy Markdown
Member

@JPeer264 JPeer264 commented Mar 26, 2026

relates to #19327

related to #16898 (it is not really closing it as we just add context propagation without adding spans for individual calls. It needs to be defined if we need it)

It is important to know that these RPC calls do only work with the .fetch call:

const id = env.MY_DURABLE_OBJECT.idFromName('workflow-test');
const stub = env.MY_DURABLE_OBJECT.get(id);

await stub.fetch(new Request('http://my-worker/my-do-call'));

This adds RPC fetch calls between:

This works by instrumenting env (via instrumentEnv), which then goes over the bindings and see if there is a DurableObject or a normal Fetcher (full list of current bindings: https://developers.cloudflare.com/workers/runtime-apis/bindings/). This got inspired by how otel-cf-workers instruments their env: https://github.com/evanderkoogh/otel-cf-workers/blob/effeb549f0a4ed1c55ea0c4f0d8e8e37e5494fb3/src/instrumentation/env.ts

With this PR I added a lot of tests to check if trace propagation works (so this PR might look like it added a lot of LoC, but it is mostly tests). So I added it for schedule and queue, but it is not possible for email and tail with wrangler dev.

Potential things to change

Trace propagagtion

I added the addTraceHeaders.ts helper, as there is currently no way to reuse the existing logic (it is baked-in into the fetch instrumentations). It would be nice once #19960 lands that we can reuse it in Cloudflare to reuse existing code. I tried to write couple of tests so we don't have duplicated headers.

Adding extra spans

So there is actually a guide by OTel to add RPC spans, but was talking with someone from the OTel maintainers and they meant that this wouldn't be necessary as we already have an http.server span from out instrumented DurableObjects (and other resources) - so it wouldn't add much of information.

Without RPC span:

Screenshot 2026-03-25 at 10 59 01

With RPC span:

Screenshot 2026-03-25 at 10 55 48

@JPeer264 JPeer264 requested review from Lms24, logaretm and timfish March 26, 2026 14:38
@JPeer264 JPeer264 self-assigned this Mar 26, 2026
@linear-code
Copy link
Copy Markdown

linear-code bot commented Mar 26, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 26, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

Deps

  • Bump OpenTelemetry dependencies by andreiborza in #20046
  • Bump babel-loader from 10.0.0 to 10.1.1 by dependabot in #19997
  • Bump handlebars from 4.7.7 to 4.7.9 by dependabot in #20008

Nuxt

  • Add middleware instrumentation compatibility for Nuxt 5 by s1gr1d in #19968
  • Support parametrized SSR routes in Nuxt 5 by s1gr1d in #19977

Other

  • (browser) Replace element timing spans with metrics by logaretm in #19869
  • (bun) Add bunRuntimeMetricsIntegration by chargome in #19979
  • (cloudflare) Propagate traceparent to RPC calls - via fetch by JPeer264 in #19991
  • (core) Support embedding APIs in google-genai by nicohrubec in #19797
  • (node) Add nodeRuntimeMetricsIntegration by chargome in #19923
  • (node-core) Add OTLP integration for node-core/light by andreiborza in #19729
  • (solid) Add route parametrization for Solid Router by andreiborza in #20031

Bug Fixes 🐛

Ci

  • Update validate-pr action to remove draft enforcement by stephanie-anderson in #20037
  • Update validate-pr action to remove draft enforcement by stephanie-anderson in #20035

Node

  • Deduplicate sentry-trace and baggage headers on outgoing requests by Lms24 in #19960
  • Ensure startNewTrace propagates traceId in OTel environments by logaretm in #19963

Other

  • (browser-tests) Pin axios to 1.13.5 to avoid compromised 1.14.1 by andreiborza in #20047
  • (core) Guard nullish response in supabase PostgREST handler by antonis in #20033
  • (e2e) Pin @opentelemetry/api to 1.9.0 in ts3.8 test app by logaretm in #19992
  • (nuxt) Use virtual module for Nuxt pages data (SSR route parametrization) by s1gr1d in #20020
  • (opentelemetry) Convert seconds timestamps in span.end() to milliseconds by logaretm in #19958
  • (profiling) Disable profiling in worker threads by chargome in #20040
  • (react-router) Disable debug ID injection in Vite plugin to prevent double injection by isaacs in #19890

Documentation 📚

  • (release) Update publishing-a-release.md by nicohrubec in #19982

Internal Changes 🔧

Core

  • Remove provider-specific AI span attributes in favor of gen_ai attributes in sentry conventions by nicohrubec in #20011
  • Introduce instrumented method registry for AI integrations by nicohrubec in #19981
  • Consolidate getOperationName into one shared utility by nicohrubec in #19971

Deps

  • Bump amqplib from 0.10.7 to 0.10.9 by dependabot in #20000
  • Bump actions/upload-artifact from 6 to 7 by dependabot in #19569
  • Bump srvx from 0.11.12 to 0.11.13 by dependabot in #20001
  • Bump @apollo/server from 5.4.0 to 5.5.0 by dependabot in #20007

Deps Dev

  • Remove esbuild override in astro-5-cf-workers E2E test by isaacs in #20024
  • Bump node-forge from 1.3.2 to 1.4.0 by dependabot in #20012
  • Bump yaml from 2.8.2 to 2.8.3 by dependabot in #19985

Other

  • (browser) Reduce browser package bundle size by HazAT in #19856
  • (browser-tests) Add waitForMetricRequest helper by logaretm in #20002
  • (deno) Expand Deno E2E test coverage by chargome in #19957
  • (e2e) Add e2e tests for nodeRuntimeMetricsIntegration by chargome in #19989

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 26, 2026

size-limit report 📦

Path Size % Change Change
@sentry/browser 25.64 kB - -
@sentry/browser - with treeshaking flags 24.13 kB - -
@sentry/browser (incl. Tracing) 42.15 kB - -
@sentry/browser (incl. Tracing, Profiling) 46.76 kB - -
@sentry/browser (incl. Tracing, Replay) 80.94 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 70.56 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 85.65 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 97.91 kB - -
@sentry/browser (incl. Feedback) 42.42 kB - -
@sentry/browser (incl. sendFeedback) 30.3 kB - -
@sentry/browser (incl. FeedbackAsync) 35.28 kB - -
@sentry/browser (incl. Metrics) 26.95 kB - -
@sentry/browser (incl. Logs) 27.1 kB - -
@sentry/browser (incl. Metrics & Logs) 27.77 kB - -
@sentry/react 27.41 kB - -
@sentry/react (incl. Tracing) 44.48 kB - -
@sentry/vue 30.08 kB - -
@sentry/vue (incl. Tracing) 44.05 kB - -
@sentry/svelte 25.66 kB - -
CDN Bundle 28.31 kB - -
CDN Bundle (incl. Tracing) 43.1 kB - -
CDN Bundle (incl. Logs, Metrics) 29.68 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 44.16 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 68.48 kB - -
CDN Bundle (incl. Tracing, Replay) 80 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 81.04 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 85.54 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 86.58 kB - -
CDN Bundle - uncompressed 82.66 kB - -
CDN Bundle (incl. Tracing) - uncompressed 127.81 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 86.81 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 131.22 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 209.79 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 244.68 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 248.08 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 257.59 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 260.98 kB - -
@sentry/nextjs (client) 46.89 kB - -
@sentry/sveltekit (client) 42.62 kB - -
@sentry/node-core 55.76 kB +0.02% +8 B 🔺
@sentry/node 172.76 kB +0.01% +12 B 🔺
@sentry/node - without tracing 96.02 kB +0.01% +6 B 🔺
@sentry/aws-serverless 112.78 kB +0.01% +7 B 🔺

View base workflow run

Copy link
Copy Markdown
Collaborator

@timfish timfish left a comment

Choose a reason for hiding this comment

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

Nice!

@JPeer264 JPeer264 changed the title feat(cloudflare): Propagate traceparent to RPC calls feat(cloudflare): Propagate traceparent to RPC calls - via fetch Mar 31, 2026
@JPeer264 JPeer264 force-pushed the jp/rpc-instrument branch from 71a3936 to 3097f54 Compare March 31, 2026 11:25
@Lms24
Copy link
Copy Markdown
Member

Lms24 commented Mar 31, 2026

It would be nice once #19960 lands that we can reuse it in Cloudflare to reuse existing code. I tried to write couple of tests so we don't have duplicated headers.

FYI, #19960 landed and I agree! Right now, our various request instrumentations combine the "logic"/"algorithm" code with platform specific code how to set headers. I think it would be good if we could strip out the algorithm part into a common helper, and only leave the platform-specific parts to the individual instrumentations. From my PoV a good improvement but something we can also tackle at a later point. Happy to leave this up to you :)

Comment on lines +29 to +31
} else if (!existing.split(',').some(entry => entry.trim().startsWith(SENTRY_BAGGAGE_KEY_PREFIX))) {
headers.set('baggage', `${existing},${baggage}`);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

l: can we reuse mergeBaggageHeaders here?
Update: realized this is only exported from @sentry/node-core but I think that's actually worth moving to core because it should be fairly platform-independent. WDYT?

Comment on lines +20 to +21

if (!headers.has('sentry-trace')) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

m: As pointed out in #19960, we should only attach any of our headers if sentry-trace isn't set yet. So we could most likely just early return here.

Comment on lines +13 to +15
const newInit = addTraceHeaders(input, init);

return fetchFn(input, newInit);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

m/q: is this how we add our tracing headers in our core/browser fetch instrumentation as well? Just wanted to double check because injecting headers into fetch arguments is a bit tricky with the various forms of input and init and the precedence.

I think adding headers to init is fine. Though us deep-copying headers from input to init, and then init again might be unexpected if one of the objects is reused by users across multiple requests. Anyway, not saying something is off but that we should double check that this is how we do it in the other SDKs as well.

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.

3 participants