Skip to content

Commit fd592c6

Browse files
committed
feat(cloudflare): Read SENTRY_RELEASE from env
1 parent 0c983b3 commit fd592c6

File tree

2 files changed

+127
-2
lines changed

2 files changed

+127
-2
lines changed

packages/cloudflare/src/handler.ts

+18-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ export function withSentry<Env = unknown, QueueHandlerMessage = unknown, CfHostM
3535
handler.fetch = new Proxy(handler.fetch, {
3636
apply(target, thisArg, args: Parameters<ExportedHandlerFetchHandler<Env, CfHostMetadata>>) {
3737
const [request, env, context] = args;
38-
const options = optionsCallback(env);
38+
const callbackOptions = optionsCallback(env);
39+
40+
const options = { ...getOptionsFromEnv(env), ...callbackOptions };
41+
3942
return wrapRequestHandler({ options, request, context }, () => target.apply(thisArg, args));
4043
},
4144
});
@@ -48,7 +51,10 @@ export function withSentry<Env = unknown, QueueHandlerMessage = unknown, CfHostM
4851
apply(target, thisArg, args: Parameters<ExportedHandlerScheduledHandler<Env>>) {
4952
const [event, env, context] = args;
5053
return withIsolationScope(isolationScope => {
51-
const options = optionsCallback(env);
54+
const callbackOptions = optionsCallback(env);
55+
56+
const options = { ...getOptionsFromEnv(env), ...callbackOptions };
57+
5258
const client = init(options);
5359
isolationScope.setClient(client);
5460

@@ -91,3 +97,13 @@ export function withSentry<Env = unknown, QueueHandlerMessage = unknown, CfHostM
9197

9298
return handler;
9399
}
100+
101+
function getOptionsFromEnv(env: unknown): CloudflareOptions {
102+
if (typeof env !== 'object' || env === null) {
103+
return {};
104+
}
105+
106+
return {
107+
release: 'SENTRY_RELEASE' in env && typeof env.SENTRY_RELEASE === 'string' ? env.SENTRY_RELEASE : undefined,
108+
};
109+
}

packages/cloudflare/test/handler.test.ts

+109
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { withSentry } from '../src/handler';
1010

1111
const MOCK_ENV = {
1212
SENTRY_DSN: 'https://public@dsn.ingest.sentry.io/1337',
13+
SENTRY_RELEASE: '1.1.1',
1314
};
1415

1516
describe('withSentry', () => {
@@ -51,6 +52,65 @@ describe('withSentry', () => {
5152

5253
expect(result).toBe(response);
5354
});
55+
56+
test('merges options from env and callback', async () => {
57+
const handler = {
58+
fetch(_request, _env, _context) {
59+
throw new Error('test');
60+
},
61+
} satisfies ExportedHandler<typeof MOCK_ENV>;
62+
63+
let sentryEvent: Event = {};
64+
65+
const wrappedHandler = withSentry(
66+
env => ({
67+
dsn: env.SENTRY_DSN,
68+
beforeSend(event) {
69+
sentryEvent = event;
70+
return null;
71+
},
72+
}),
73+
handler,
74+
);
75+
76+
try {
77+
await wrappedHandler.fetch(new Request('https://example.com'), MOCK_ENV, createMockExecutionContext());
78+
} catch {
79+
// ignore
80+
}
81+
82+
expect(sentryEvent.release).toEqual('1.1.1');
83+
});
84+
85+
test('callback options take precedence over env options', async () => {
86+
const handler = {
87+
fetch(_request, _env, _context) {
88+
throw new Error('test');
89+
},
90+
} satisfies ExportedHandler<typeof MOCK_ENV>;
91+
92+
let sentryEvent: Event = {};
93+
94+
const wrappedHandler = withSentry(
95+
env => ({
96+
dsn: env.SENTRY_DSN,
97+
release: '2.0.0',
98+
beforeSend(event) {
99+
sentryEvent = event;
100+
return null;
101+
},
102+
}),
103+
handler,
104+
);
105+
106+
try {
107+
await wrappedHandler.fetch(new Request('https://example.com'), MOCK_ENV, createMockExecutionContext());
108+
} catch {
109+
// ignore
110+
}
111+
112+
expect(sentryEvent.release).toEqual('2.0.0');
113+
});
54114
});
55115

56116
describe('scheduled handler', () => {
@@ -70,6 +130,55 @@ describe('withSentry', () => {
70130
expect(optionsCallback).toHaveBeenLastCalledWith(MOCK_ENV);
71131
});
72132

133+
test('merges options from env and callback', async () => {
134+
const handler = {
135+
scheduled(_controller, _env, _context) {
136+
SentryCore.captureMessage('cloud_resource');
137+
return;
138+
},
139+
} satisfies ExportedHandler<typeof MOCK_ENV>;
140+
141+
let sentryEvent: Event = {};
142+
const wrappedHandler = withSentry(
143+
env => ({
144+
dsn: env.SENTRY_DSN,
145+
beforeSend(event) {
146+
sentryEvent = event;
147+
return null;
148+
},
149+
}),
150+
handler,
151+
);
152+
await wrappedHandler.scheduled(createMockScheduledController(), MOCK_ENV, createMockExecutionContext());
153+
154+
expect(sentryEvent.release).toBe('1.1.1');
155+
});
156+
157+
test('callback options take precedence over env options', async () => {
158+
const handler = {
159+
scheduled(_controller, _env, _context) {
160+
SentryCore.captureMessage('cloud_resource');
161+
return;
162+
},
163+
} satisfies ExportedHandler<typeof MOCK_ENV>;
164+
165+
let sentryEvent: Event = {};
166+
const wrappedHandler = withSentry(
167+
env => ({
168+
dsn: env.SENTRY_DSN,
169+
release: '2.0.0',
170+
beforeSend(event) {
171+
sentryEvent = event;
172+
return null;
173+
},
174+
}),
175+
handler,
176+
);
177+
await wrappedHandler.scheduled(createMockScheduledController(), MOCK_ENV, createMockExecutionContext());
178+
179+
expect(sentryEvent.release).toEqual('2.0.0');
180+
});
181+
73182
test('flushes the event after the handler is done using the cloudflare context.waitUntil', async () => {
74183
const handler = {
75184
scheduled(_controller, _env, _context) {

0 commit comments

Comments
 (0)