Skip to content

Commit b9178db

Browse files
committed
Set shouldHandleError in integration
1 parent fc2159e commit b9178db

File tree

16 files changed

+704
-60
lines changed

16 files changed

+704
-60
lines changed

dev-packages/e2e-tests/test-applications/node-fastify-3/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
"private": true,
55
"scripts": {
66
"start": "ts-node src/app.ts",
7+
"start:override": "ts-node src/app-handle-error-override.ts",
78
"test": "playwright test",
9+
"test:override": "playwright test --config playwright.override.config.mjs",
810
"clean": "npx rimraf node_modules pnpm-lock.yaml",
911
"typecheck": "tsc",
1012
"test:build": "pnpm install && pnpm run typecheck",
11-
"test:assert": "pnpm test"
13+
"test:assert": "pnpm test && pnpm test:override"
1214
},
1315
"dependencies": {
1416
"@sentry/node": "latest || *",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { getPlaywrightConfig } from '@sentry-internal/test-utils';
2+
3+
const config = getPlaywrightConfig({
4+
startCommand: `pnpm start:override`,
5+
});
6+
7+
export default config;
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import type * as S from '@sentry/node';
2+
const Sentry = require('@sentry/node') as typeof S;
3+
4+
// We wrap console.warn to find out if a warning is incorrectly logged
5+
console.warn = new Proxy(console.warn, {
6+
apply: function (target, thisArg, argumentsList) {
7+
const msg = argumentsList[0];
8+
if (typeof msg === 'string' && msg.startsWith('[Sentry]')) {
9+
console.error(`Sentry warning was triggered: ${msg}`);
10+
process.exit(1);
11+
}
12+
13+
return target.apply(thisArg, argumentsList);
14+
},
15+
});
16+
17+
Sentry.init({
18+
environment: 'qa', // dynamic sampling bias to keep transactions
19+
dsn: process.env.E2E_TEST_DSN,
20+
integrations: [
21+
Sentry.fastifyIntegration({
22+
shouldHandleError: (error, _request, _reply) => {
23+
return true;
24+
},
25+
}),
26+
],
27+
tracesSampleRate: 1,
28+
tunnel: 'http://localhost:3031/', // proxy server
29+
tracePropagationTargets: ['http://localhost:3030', '/external-allowed'],
30+
});
31+
32+
import type * as H from 'http';
33+
import type * as F from 'fastify';
34+
35+
// Make sure fastify is imported after Sentry is initialized
36+
const { fastify } = require('fastify') as typeof F;
37+
const http = require('http') as typeof H;
38+
39+
const app = fastify();
40+
const port = 3030;
41+
const port2 = 3040;
42+
43+
Sentry.setupFastifyErrorHandler(app, {
44+
shouldHandleError: (error, _request, _reply) => {
45+
// @ts-ignore // Fastify V3 is not typed correctly
46+
if (_request.url?.includes('/test-error-not-captured')) {
47+
// Errors from this path will not be captured by Sentry
48+
return false;
49+
}
50+
51+
return true;
52+
},
53+
});
54+
55+
app.get('/test-success', function (_req, res) {
56+
res.send({ version: 'v1' });
57+
});
58+
59+
app.get<{ Params: { param: string } }>('/test-param/:param', function (req, res) {
60+
res.send({ paramWas: req.params.param });
61+
});
62+
63+
app.get<{ Params: { id: string } }>('/test-inbound-headers/:id', function (req, res) {
64+
const headers = req.headers;
65+
66+
res.send({ headers, id: req.params.id });
67+
});
68+
69+
app.get<{ Params: { id: string } }>('/test-outgoing-http/:id', async function (req, res) {
70+
const id = req.params.id;
71+
const data = await makeHttpRequest(`http://localhost:3030/test-inbound-headers/${id}`);
72+
73+
res.send(data);
74+
});
75+
76+
app.get<{ Params: { id: string } }>('/test-outgoing-fetch/:id', async function (req, res) {
77+
const id = req.params.id;
78+
const response = await fetch(`http://localhost:3030/test-inbound-headers/${id}`);
79+
const data = await response.json();
80+
81+
res.send(data);
82+
});
83+
84+
app.get('/test-transaction', async function (req, res) {
85+
Sentry.startSpan({ name: 'test-span' }, () => {
86+
Sentry.startSpan({ name: 'child-span' }, () => {});
87+
});
88+
89+
res.send({});
90+
});
91+
92+
app.get('/test-error', async function (req, res) {
93+
const exceptionId = Sentry.captureException(new Error('This is an error'));
94+
95+
await Sentry.flush(2000);
96+
97+
res.send({ exceptionId });
98+
});
99+
100+
app.get('/test-error-not-captured', async function () {
101+
// This error will not be captured by Sentry
102+
throw new Error('This is an error that will not be captured');
103+
});
104+
105+
app.get<{ Params: { id: string } }>('/test-exception/:id', async function (req, res) {
106+
throw new Error(`This is an exception with id ${req.params.id}`);
107+
});
108+
109+
app.get('/test-outgoing-fetch-external-allowed', async function (req, res) {
110+
const fetchResponse = await fetch(`http://localhost:${port2}/external-allowed`);
111+
const data = await fetchResponse.json();
112+
113+
res.send(data);
114+
});
115+
116+
app.get('/test-outgoing-fetch-external-disallowed', async function (req, res) {
117+
const fetchResponse = await fetch(`http://localhost:${port2}/external-disallowed`);
118+
const data = await fetchResponse.json();
119+
120+
res.send(data);
121+
});
122+
123+
app.get('/test-outgoing-http-external-allowed', async function (req, res) {
124+
const data = await makeHttpRequest(`http://localhost:${port2}/external-allowed`);
125+
res.send(data);
126+
});
127+
128+
app.get('/test-outgoing-http-external-disallowed', async function (req, res) {
129+
const data = await makeHttpRequest(`http://localhost:${port2}/external-disallowed`);
130+
res.send(data);
131+
});
132+
133+
app.post('/test-post', function (req, res) {
134+
res.send({ status: 'ok', body: req.body });
135+
});
136+
137+
app.listen({ port: port });
138+
139+
// A second app so we can test header propagation between external URLs
140+
const app2 = fastify();
141+
app2.get('/external-allowed', function (req, res) {
142+
const headers = req.headers;
143+
144+
res.send({ headers, route: '/external-allowed' });
145+
});
146+
147+
app2.get('/external-disallowed', function (req, res) {
148+
const headers = req.headers;
149+
150+
res.send({ headers, route: '/external-disallowed' });
151+
});
152+
153+
app2.listen({ port: port2 });
154+
155+
function makeHttpRequest(url: string) {
156+
return new Promise(resolve => {
157+
const data: any[] = [];
158+
159+
http
160+
.request(url, httpRes => {
161+
httpRes.on('data', chunk => {
162+
data.push(chunk);
163+
});
164+
httpRes.on('error', error => {
165+
resolve({ error: error.message, url });
166+
});
167+
httpRes.on('end', () => {
168+
try {
169+
const json = JSON.parse(Buffer.concat(data).toString());
170+
resolve(json);
171+
} catch {
172+
resolve({ data: Buffer.concat(data).toString(), url });
173+
}
174+
});
175+
})
176+
.end();
177+
});
178+
}

dev-packages/e2e-tests/test-applications/node-fastify-3/src/app.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,19 @@ console.warn = new Proxy(console.warn, {
1717
Sentry.init({
1818
environment: 'qa', // dynamic sampling bias to keep transactions
1919
dsn: process.env.E2E_TEST_DSN,
20-
integrations: [],
20+
integrations: [
21+
Sentry.fastifyIntegration({
22+
shouldHandleError: (error, _request, _reply) => {
23+
// @ts-ignore // Fastify V3 is not typed correctly
24+
if (_request.url?.includes('/test-error-not-captured')) {
25+
// Errors from this path will not be captured by Sentry
26+
return false;
27+
}
28+
29+
return true;
30+
},
31+
}),
32+
],
2133
tracesSampleRate: 1,
2234
tunnel: 'http://localhost:3031/', // proxy server
2335
tracePropagationTargets: ['http://localhost:3030', '/external-allowed'],
@@ -81,6 +93,11 @@ app.get('/test-error', async function (req, res) {
8193
res.send({ exceptionId });
8294
});
8395

96+
app.get('/test-error-not-captured', async function () {
97+
// This error will not be captured by Sentry
98+
throw new Error('This is an error that will not be captured');
99+
});
100+
84101
app.get<{ Params: { id: string } }>('/test-exception/:id', async function (req, res) {
85102
throw new Error(`This is an exception with id ${req.params.id}`);
86103
});

dev-packages/e2e-tests/test-applications/node-fastify-3/tests/errors.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,18 @@ test('Sends correct error event', async ({ baseURL }) => {
2828
parent_span_id: expect.stringMatching(/[a-f0-9]{16}/),
2929
});
3030
});
31+
32+
test('Does not send error when shouldHandleError returns false', async ({ baseURL }) => {
33+
const errorEventPromise = waitForError('node-fastify-3', event => {
34+
return !event.type && event.exception?.values?.[0]?.value === 'This is an error that will not be captured';
35+
});
36+
37+
errorEventPromise.then(() => {
38+
throw new Error('This error should not be captured');
39+
});
40+
41+
await fetch(`${baseURL}/test-error-not-captured`);
42+
43+
// wait for a short time to ensure the error is not captured
44+
await new Promise(resolve => setTimeout(resolve, 1000));
45+
});

dev-packages/e2e-tests/test-applications/node-fastify-4/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
"private": true,
55
"scripts": {
66
"start": "ts-node src/app.ts",
7+
"start:override": "ts-node src/app-handle-error-override.ts",
78
"test": "playwright test",
9+
"test:override": "playwright test --config playwright.override.config.mjs",
810
"clean": "npx rimraf node_modules pnpm-lock.yaml",
911
"typecheck": "tsc",
1012
"test:build": "pnpm install && pnpm run typecheck",
11-
"test:assert": "pnpm test"
13+
"test:assert": "pnpm test && pnpm test:override"
1214
},
1315
"dependencies": {
1416
"@sentry/node": "latest || *",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { getPlaywrightConfig } from '@sentry-internal/test-utils';
2+
3+
const config = getPlaywrightConfig({
4+
startCommand: `pnpm start:override`,
5+
});
6+
7+
export default config;

0 commit comments

Comments
 (0)