Skip to content

Commit

Permalink
fix(node): Add conditions to TracingHanlder.startTransaction (#5485)
Browse files Browse the repository at this point in the history
Currently, our TracingHandler always starts a transaction, whether or not tracing is enabled. It also traces OPTIONS and HEAD requests, which it shouldn't. This fixes both of those problems by checking both the current client's options (for tracing enablement) and the incoming request's method before starting a transaction.
  • Loading branch information
lobsterkatie committed Jul 28, 2022
1 parent 1182e71 commit 538f41c
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 2 deletions.
20 changes: 19 additions & 1 deletion packages/node/src/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,24 @@ export function tracingHandler(): (
res: http.ServerResponse,
next: (error?: any) => void,
): void {
const hub = getCurrentHub();
const options = hub.getClient()?.getOptions();

if (!options || req.method?.toUpperCase() === 'OPTIONS' || req.method?.toUpperCase() === 'HEAD') {
return next();
}

// TODO: This is the `hasTracingEnabled` check, but we're doing it manually since `@sentry/tracing` isn't a
// dependency of `@sentry/node`. Long term, that function should probably move to `@sentry/hub.
if (!('tracesSampleRate' in options) && !('tracesSampler' in options)) {
__DEBUG_BUILD__ &&
logger.warn(
'Sentry `tracingHandler` is being used, but tracing is disabled. Please enable tracing by setting ' +
'either `tracesSampleRate` or `tracesSampler` in your `Sentry.init()` options.',
);
return next();
}

// If there is a trace header set, we extract the data from it (parentSpanId, traceId, and sampling decision)
const traceparentData =
req.headers && isString(req.headers['sentry-trace']) && extractTraceparentData(req.headers['sentry-trace']);
Expand All @@ -53,7 +71,7 @@ export function tracingHandler(): (
);

// We put the transaction on the scope so users can attach children to it
getCurrentHub().configureScope(scope => {
hub.configureScope(scope => {
scope.setSpan(transaction);
});

Expand Down
31 changes: 30 additions & 1 deletion packages/node/test/handlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,16 @@ describe('tracingHandler', () => {

const sentryTracingMiddleware = tracingHandler();

let req: http.IncomingMessage, res: http.ServerResponse, next: () => undefined;
let hub: Hub, req: http.IncomingMessage, res: http.ServerResponse, next: () => undefined;

function createNoOpSpy() {
const noop = { noop: () => undefined }; // this is wrapped in an object so jest can spy on it
return jest.spyOn(noop, 'noop') as any;
}

beforeEach(() => {
hub = new Hub(new NodeClient(getDefaultNodeClientOptions({ tracesSampleRate: 1.0 })));
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub);
req = {
headers,
method,
Expand All @@ -181,6 +183,33 @@ describe('tracingHandler', () => {
expect(startTransaction).toHaveBeenCalled();
});

it("doesn't create a transaction when handling a `HEAD` request", () => {
const startTransaction = jest.spyOn(sentryCore, 'startTransaction');
req.method = 'HEAD';

sentryTracingMiddleware(req, res, next);

expect(startTransaction).not.toHaveBeenCalled();
});

it("doesn't create a transaction when handling an `OPTIONS` request", () => {
const startTransaction = jest.spyOn(sentryCore, 'startTransaction');
req.method = 'OPTIONS';

sentryTracingMiddleware(req, res, next);

expect(startTransaction).not.toHaveBeenCalled();
});

it("doesn't create a transaction if tracing is disabled", () => {
delete hub.getClient()?.getOptions().tracesSampleRate;
const startTransaction = jest.spyOn(sentryCore, 'startTransaction');

sentryTracingMiddleware(req, res, next);

expect(startTransaction).not.toHaveBeenCalled();
});

it("pulls parent's data from tracing header on the request", () => {
req.headers = { 'sentry-trace': '12312012123120121231201212312012-1121201211212012-0' };

Expand Down

0 comments on commit 538f41c

Please sign in to comment.