From caf49563ce37fb79e245b1b3ae1bf1d2fd8e74a8 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 12 Sep 2025 12:29:03 +0200 Subject: [PATCH 1/5] ref(cloudflare): Adjust event `mechanism`s and durable object origin --- .../cloudflare-integration-tests/suites/basic/test.ts | 2 +- .../suites/tracing/durableobject/test.ts | 4 ++-- .../cloudflare-workers/tests/index.test.ts | 8 ++++---- packages/cloudflare/src/durableobject.ts | 8 ++++---- packages/cloudflare/src/handler.ts | 10 +++++----- packages/cloudflare/src/request.ts | 4 ++-- packages/cloudflare/src/workflows.ts | 2 +- packages/cloudflare/test/handler.test.ts | 10 +++++----- packages/cloudflare/test/request.test.ts | 2 +- packages/cloudflare/test/workflow.test.ts | 2 +- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/dev-packages/cloudflare-integration-tests/suites/basic/test.ts b/dev-packages/cloudflare-integration-tests/suites/basic/test.ts index 1bd7b4bac094..b785e6e37fd1 100644 --- a/dev-packages/cloudflare-integration-tests/suites/basic/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/basic/test.ts @@ -15,7 +15,7 @@ it('Basic error in fetch handler', async () => { stacktrace: { frames: expect.any(Array), }, - mechanism: { type: 'cloudflare', handled: false }, + mechanism: { type: 'auto.http.cloudflare', handled: false }, }, ], }, diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject/test.ts index cfb6841004a9..a9daae21480f 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject/test.ts @@ -12,9 +12,9 @@ it('traces a durable object method', async () => { op: 'rpc', data: expect.objectContaining({ 'sentry.op': 'rpc', - 'sentry.origin': 'auto.faas.cloudflare_durableobjects', + 'sentry.origin': 'auto.faas.cloudflare.durable_object', }), - origin: 'auto.faas.cloudflare_durableobjects', + origin: 'auto.faas.cloudflare.durable_object', }), }), transaction: 'sayHello', diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts b/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts index 31cc02b8c5e8..3888ea9c7dcc 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts @@ -20,7 +20,7 @@ test("worker's withSentry", async ({ baseURL }) => { test('RPC method which throws an exception to be logged to sentry', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; }); const response = await fetch(`${baseURL}/rpc/throwException`); expect(response.status).toBe(500); @@ -29,7 +29,7 @@ test('RPC method which throws an exception to be logged to sentry', async ({ bas }); test("Request processed by DurableObject's fetch is recorded", async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; }); const response = await fetch(`${baseURL}/pass-to-object/throwException`); expect(response.status).toBe(500); @@ -38,7 +38,7 @@ test("Request processed by DurableObject's fetch is recorded", async ({ baseURL }); test('Websocket.webSocketMessage', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; }); const url = new URL('/pass-to-object/ws', baseURL); url.protocol = url.protocol.replace('http', 'ws'); @@ -53,7 +53,7 @@ test('Websocket.webSocketMessage', async ({ baseURL }) => { test('Websocket.webSocketClose', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; }); const url = new URL('/pass-to-object/ws', baseURL); url.protocol = url.protocol.replace('http', 'ws'); diff --git a/packages/cloudflare/src/durableobject.ts b/packages/cloudflare/src/durableobject.ts index bda7a9aa3538..0310d4066d21 100644 --- a/packages/cloudflare/src/durableobject.ts +++ b/packages/cloudflare/src/durableobject.ts @@ -79,7 +79,7 @@ function wrapMethodWithSentry( (e: unknown) => { captureException(e, { mechanism: { - type: 'cloudflare_durableobject', + type: 'auto.faas.cloudflare.durable_object', handled: false, }, }); @@ -106,7 +106,7 @@ function wrapMethodWithSentry( const attributes = wrapperOptions.spanOp ? { [SEMANTIC_ATTRIBUTE_SENTRY_OP]: wrapperOptions.spanOp, - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare_durableobjects', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.durable_object', } : {}; @@ -123,7 +123,7 @@ function wrapMethodWithSentry( (e: unknown) => { captureException(e, { mechanism: { - type: 'cloudflare_durableobject', + type: 'auto.faas.cloudflare.durable_object', handled: false, }, }); @@ -138,7 +138,7 @@ function wrapMethodWithSentry( } catch (e) { captureException(e, { mechanism: { - type: 'cloudflare_durableobject', + type: 'auto.faas.cloudflare.durable_object', handled: false, }, }); diff --git a/packages/cloudflare/src/handler.ts b/packages/cloudflare/src/handler.ts index 354233154a0b..a6e5983902c6 100644 --- a/packages/cloudflare/src/handler.ts +++ b/packages/cloudflare/src/handler.ts @@ -59,7 +59,7 @@ export function withSentry); } catch (e) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.scheduled' } }); throw e; } finally { waitUntil(flush(2000)); @@ -138,7 +138,7 @@ export function withSentry); } catch (e) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.email' } }); throw e; } finally { waitUntil(flush(2000)); @@ -188,7 +188,7 @@ export function withSentry); } catch (e) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.queue' } }); throw e; } finally { waitUntil(flush(2000)); @@ -220,7 +220,7 @@ export function withSentry); } catch (e) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.tail' } }); throw e; } finally { waitUntil(flush(2000)); diff --git a/packages/cloudflare/src/request.ts b/packages/cloudflare/src/request.ts index 45fe548696ab..5c97562d9fde 100644 --- a/packages/cloudflare/src/request.ts +++ b/packages/cloudflare/src/request.ts @@ -84,7 +84,7 @@ export function wrapRequestHandler( return await handler(); } catch (e) { if (captureErrors) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } }); } throw e; } finally { @@ -110,7 +110,7 @@ export function wrapRequestHandler( return res; } catch (e) { if (captureErrors) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } }); } throw e; } finally { diff --git a/packages/cloudflare/src/workflows.ts b/packages/cloudflare/src/workflows.ts index 97726e9b9270..336df2abe301 100644 --- a/packages/cloudflare/src/workflows.ts +++ b/packages/cloudflare/src/workflows.ts @@ -103,7 +103,7 @@ class WrappedWorkflowStep implements WorkflowStep { span.setStatus({ code: 1 }); return result; } catch (error) { - captureException(error, { mechanism: { handled: true, type: 'cloudflare' } }); + captureException(error, { mechanism: { handled: true, type: 'auto.faas.cloudflare.workflow' } }); throw error; } finally { this._ctx.waitUntil(flush(2000)); diff --git a/packages/cloudflare/test/handler.test.ts b/packages/cloudflare/test/handler.test.ts index ddd4b0010ec0..97e93199ea31 100644 --- a/packages/cloudflare/test/handler.test.ts +++ b/packages/cloudflare/test/handler.test.ts @@ -305,7 +305,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.faas.cloudflare.scheduled' }, }); }); @@ -545,7 +545,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.faas.cloudflare.email' }, }); }); @@ -784,7 +784,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.faas.cloudflare.queue' }, }); }); @@ -1027,7 +1027,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.faas.cloudflare.tail' }, }); }); @@ -1102,7 +1102,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.faas.cloudflare.error_handler' }, }); expect(errorHandlerResponse?.status).toBe(500); }); diff --git a/packages/cloudflare/test/request.test.ts b/packages/cloudflare/test/request.test.ts index ad323e3c5b5a..d6d0de5824a1 100644 --- a/packages/cloudflare/test/request.test.ts +++ b/packages/cloudflare/test/request.test.ts @@ -192,7 +192,7 @@ describe('withSentry', () => { expect(captureExceptionSpy).toHaveBeenCalledTimes(1); expect(captureExceptionSpy).toHaveBeenLastCalledWith(error, { - mechanism: { handled: false, type: 'cloudflare' }, + mechanism: { handled: false, type: 'auto.http.cloudflare' }, }); }); diff --git a/packages/cloudflare/test/workflow.test.ts b/packages/cloudflare/test/workflow.test.ts index e1a6c87e5279..2ca2ccd28e46 100644 --- a/packages/cloudflare/test/workflow.test.ts +++ b/packages/cloudflare/test/workflow.test.ts @@ -272,7 +272,7 @@ describe.skipIf(NODE_MAJOR_VERSION < 20)('workflows', () => { expect.objectContaining({ type: 'Error', value: 'Test error', - mechanism: { type: 'cloudflare', handled: true }, + mechanism: { type: 'auto.faas.cloudflare.workflow', handled: true }, }), ], }, From 2a511149f6d53eb8b0345aeacbff0c748f9a5967 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 12 Sep 2025 13:08:31 +0200 Subject: [PATCH 2/5] one more mechanism --- packages/cloudflare/src/durableobject.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cloudflare/src/durableobject.ts b/packages/cloudflare/src/durableobject.ts index 0310d4066d21..135f9d45e3ef 100644 --- a/packages/cloudflare/src/durableobject.ts +++ b/packages/cloudflare/src/durableobject.ts @@ -94,7 +94,7 @@ function wrapMethodWithSentry( } catch (e) { captureException(e, { mechanism: { - type: 'cloudflare_durableobject', + type: 'auto.faas.cloudflare.durable_object', handled: false, }, }); From 6bca21d1af2d5d48c3aedbde0ed7719d5309cbb9 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 12 Sep 2025 16:15:58 +0200 Subject: [PATCH 3/5] fix test? --- .../cloudflare-workers/tests/index.test.ts | 7 +++++-- packages/cloudflare/src/durableobject.ts | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts b/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts index 3888ea9c7dcc..db84e77790df 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts @@ -27,18 +27,21 @@ test('RPC method which throws an exception to be logged to sentry', async ({ bas const event = await eventWaiter; expect(event.exception?.values?.[0]?.value).toBe('Should be recorded in Sentry.'); }); + test("Request processed by DurableObject's fetch is recorded", async ({ baseURL }) => { + console.log('xx Request processed by DurableObject'); const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; + return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; }); const response = await fetch(`${baseURL}/pass-to-object/throwException`); expect(response.status).toBe(500); const event = await eventWaiter; expect(event.exception?.values?.[0]?.value).toBe('Should be recorded in Sentry.'); }); + test('Websocket.webSocketMessage', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; + return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; }); const url = new URL('/pass-to-object/ws', baseURL); url.protocol = url.protocol.replace('http', 'ws'); diff --git a/packages/cloudflare/src/durableobject.ts b/packages/cloudflare/src/durableobject.ts index 135f9d45e3ef..0f139a80ccd0 100644 --- a/packages/cloudflare/src/durableobject.ts +++ b/packages/cloudflare/src/durableobject.ts @@ -243,7 +243,7 @@ export function instrumentDurableObjectWithSentry< (_, error) => captureException(error, { mechanism: { - type: 'cloudflare_durableobject_websocket', + type: 'auto.faas.cloudflare.durable_object_websocket', handled: false, }, }), From 754858eb84ec9ade59bd90e4365b505a8671d338 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 12 Sep 2025 17:10:40 +0200 Subject: [PATCH 4/5] . --- .../cloudflare-workers/tests/index.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts b/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts index db84e77790df..f1e6be31608e 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts @@ -31,7 +31,7 @@ test('RPC method which throws an exception to be logged to sentry', async ({ bas test("Request processed by DurableObject's fetch is recorded", async ({ baseURL }) => { console.log('xx Request processed by DurableObject'); const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; }); const response = await fetch(`${baseURL}/pass-to-object/throwException`); expect(response.status).toBe(500); @@ -41,7 +41,7 @@ test("Request processed by DurableObject's fetch is recorded", async ({ baseURL test('Websocket.webSocketMessage', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare_durableobject'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object_websocket'; }); const url = new URL('/pass-to-object/ws', baseURL); url.protocol = url.protocol.replace('http', 'ws'); @@ -56,7 +56,7 @@ test('Websocket.webSocketMessage', async ({ baseURL }) => { test('Websocket.webSocketClose', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object_websocket'; }); const url = new URL('/pass-to-object/ws', baseURL); url.protocol = url.protocol.replace('http', 'ws'); From b020db7afcb10bd581b7bc22942c6c013347358b Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Mon, 15 Sep 2025 16:03:03 +0200 Subject: [PATCH 5/5] fix test for realz? --- CHANGELOG.md | 1 + .../cloudflare-workers/playwright.config.ts | 1 + .../cloudflare-workers/tests/index.test.ts | 7 +++---- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b470228dcc7b..21fbb2ccfd42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - ref(astro): Adjust `mechanism` on error events captured by astro middleware ([#17613](https://github.com/getsentry/sentry-javascript/pull/17613)) - ref(aws-severless): Slightly adjust aws-serverless mechanism type ([#17614](https://github.com/getsentry/sentry-javascript/pull/17614)) - ref(bun): Adjust `mechanism` of errors captured in Bun.serve ([#17616](https://github.com/getsentry/sentry-javascript/pull/17616)) + - ref(cloudflare): Adjust event `mechanisms` and durable object origin ([#17618](https://github.com/getsentry/sentry-javascript/pull/17618)) - ref(core): Adjust `mechanism` in `captureConsoleIntegration` ([#17633](https://github.com/getsentry/sentry-javascript/pull/17633)) - ref(core): Adjust MCP server error event `mechanism` ([#17622](https://github.com/getsentry/sentry-javascript/pull/17622)) - ref(core): Simplify `linkedErrors` mechanism logic ([#17600](https://github.com/getsentry/sentry-javascript/pull/17600)) diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-workers/playwright.config.ts b/dev-packages/e2e-tests/test-applications/cloudflare-workers/playwright.config.ts index c69c955fafd8..73abbd951b90 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-workers/playwright.config.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-workers/playwright.config.ts @@ -15,6 +15,7 @@ const config = getPlaywrightConfig( { // This comes with the risk of tests leaking into each other but the tests run quite slow so we should parallelize workers: '100%', + retries: 0, }, ); diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts b/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts index f1e6be31608e..df8e655416fb 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts @@ -10,7 +10,7 @@ test('Index page', async ({ baseURL }) => { test("worker's withSentry", async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'cloudflare'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.http.cloudflare'; }); const response = await fetch(`${baseURL}/throwException`); expect(response.status).toBe(500); @@ -29,7 +29,6 @@ test('RPC method which throws an exception to be logged to sentry', async ({ bas }); test("Request processed by DurableObject's fetch is recorded", async ({ baseURL }) => { - console.log('xx Request processed by DurableObject'); const eventWaiter = waitForError('cloudflare-workers', event => { return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; }); @@ -41,7 +40,7 @@ test("Request processed by DurableObject's fetch is recorded", async ({ baseURL test('Websocket.webSocketMessage', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object_websocket'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; }); const url = new URL('/pass-to-object/ws', baseURL); url.protocol = url.protocol.replace('http', 'ws'); @@ -56,7 +55,7 @@ test('Websocket.webSocketMessage', async ({ baseURL }) => { test('Websocket.webSocketClose', async ({ baseURL }) => { const eventWaiter = waitForError('cloudflare-workers', event => { - return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object_websocket'; + return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object'; }); const url = new URL('/pass-to-object/ws', baseURL); url.protocol = url.protocol.replace('http', 'ws');