Skip to content

Commit 3491bfe

Browse files
committed
use domains
1 parent 484aad5 commit 3491bfe

File tree

1 file changed

+62
-54
lines changed

1 file changed

+62
-54
lines changed

packages/nextjs/src/utils/handlers.ts

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { captureException, flush, getCurrentHub, Handlers, startTransaction, withScope } from '@sentry/node';
22
import { extractTraceparentData, getActiveTransaction, hasTracingEnabled } from '@sentry/tracing';
33
import { addExceptionMechanism, isString, logger, stripUrlQueryAndFragment } from '@sentry/utils';
4+
import * as domain from 'domain';
45
import { NextApiHandler } from 'next';
56

67
import { addRequestDataToEvent, NextRequest } from './instrumentServer';
@@ -14,70 +15,77 @@ type WrappedNextApiHandler = NextApiHandler;
1415
export const withSentry = (handler: NextApiHandler): WrappedNextApiHandler => {
1516
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
1617
return async (req, res) => {
17-
try {
18-
const currentScope = getCurrentHub().getScope();
18+
// wrap everything in a domain in order to prevent scope bleed between requests
19+
const local = domain.create();
20+
local.add(req);
21+
local.add(res);
1922

20-
if (currentScope) {
21-
currentScope.addEventProcessor(event => addRequestDataToEvent(event, req as NextRequest));
23+
local.run(async () => {
24+
try {
25+
const currentScope = getCurrentHub().getScope();
2226

23-
if (hasTracingEnabled()) {
24-
// If there is a trace header set, extract the data from it (parentSpanId, traceId, and sampling decision)
25-
let traceparentData;
26-
if (req.headers && isString(req.headers['sentry-trace'])) {
27-
traceparentData = extractTraceparentData(req.headers['sentry-trace'] as string);
28-
logger.log(`[Tracing] Continuing trace ${traceparentData?.traceId}.`);
29-
}
27+
if (currentScope) {
28+
currentScope.addEventProcessor(event => addRequestDataToEvent(event, req as NextRequest));
3029

31-
const url = `${req.url}`;
32-
// pull off query string, if any
33-
let reqPath = stripUrlQueryAndFragment(url);
34-
// Replace with placeholder
35-
if (req.query) {
36-
// TODO get this from next if possible, to avoid accidentally replacing non-dynamic parts of the path if
37-
// they match dynamic parts
38-
for (const [key, value] of Object.entries(req.query)) {
39-
reqPath = reqPath.replace(`${value}`, `[${key}]`);
30+
if (hasTracingEnabled()) {
31+
// If there is a trace header set, extract the data from it (parentSpanId, traceId, and sampling decision)
32+
let traceparentData;
33+
if (req.headers && isString(req.headers['sentry-trace'])) {
34+
traceparentData = extractTraceparentData(req.headers['sentry-trace'] as string);
35+
logger.log(`[Tracing] Continuing trace ${traceparentData?.traceId}.`);
4036
}
41-
}
42-
const reqMethod = `${(req.method || 'GET').toUpperCase()} `;
4337

44-
const transaction = startTransaction(
45-
{
46-
name: `${reqMethod}${reqPath}`,
47-
op: 'http.server',
48-
...traceparentData,
49-
},
50-
// extra context passed to the `tracesSampler`
51-
{ request: req },
52-
);
53-
currentScope.setSpan(transaction);
38+
const url = `${req.url}`;
39+
// pull off query string, if any
40+
let reqPath = stripUrlQueryAndFragment(url);
41+
// Replace with placeholder
42+
if (req.query) {
43+
// TODO get this from next if possible, to avoid accidentally replacing non-dynamic parts of the path if
44+
// they match dynamic parts
45+
for (const [key, value] of Object.entries(req.query)) {
46+
reqPath = reqPath.replace(`${value}`, `[${key}]`);
47+
}
48+
}
49+
const reqMethod = `${(req.method || 'GET').toUpperCase()} `;
50+
51+
const transaction = startTransaction(
52+
{
53+
name: `${reqMethod}${reqPath}`,
54+
op: 'http.server',
55+
...traceparentData,
56+
},
57+
// extra context passed to the `tracesSampler`
58+
{ request: req },
59+
);
60+
currentScope.setSpan(transaction);
61+
}
5462
}
55-
}
5663

57-
return await handler(req, res); // Call original handler
58-
} catch (e) {
59-
withScope(scope => {
60-
scope.addEventProcessor(event => {
61-
addExceptionMechanism(event, {
62-
handled: false,
64+
return await handler(req, res); // Call original handler
65+
} catch (e) {
66+
withScope(scope => {
67+
scope.addEventProcessor(event => {
68+
addExceptionMechanism(event, {
69+
handled: false,
70+
});
71+
return parseRequest(event, req);
6372
});
64-
return parseRequest(event, req);
73+
captureException(e);
6574
});
66-
captureException(e);
67-
});
68-
throw e;
69-
} finally {
70-
const transaction = getActiveTransaction();
71-
if (transaction) {
72-
transaction.setHttpStatus(res.statusCode);
75+
throw e;
76+
} finally {
77+
const transaction = getActiveTransaction();
78+
if (transaction) {
79+
transaction.setHttpStatus(res.statusCode);
7380

74-
transaction.finish();
75-
}
76-
try {
77-
await flush(2000);
78-
} catch (e) {
79-
// no-empty
81+
transaction.finish();
82+
}
83+
try {
84+
await flush(2000);
85+
} catch (e) {
86+
// no-empty
87+
}
8088
}
81-
}
89+
});
8290
};
8391
};

0 commit comments

Comments
 (0)