From b75567aaa94aebe1796b15a40e16ade44e905970 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Thu, 6 Aug 2026 10:25:13 +0200 Subject: [PATCH 1/2] feat(cloudflare)!: Set enableRpcTracePropagation to true by default --- MIGRATION.md | 2 +- .../no-propagation-worker-do/index.ts | 2 ++ .../worker-do-rpc-disabled/index.ts | 2 ++ .../index-sub-worker.ts | 1 + .../worker-workerentrypoint-rpc/index.ts | 7 ++++- .../workerentrypoint-do-rpc-disabled/index.ts | 2 ++ packages/cloudflare/src/client.ts | 5 ++-- packages/cloudflare/src/durableobject.ts | 4 +-- .../instrumentWorkerEntrypoint.ts | 2 +- .../instrumentations/worker/instrumentEnv.ts | 2 +- .../cloudflare/test/durableobject.test.ts | 21 +++++++++++++-- .../instrumentations/instrumentEnv.test.ts | 27 ++++++++++++++----- 12 files changed, 61 insertions(+), 16 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index cfaa4fa824c0..d9fc9a6f83f6 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -652,7 +652,7 @@ Sentry.init({ ); ``` -> **TODO(v11):** This might change to `enableRpcTracePropagation: true` by default. This depends on the outcomes of #20525 +- The `enableRpcTracePropagation` option now defaults to `true`. Trace context is propagated across RPC calls (service bindings, Durable Objects, WorkerEntrypoints) unless you explicitly set `enableRpcTracePropagation: false`. - The `instrumentPrototypeMethods` option of `instrumentDurableObjectWithSentry` was removed. Use `enableRpcTracePropagation` instead, which was introduced as its replacement in v10. diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/no-propagation-worker-do/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/no-propagation-worker-do/index.ts index 1b56811556cd..860ac79f51ab 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/no-propagation-worker-do/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/no-propagation-worker-do/index.ts @@ -18,6 +18,7 @@ export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + enableRpcTracePropagation: false, }), MyDurableObjectBase, ); @@ -27,6 +28,7 @@ export default Sentry.withSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + enableRpcTracePropagation: false, }), { async fetch(request, env) { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-do-rpc-disabled/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-do-rpc-disabled/index.ts index 9871523e7bbd..7f357e83bcce 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-do-rpc-disabled/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-do-rpc-disabled/index.ts @@ -21,6 +21,7 @@ export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + enableRpcTracePropagation: false, }), MyDurableObjectBase, ); @@ -30,6 +31,7 @@ export default Sentry.withSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + enableRpcTracePropagation: false, }), { async fetch(request, env) { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-workerentrypoint-rpc/index-sub-worker.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-workerentrypoint-rpc/index-sub-worker.ts index 6c8638be5ad1..29b9701459ef 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-workerentrypoint-rpc/index-sub-worker.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-workerentrypoint-rpc/index-sub-worker.ts @@ -62,6 +62,7 @@ export const NoPropagationEntrypoint = Sentry.withSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + enableRpcTracePropagation: false, transportOptions: { fetch: fetch.bind(globalThis) }, }), MySubWorkerEntrypointBase, diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-workerentrypoint-rpc/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-workerentrypoint-rpc/index.ts index d366e7d71afc..584c96ca254e 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-workerentrypoint-rpc/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/worker-workerentrypoint-rpc/index.ts @@ -20,7 +20,12 @@ class LoopbackEntrypointBase extends WorkerEntrypoint { } export const LoopbackEntrypoint = Sentry.withSentry( - (env: Env) => ({ dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 0 }), + (env: Env) => ({ + dsn: env.SENTRY_DSN, + traceLifecycle: 'static', + tracesSampleRate: 0, + enableRpcTracePropagation: false, + }), LoopbackEntrypointBase, ); diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/workerentrypoint-do-rpc-disabled/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/workerentrypoint-do-rpc-disabled/index.ts index 33889dbbb473..fd53867119bd 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/workerentrypoint-do-rpc-disabled/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/propagation/workerentrypoint-do-rpc-disabled/index.ts @@ -21,6 +21,7 @@ export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + enableRpcTracePropagation: false, }), MyDurableObjectBase, ); @@ -46,6 +47,7 @@ export default Sentry.withSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, + enableRpcTracePropagation: false, }), MyWorkerEntrypointBase, ); diff --git a/packages/cloudflare/src/client.ts b/packages/cloudflare/src/client.ts index 6acf72bd1fb4..8c814eae0250 100644 --- a/packages/cloudflare/src/client.ts +++ b/packages/cloudflare/src/client.ts @@ -200,9 +200,10 @@ interface BaseCloudflareOptions { * - Create spans for each RPC method invocation * - Capture errors thrown by RPC methods * - * **Important:** This option should be enabled on **both sides** for full trace propagation. + * **Important:** This option is enabled by default. Set it to `false` to opt out, e.g. if you + * do not want trace context to leave your Worker via RPC calls. * - * @default false + * @default true * @example * ```ts * // Worker side (caller) diff --git a/packages/cloudflare/src/durableobject.ts b/packages/cloudflare/src/durableobject.ts index ac6710e02bd6..4a6ea18204f6 100644 --- a/packages/cloudflare/src/durableobject.ts +++ b/packages/cloudflare/src/durableobject.ts @@ -274,8 +274,8 @@ export function finalizeWithRpcInstrumentation( context: InstrumentedDurableObjectContext, excludedMethods?: ReadonlySet, ): T { - // Skip RPC instrumentation if not enabled - if (!options.enableRpcTracePropagation) { + // Skip RPC instrumentation only when explicitly opted out (enabled by default) + if (options.enableRpcTracePropagation === false) { return obj; } diff --git a/packages/cloudflare/src/instrumentations/instrumentWorkerEntrypoint.ts b/packages/cloudflare/src/instrumentations/instrumentWorkerEntrypoint.ts index c2646ad32e5a..f92093f42792 100644 --- a/packages/cloudflare/src/instrumentations/instrumentWorkerEntrypoint.ts +++ b/packages/cloudflare/src/instrumentations/instrumentWorkerEntrypoint.ts @@ -94,7 +94,7 @@ function instrumentMethod( true, ); - if (!options.enableRpcTracePropagation) { + if (options.enableRpcTracePropagation === false) { return captureMethod; } diff --git a/packages/cloudflare/src/instrumentations/worker/instrumentEnv.ts b/packages/cloudflare/src/instrumentations/worker/instrumentEnv.ts index 5a440503a4ee..36a3b0659d65 100644 --- a/packages/cloudflare/src/instrumentations/worker/instrumentEnv.ts +++ b/packages/cloudflare/src/instrumentations/worker/instrumentEnv.ts @@ -91,7 +91,7 @@ export function instrumentEnv>(env: Env, opt return instrumented; } - if (!options?.enableRpcTracePropagation) { + if (options?.enableRpcTracePropagation === false) { return item; } diff --git a/packages/cloudflare/test/durableobject.test.ts b/packages/cloudflare/test/durableobject.test.ts index b7d94d5b5b1b..3830e779d4e3 100644 --- a/packages/cloudflare/test/durableobject.test.ts +++ b/packages/cloudflare/test/durableobject.test.ts @@ -317,13 +317,16 @@ describe('instrumentDurableObjectWithSentry', () => { expect(getInstrumented(obj.alarm)).toBeTruthy(); }); - it('Does not instrument RPC methods when enableRpcTracePropagation is not set', () => { + it('Does not instrument RPC methods when enableRpcTracePropagation is false', () => { const testClass = class { rpcMethod() { return 'result'; } }; - const instrumented = instrumentDurableObjectWithSentry(vi.fn().mockReturnValue({}), testClass as any); + const instrumented = instrumentDurableObjectWithSentry( + vi.fn().mockReturnValue({ enableRpcTracePropagation: false }), + testClass as any, + ); const obj = Reflect.construct(instrumented, []); // RPC method should not be wrapped @@ -331,6 +334,20 @@ describe('instrumentDurableObjectWithSentry', () => { expect(obj.rpcMethod()).toBe('result'); }); + it('instruments RPC methods by default when enableRpcTracePropagation is not set', () => { + const testClass = class { + rpcMethod() { + return 'result'; + } + }; + const instrumented = instrumentDurableObjectWithSentry(vi.fn().mockReturnValue({}), testClass as any); + const obj = Reflect.construct(instrumented, []); + + // RPC method should be wrapped on the prototype by default + expect(getInstrumented(obj.rpcMethod)).toBeTruthy(); + expect(obj.rpcMethod()).toBe('result'); + }); + it('does not wrap Object.prototype methods as RPC methods', () => { const testClass = class { rpcMethod() { diff --git a/packages/cloudflare/test/instrumentations/instrumentEnv.test.ts b/packages/cloudflare/test/instrumentations/instrumentEnv.test.ts index 72f9d0774507..f8390492cf82 100644 --- a/packages/cloudflare/test/instrumentations/instrumentEnv.test.ts +++ b/packages/cloudflare/test/instrumentations/instrumentEnv.test.ts @@ -82,13 +82,28 @@ describe('instrumentEnv', () => { newUniqueId: vi.fn(), }; const env = { COUNTER: doNamespace }; - const instrumented = instrumentEnv(env); + const instrumented = instrumentEnv(env, { enableRpcTracePropagation: false }); // DO bindings pass through untouched when RPC propagation is disabled expect(instrumented.COUNTER).toBe(doNamespace); expect(instrumentDurableObjectNamespace).not.toHaveBeenCalled(); }); + it('detects and instruments DurableObjectNamespace bindings by default', () => { + const doNamespace = { + idFromName: vi.fn(), + idFromString: vi.fn(), + get: vi.fn(), + newUniqueId: vi.fn(), + }; + const env = { COUNTER: doNamespace }; + const instrumented = instrumentEnv(env, {}); + + const result = instrumented.COUNTER; + expect(instrumentDurableObjectNamespace).toHaveBeenCalledWith(doNamespace); + expect((result as any).__instrumented).toBe(true); + }); + it('detects and instruments DurableObjectNamespace bindings when enableRpcTracePropagation is enabled', () => { const doNamespace = { idFromName: vi.fn(), @@ -160,7 +175,7 @@ describe('instrumentEnv', () => { }, ); const env = { SERVICE: jsrpcProxy }; - const instrumented = instrumentEnv(env); + const instrumented = instrumentEnv(env, { enableRpcTracePropagation: false }); const result = instrumented.SERVICE; // Should be the same reference — not wrapped when propagation is disabled @@ -346,7 +361,7 @@ describe('instrumentEnv', () => { const mockFetch = vi.fn(); const mtlsFetcher = createMtlsFetcherProxy(mockFetch); const env = { MY_CERT: mtlsFetcher }; - const instrumented = instrumentEnv(env); + const instrumented = instrumentEnv(env, { enableRpcTracePropagation: false }); expect(instrumented.MY_CERT).toBe(mtlsFetcher); }); @@ -378,7 +393,7 @@ describe('instrumentEnv', () => { }); describe('JSRPC RPC method instrumentation', () => { - it('does not inject Sentry RPC meta by default (enableRpcTracePropagation not set)', () => { + it('does not inject Sentry RPC meta when enableRpcTracePropagation is disabled', () => { vi.spyOn(SentryCore, 'getTraceData').mockReturnValue({ 'sentry-trace': '12345678901234567890123456789012-1234567890123456-1', baggage: 'sentry-environment=production', @@ -397,11 +412,11 @@ describe('instrumentEnv', () => { }, ); const env = { SERVICE: jsrpcProxy }; - const instrumented = instrumentEnv(env); + const instrumented = instrumentEnv(env, { enableRpcTracePropagation: false }); instrumented.SERVICE.myRpcMethod('arg1', 42); - // Without enableRpcTracePropagation, no metadata should be injected + // With enableRpcTracePropagation disabled, no metadata should be injected expect(rpcMethod).toHaveBeenCalledWith('arg1', 42); }); From 6e9cf9b5d0ae2a8757acfbad59d0271556d5dfa6 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Thu, 6 Aug 2026 17:03:16 +0200 Subject: [PATCH 2/2] fixup! feat(cloudflare)!: Set enableRpcTracePropagation to true by default --- packages/cloudflare/src/client.ts | 19 ++----------------- packages/cloudflare/src/durableobject.ts | 4 ++-- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/packages/cloudflare/src/client.ts b/packages/cloudflare/src/client.ts index 8c814eae0250..55fbe1a605cc 100644 --- a/packages/cloudflare/src/client.ts +++ b/packages/cloudflare/src/client.ts @@ -206,29 +206,14 @@ interface BaseCloudflareOptions { * @default true * @example * ```ts - * // Worker side (caller) + * // Opt out of RPC trace propagation * export default Sentry.withSentry( * (env) => ({ * dsn: env.SENTRY_DSN, - * enableRpcTracePropagation: true, + * enableRpcTracePropagation: false, * }), * handler, * ); - * - * // Durable Object side (receiver) - * export const MyDO = Sentry.instrumentDurableObjectWithSentry( - * (env) => ({ - * dsn: env.SENTRY_DSN, - * enableRpcTracePropagation: true, - * }), - * MyDOBase, - * ); - * - * // WorkerEntrypoint side (receiver) - * export const MyEntrypoint = Sentry.withSentry( - * env => ({ dsn: env.SENTRY_DSN, enableRpcTracePropagation: true }), - * MyEntrypointBase, - * ); * ``` */ enableRpcTracePropagation?: boolean; diff --git a/packages/cloudflare/src/durableobject.ts b/packages/cloudflare/src/durableobject.ts index 4a6ea18204f6..d0f740c214b2 100644 --- a/packages/cloudflare/src/durableobject.ts +++ b/packages/cloudflare/src/durableobject.ts @@ -399,7 +399,8 @@ function createRpcPrototypeWrapper(methodName: string, originalMethod: Unchecked * - webSocketClose * - webSocketError * - * To instrument RPC methods (prototype methods), enable the `enableRpcTracePropagation` option. + * RPC methods (prototype methods) are instrumented by default. Set `enableRpcTracePropagation` + * to `false` to opt out. * * @param optionsCallback Function that returns the options for the SDK initialization. * @param DurableObjectClass The Durable Object class to instrument. @@ -478,7 +479,6 @@ export function instrumentDurableObjectWithSentry< * env => ({ * dsn: env.SENTRY_DSN, * tracesSampleRate: 1.0, - * enableRpcTracePropagation: true, * }), * MyAgentBase, * );