Skip to content

Commit da07ea7

Browse files
authored
fix(nextjs): Use domains to prevent scope bleed on backend (#3574)
1 parent 5d4dcab commit da07ea7

File tree

1 file changed

+35
-26
lines changed

1 file changed

+35
-26
lines changed

packages/nextjs/src/utils/instrumentServer.ts

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { deepReadDirSync } from '@sentry/node';
22
import { hasTracingEnabled } from '@sentry/tracing';
33
import { Transaction } from '@sentry/types';
44
import { fill, logger } from '@sentry/utils';
5+
import * as domain from 'domain';
56
import * as http from 'http';
67
import { default as createNextServer } from 'next';
78
import * as url from 'url';
@@ -173,35 +174,43 @@ function makeWrappedReqHandler(origReqHandler: ReqHandler): WrappedReqHandler {
173174
res: NextResponse,
174175
parsedUrl?: url.UrlWithParsedQuery,
175176
): Promise<void> {
176-
// We only want to record page and API requests
177-
if (hasTracingEnabled() && shouldTraceRequest(req.url, publicDirFiles)) {
178-
const transaction = Sentry.startTransaction({
179-
name: `${(req.method || 'GET').toUpperCase()} ${req.url}`,
180-
op: 'http.server',
181-
});
182-
Sentry.getCurrentHub()
183-
.getScope()
184-
?.setSpan(transaction);
185-
186-
res.__sentry__ = {};
187-
res.__sentry__.transaction = transaction;
188-
}
189-
190-
res.once('finish', () => {
191-
const transaction = res.__sentry__?.transaction;
192-
if (transaction) {
193-
// Push `transaction.finish` to the next event loop so open spans have a chance to finish before the transaction
194-
// closes
195-
setImmediate(() => {
196-
// TODO
197-
// addExpressReqToTransaction(transaction, req);
198-
transaction.setHttpStatus(res.statusCode);
199-
transaction.finish();
177+
// wrap everything in a domain in order to prevent scope bleed between requests
178+
const local = domain.create();
179+
local.add(req);
180+
local.add(res);
181+
// TODO could this replace wrapping the error logger?
182+
// local.on('error', Sentry.captureException);
183+
184+
local.run(() => {
185+
// We only want to record page and API requests
186+
if (hasTracingEnabled() && shouldTraceRequest(req.url, publicDirFiles)) {
187+
const transaction = Sentry.startTransaction({
188+
name: `${(req.method || 'GET').toUpperCase()} ${req.url}`,
189+
op: 'http.server',
190+
});
191+
Sentry.getCurrentHub()
192+
.getScope()
193+
?.setSpan(transaction);
194+
195+
res.__sentry__ = { transaction };
196+
197+
res.once('finish', () => {
198+
const transaction = res.__sentry__?.transaction;
199+
if (transaction) {
200+
// Push `transaction.finish` to the next event loop so open spans have a chance to finish before the transaction
201+
// closes
202+
setImmediate(() => {
203+
// TODO
204+
// addExpressReqToTransaction(transaction, req);
205+
transaction.setHttpStatus(res.statusCode);
206+
transaction.finish();
207+
});
208+
}
200209
});
210+
211+
return origReqHandler.call(this, req, res, parsedUrl);
201212
}
202213
});
203-
204-
return origReqHandler.call(this, req, res, parsedUrl);
205214
};
206215

207216
return wrappedReqHandler;

0 commit comments

Comments
 (0)