Skip to content

Commit b8e7422

Browse files
authored
feat(cloudflare): Add option to opt out of capturing errors in wrapRequestHandler (#16852)
Add a `captureErrors` option to the `wrapRequestHandler` options from `@sentry/cloudflare`. While by default, the wrapper should capture exceptions (for example, when it's used in pure CF worker functions), it shouldn't do that when it's used in higher-level SDKs, like SvelteKit. There, we want our other error capturing implementations to do the job.
1 parent 60063e8 commit b8e7422

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

packages/cloudflare/src/request.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ interface RequestHandlerWrapperOptions {
1818
options: CloudflareOptions;
1919
request: Request<unknown, IncomingRequestCfProperties<unknown>>;
2020
context: ExecutionContext;
21+
/**
22+
* If true, errors will be captured, rethrown and sent to Sentry.
23+
* Otherwise, errors are rethrown but not captured.
24+
*
25+
* You most likely don't want to set this to `false`, if you use `wrapRequestHandler` directly.
26+
* This is primarily meant as an escape hatch for higher-level SDKs relying on additional error
27+
* capturing mechanisms where this wrapper captures errors too early or too generally.
28+
*
29+
* @default true
30+
*/
31+
captureErrors?: boolean;
2132
}
2233

2334
/**
@@ -28,7 +39,7 @@ export function wrapRequestHandler(
2839
handler: (...args: unknown[]) => Response | Promise<Response>,
2940
): Promise<Response> {
3041
return withIsolationScope(async isolationScope => {
31-
const { options, request } = wrapperOptions;
42+
const { options, request, captureErrors = true } = wrapperOptions;
3243

3344
// In certain situations, the passed context can become undefined.
3445
// For example, for Astro while prerendering pages at build time.
@@ -67,7 +78,9 @@ export function wrapRequestHandler(
6778
try {
6879
return await handler();
6980
} catch (e) {
70-
captureException(e, { mechanism: { handled: false, type: 'cloudflare' } });
81+
if (captureErrors) {
82+
captureException(e, { mechanism: { handled: false, type: 'cloudflare' } });
83+
}
7184
throw e;
7285
} finally {
7386
waitUntil?.(flush(2000));
@@ -91,7 +104,9 @@ export function wrapRequestHandler(
91104
setHttpStatus(span, res.status);
92105
return res;
93106
} catch (e) {
94-
captureException(e, { mechanism: { handled: false, type: 'cloudflare' } });
107+
if (captureErrors) {
108+
captureException(e, { mechanism: { handled: false, type: 'cloudflare' } });
109+
}
95110
throw e;
96111
} finally {
97112
waitUntil?.(flush(2000));

packages/cloudflare/test/request.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,33 @@ describe('withSentry', () => {
212212

213213
expect(thrownError).toBe(error);
214214
});
215+
216+
test("doesn't capture errors if `captureErrors` is false", async () => {
217+
const captureExceptionSpy = vi.spyOn(SentryCore, 'captureException');
218+
const error = new Error('test');
219+
220+
expect(captureExceptionSpy).not.toHaveBeenCalled();
221+
let thrownError: Error | undefined;
222+
223+
try {
224+
await wrapRequestHandler(
225+
{
226+
options: MOCK_OPTIONS,
227+
request: new Request('https://example.com'),
228+
context: createMockExecutionContext(),
229+
captureErrors: false,
230+
},
231+
() => {
232+
throw error;
233+
},
234+
);
235+
} catch (e: any) {
236+
thrownError = e;
237+
}
238+
239+
expect(captureExceptionSpy).not.toHaveBeenCalled();
240+
expect(thrownError).toBe(error);
241+
});
215242
});
216243

217244
describe('tracing instrumentation', () => {

0 commit comments

Comments
 (0)