diff --git a/MIGRATION.md b/MIGRATION.md index 7f4b90b975fa..7b727b8c2cac 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -745,8 +745,6 @@ Sentry.init({ ); ``` -- 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 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 860ac79f51ab..1b56811556cd 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,7 +18,6 @@ export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, - enableRpcTracePropagation: false, }), MyDurableObjectBase, ); @@ -28,7 +27,6 @@ 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 7f357e83bcce..9871523e7bbd 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,7 +21,6 @@ export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, - enableRpcTracePropagation: false, }), MyDurableObjectBase, ); @@ -31,7 +30,6 @@ 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 29b9701459ef..6c8638be5ad1 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,7 +62,6 @@ 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 584c96ca254e..d366e7d71afc 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,12 +20,7 @@ class LoopbackEntrypointBase extends WorkerEntrypoint { } export const LoopbackEntrypoint = Sentry.withSentry( - (env: Env) => ({ - dsn: env.SENTRY_DSN, - traceLifecycle: 'static', - tracesSampleRate: 0, - enableRpcTracePropagation: false, - }), + (env: Env) => ({ dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 0 }), 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 fd53867119bd..33889dbbb473 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,7 +21,6 @@ export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry( dsn: env.SENTRY_DSN, traceLifecycle: 'static', tracesSampleRate: 1.0, - enableRpcTracePropagation: false, }), MyDurableObjectBase, ); @@ -47,7 +46,6 @@ 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 46f3983d8ff0..f1b74d5a4195 100644 --- a/packages/cloudflare/src/client.ts +++ b/packages/cloudflare/src/client.ts @@ -200,20 +200,34 @@ interface BaseCloudflareOptions { * - Create spans for each RPC method invocation * - Capture errors thrown by RPC methods * - * **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. + * **Important:** This option should be enabled on **both sides** for full trace propagation. * - * @default true + * @default false * @example * ```ts - * // Opt out of RPC trace propagation + * // Worker side (caller) * export default Sentry.withSentry( * (env) => ({ * dsn: env.SENTRY_DSN, - * enableRpcTracePropagation: false, + * enableRpcTracePropagation: true, * }), * 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 60236033d698..b5fe1a86bcd6 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 only when explicitly opted out (enabled by default) - if (options.enableRpcTracePropagation === false) { + // Skip RPC instrumentation if not enabled + if (!options.enableRpcTracePropagation) { return obj; } @@ -403,8 +403,7 @@ function createRpcPrototypeWrapper(methodName: string, originalMethod: Unchecked * - webSocketClose * - webSocketError * - * RPC methods (prototype methods) are instrumented by default. Set `enableRpcTracePropagation` - * to `false` to opt out. + * To instrument RPC methods (prototype methods), enable the `enableRpcTracePropagation` option. * * @param optionsCallback Function that returns the options for the SDK initialization. * @param DurableObjectClass The Durable Object class to instrument. @@ -483,6 +482,7 @@ export function instrumentDurableObjectWithSentry< * env => ({ * dsn: env.SENTRY_DSN, * tracesSampleRate: 1.0, + * enableRpcTracePropagation: true, * }), * MyAgentBase, * ); diff --git a/packages/cloudflare/src/instrumentations/instrumentWorkerEntrypoint.ts b/packages/cloudflare/src/instrumentations/instrumentWorkerEntrypoint.ts index f92093f42792..c2646ad32e5a 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 === false) { + if (!options.enableRpcTracePropagation) { return captureMethod; } diff --git a/packages/cloudflare/src/instrumentations/worker/instrumentEnv.ts b/packages/cloudflare/src/instrumentations/worker/instrumentEnv.ts index 36a3b0659d65..5a440503a4ee 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 === false) { + if (!options?.enableRpcTracePropagation) { return item; } diff --git a/packages/cloudflare/test/durableobject.test.ts b/packages/cloudflare/test/durableobject.test.ts index bb6b79717664..44d4bf25d12b 100644 --- a/packages/cloudflare/test/durableobject.test.ts +++ b/packages/cloudflare/test/durableobject.test.ts @@ -317,16 +317,13 @@ describe('instrumentDurableObjectWithSentry', () => { expect(getInstrumented(obj.alarm)).toBeTruthy(); }); - it('Does not instrument RPC methods when enableRpcTracePropagation is false', () => { + it('Does not instrument RPC methods when enableRpcTracePropagation is not set', () => { const testClass = class { rpcMethod() { return 'result'; } }; - const instrumented = instrumentDurableObjectWithSentry( - vi.fn().mockReturnValue({ enableRpcTracePropagation: false }), - testClass as any, - ); + const instrumented = instrumentDurableObjectWithSentry(vi.fn().mockReturnValue({}), testClass as any); const obj = Reflect.construct(instrumented, []); // RPC method should not be wrapped @@ -334,20 +331,6 @@ 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('skips non-configurable prototype methods instead of failing construction', () => { const testClass = class { sealedMethod() { diff --git a/packages/cloudflare/test/instrumentations/instrumentEnv.test.ts b/packages/cloudflare/test/instrumentations/instrumentEnv.test.ts index f8390492cf82..72f9d0774507 100644 --- a/packages/cloudflare/test/instrumentations/instrumentEnv.test.ts +++ b/packages/cloudflare/test/instrumentations/instrumentEnv.test.ts @@ -82,28 +82,13 @@ describe('instrumentEnv', () => { newUniqueId: vi.fn(), }; const env = { COUNTER: doNamespace }; - const instrumented = instrumentEnv(env, { enableRpcTracePropagation: false }); + const instrumented = instrumentEnv(env); // 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(), @@ -175,7 +160,7 @@ describe('instrumentEnv', () => { }, ); const env = { SERVICE: jsrpcProxy }; - const instrumented = instrumentEnv(env, { enableRpcTracePropagation: false }); + const instrumented = instrumentEnv(env); const result = instrumented.SERVICE; // Should be the same reference — not wrapped when propagation is disabled @@ -361,7 +346,7 @@ describe('instrumentEnv', () => { const mockFetch = vi.fn(); const mtlsFetcher = createMtlsFetcherProxy(mockFetch); const env = { MY_CERT: mtlsFetcher }; - const instrumented = instrumentEnv(env, { enableRpcTracePropagation: false }); + const instrumented = instrumentEnv(env); expect(instrumented.MY_CERT).toBe(mtlsFetcher); }); @@ -393,7 +378,7 @@ describe('instrumentEnv', () => { }); describe('JSRPC RPC method instrumentation', () => { - it('does not inject Sentry RPC meta when enableRpcTracePropagation is disabled', () => { + it('does not inject Sentry RPC meta by default (enableRpcTracePropagation not set)', () => { vi.spyOn(SentryCore, 'getTraceData').mockReturnValue({ 'sentry-trace': '12345678901234567890123456789012-1234567890123456-1', baggage: 'sentry-environment=production', @@ -412,11 +397,11 @@ describe('instrumentEnv', () => { }, ); const env = { SERVICE: jsrpcProxy }; - const instrumented = instrumentEnv(env, { enableRpcTracePropagation: false }); + const instrumented = instrumentEnv(env); instrumented.SERVICE.myRpcMethod('arg1', 42); - // With enableRpcTracePropagation disabled, no metadata should be injected + // Without enableRpcTracePropagation, no metadata should be injected expect(rpcMethod).toHaveBeenCalledWith('arg1', 42); });