Skip to content

Commit 23c19bf

Browse files
authored
feat(node): Move tracing options to Http integration (#6191)
Since both `tracing` and `shouldCreateSpanForRequest` effectively control whether tracing is enabled and have opposing defaults (`tracing: false` and `shouldCreateSpanForRequest: _ => true`), this patch makes `tracing: TracingOptions | boolean` so its not a breaking change and the options don't end up conflicting. ```ts interface TracingOptions { tracePropagationTargets?: TracePropagationTargets; shouldCreateSpanForRequest?: (url: string) => boolean; } interface HttpOptions { breadcrumbs?: boolean; tracing?: TracingOptions | boolean; } ```
1 parent b4e89de commit 23c19bf

File tree

5 files changed

+248
-102
lines changed

5 files changed

+248
-102
lines changed

packages/nextjs/src/index.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ function addServerIntegrations(options: NextjsOptions): void {
129129
if (hasTracingEnabled(options)) {
130130
const defaultHttpTracingIntegration = new Integrations.Http({ tracing: true });
131131
integrations = addOrUpdateIntegration(defaultHttpTracingIntegration, integrations, {
132-
_tracing: true,
132+
_tracing: {},
133133
});
134134
}
135135

packages/nextjs/test/index.server.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ describe('Server init()', () => {
169169
const httpIntegration = findIntegrationByName(nodeInitOptions.integrations, 'Http');
170170

171171
expect(httpIntegration).toBeDefined();
172-
expect(httpIntegration).toEqual(expect.objectContaining({ _tracing: true }));
172+
expect(httpIntegration).toEqual(expect.objectContaining({ _tracing: {} }));
173173
});
174174

175175
it('adds `Http` integration with tracing enabled if `tracesSampler` is set', () => {
@@ -179,7 +179,7 @@ describe('Server init()', () => {
179179
const httpIntegration = findIntegrationByName(nodeInitOptions.integrations, 'Http');
180180

181181
expect(httpIntegration).toBeDefined();
182-
expect(httpIntegration).toEqual(expect.objectContaining({ _tracing: true }));
182+
expect(httpIntegration).toEqual(expect.objectContaining({ _tracing: {} }));
183183
});
184184

185185
it('does not add `Http` integration if tracing not enabled in SDK', () => {
@@ -201,7 +201,7 @@ describe('Server init()', () => {
201201
const httpIntegration = findIntegrationByName(nodeInitOptions.integrations, 'Http');
202202

203203
expect(httpIntegration).toBeDefined();
204-
expect(httpIntegration).toEqual(expect.objectContaining({ _tracing: true }));
204+
expect(httpIntegration).toEqual(expect.objectContaining({ _tracing: {} }));
205205
});
206206

207207
it('forces `_tracing = true` if `tracesSampler` is set', () => {
@@ -214,7 +214,7 @@ describe('Server init()', () => {
214214
const httpIntegration = findIntegrationByName(nodeInitOptions.integrations, 'Http');
215215

216216
expect(httpIntegration).toBeDefined();
217-
expect(httpIntegration).toEqual(expect.objectContaining({ _tracing: true }));
217+
expect(httpIntegration).toEqual(expect.objectContaining({ _tracing: {} }));
218218
});
219219

220220
it('does not force `_tracing = true` if tracing not enabled in SDK', () => {
@@ -226,7 +226,7 @@ describe('Server init()', () => {
226226
const httpIntegration = findIntegrationByName(nodeInitOptions.integrations, 'Http');
227227

228228
expect(httpIntegration).toBeDefined();
229-
expect(httpIntegration).toEqual(expect.objectContaining({ _tracing: false }));
229+
expect(httpIntegration).toEqual(expect.objectContaining({ _tracing: undefined }));
230230
});
231231
});
232232
});

packages/node/src/integrations/http.ts

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getCurrentHub, Hub } from '@sentry/core';
2-
import { EventProcessor, Integration, Span } from '@sentry/types';
2+
import { EventProcessor, Integration, Span, TracePropagationTargets } from '@sentry/types';
33
import {
44
dynamicSamplingContextToSentryBaggageHeader,
55
fill,
@@ -11,7 +11,6 @@ import * as http from 'http';
1111
import * as https from 'https';
1212

1313
import { NodeClient } from '../client';
14-
import { NodeClientOptions } from '../types';
1514
import {
1615
cleanSpanDescription,
1716
extractUrl,
@@ -23,6 +22,39 @@ import {
2322

2423
const NODE_VERSION = parseSemver(process.versions.node);
2524

25+
interface TracingOptions {
26+
/**
27+
* List of strings/regex controlling to which outgoing requests
28+
* the SDK will attach tracing headers.
29+
*
30+
* By default the SDK will attach those headers to all outgoing
31+
* requests. If this option is provided, the SDK will match the
32+
* request URL of outgoing requests against the items in this
33+
* array, and only attach tracing headers if a match was found.
34+
*/
35+
tracePropagationTargets?: TracePropagationTargets;
36+
37+
/**
38+
* Function determining whether or not to create spans to track outgoing requests to the given URL.
39+
* By default, spans will be created for all outgoing requests.
40+
*/
41+
shouldCreateSpanForRequest?: (url: string) => boolean;
42+
}
43+
44+
interface HttpOptions {
45+
/**
46+
* Whether breadcrumbs should be recorded for requests
47+
* Defaults to true
48+
*/
49+
breadcrumbs?: boolean;
50+
51+
/**
52+
* Whether tracing spans should be created for requests
53+
* Defaults to false
54+
*/
55+
tracing?: TracingOptions | boolean;
56+
}
57+
2658
/**
2759
* The http module integration instruments Node's internal http module. It creates breadcrumbs, transactions for outgoing
2860
* http requests and attaches trace data when tracing is enabled via its `tracing` option.
@@ -38,22 +70,15 @@ export class Http implements Integration {
3870
*/
3971
public name: string = Http.id;
4072

41-
/**
42-
* @inheritDoc
43-
*/
4473
private readonly _breadcrumbs: boolean;
74+
private readonly _tracing: TracingOptions | undefined;
4575

4676
/**
4777
* @inheritDoc
4878
*/
49-
private readonly _tracing: boolean;
50-
51-
/**
52-
* @inheritDoc
53-
*/
54-
public constructor(options: { breadcrumbs?: boolean; tracing?: boolean } = {}) {
79+
public constructor(options: HttpOptions = {}) {
5580
this._breadcrumbs = typeof options.breadcrumbs === 'undefined' ? true : options.breadcrumbs;
56-
this._tracing = typeof options.tracing === 'undefined' ? false : options.tracing;
81+
this._tracing = !options.tracing ? undefined : options.tracing === true ? {} : options.tracing;
5782
}
5883

5984
/**
@@ -76,7 +101,11 @@ export class Http implements Integration {
76101
return;
77102
}
78103

79-
const wrappedHandlerMaker = _createWrappedRequestMethodFactory(this._breadcrumbs, this._tracing, clientOptions);
104+
// TODO (v8): `tracePropagationTargets` and `shouldCreateSpanForRequest` will be removed from clientOptions
105+
// and we will no longer have to do this optional merge, we can just pass `this._tracing` directly.
106+
const tracingOptions = this._tracing ? { ...clientOptions, ...this._tracing } : undefined;
107+
108+
const wrappedHandlerMaker = _createWrappedRequestMethodFactory(this._breadcrumbs, tracingOptions);
80109

81110
// eslint-disable-next-line @typescript-eslint/no-var-requires
82111
const httpModule = require('http');
@@ -111,37 +140,36 @@ type WrappedRequestMethodFactory = (original: OriginalRequestMethod) => WrappedR
111140
*/
112141
function _createWrappedRequestMethodFactory(
113142
breadcrumbsEnabled: boolean,
114-
tracingEnabled: boolean,
115-
options: NodeClientOptions | undefined,
143+
tracingOptions: TracingOptions | undefined,
116144
): WrappedRequestMethodFactory {
117145
// We're caching results so we don't have to recompute regexp every time we create a request.
118146
const createSpanUrlMap: Record<string, boolean> = {};
119147
const headersUrlMap: Record<string, boolean> = {};
120148

121149
const shouldCreateSpan = (url: string): boolean => {
122-
if (options?.shouldCreateSpanForRequest === undefined) {
150+
if (tracingOptions?.shouldCreateSpanForRequest === undefined) {
123151
return true;
124152
}
125153

126154
if (createSpanUrlMap[url]) {
127155
return createSpanUrlMap[url];
128156
}
129157

130-
createSpanUrlMap[url] = options.shouldCreateSpanForRequest(url);
158+
createSpanUrlMap[url] = tracingOptions.shouldCreateSpanForRequest(url);
131159

132160
return createSpanUrlMap[url];
133161
};
134162

135163
const shouldAttachTraceData = (url: string): boolean => {
136-
if (options?.tracePropagationTargets === undefined) {
164+
if (tracingOptions?.tracePropagationTargets === undefined) {
137165
return true;
138166
}
139167

140168
if (headersUrlMap[url]) {
141169
return headersUrlMap[url];
142170
}
143171

144-
headersUrlMap[url] = options.tracePropagationTargets.some(tracePropagationTarget =>
172+
headersUrlMap[url] = tracingOptions.tracePropagationTargets.some(tracePropagationTarget =>
145173
isMatchingPattern(url, tracePropagationTarget),
146174
);
147175

@@ -167,7 +195,7 @@ function _createWrappedRequestMethodFactory(
167195

168196
const scope = getCurrentHub().getScope();
169197

170-
if (scope && tracingEnabled && shouldCreateSpan(requestUrl)) {
198+
if (scope && tracingOptions && shouldCreateSpan(requestUrl)) {
171199
parentSpan = scope.getSpan();
172200

173201
if (parentSpan) {
@@ -235,7 +263,7 @@ function _createWrappedRequestMethodFactory(
235263
if (breadcrumbsEnabled) {
236264
addRequestBreadcrumb('response', requestUrl, req, res);
237265
}
238-
if (tracingEnabled && requestSpan) {
266+
if (requestSpan) {
239267
if (res.statusCode) {
240268
requestSpan.setHttpStatus(res.statusCode);
241269
}
@@ -250,7 +278,7 @@ function _createWrappedRequestMethodFactory(
250278
if (breadcrumbsEnabled) {
251279
addRequestBreadcrumb('error', requestUrl, req);
252280
}
253-
if (tracingEnabled && requestSpan) {
281+
if (requestSpan) {
254282
requestSpan.setHttpStatus(500);
255283
requestSpan.description = cleanSpanDescription(requestSpan.description, requestOptions, req);
256284
requestSpan.finish();

packages/node/src/types.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,39 @@ export interface BaseNodeOptions {
66
/** Sets an optional server name (device name) */
77
serverName?: string;
88

9-
// We have this option separately in both, the node options and the browser options, so that we can have different JSDoc
10-
// comments, since this has different behaviour in the Browser and Node SDKs.
9+
// TODO (v8): Remove this in v8
1110
/**
12-
* List of strings/regex controlling to which outgoing requests
13-
* the SDK will attach tracing headers.
14-
*
15-
* By default the SDK will attach those headers to all outgoing
16-
* requests. If this option is provided, the SDK will match the
17-
* request URL of outgoing requests against the items in this
18-
* array, and only attach tracing headers if a match was found.
11+
* @deprecated Moved to constructor options of the `Http` integration.
12+
* @example
13+
* ```js
14+
* Sentry.init({
15+
* integrations: [
16+
* new Sentry.Integrations.Http({
17+
* tracing: {
18+
* tracePropagationTargets: ['api.site.com'],
19+
* }
20+
* });
21+
* ],
22+
* });
23+
* ```
1924
*/
2025
tracePropagationTargets?: TracePropagationTargets;
2126

27+
// TODO (v8): Remove this in v8
2228
/**
23-
* Function determining whether or not to create spans to track outgoing requests to the given URL.
24-
* By default, spans will be created for all outgoing requests.
29+
* @deprecated Moved to constructor options of the `Http` integration.
30+
* @example
31+
* ```js
32+
* Sentry.init({
33+
* integrations: [
34+
* new Sentry.Integrations.Http({
35+
* tracing: {
36+
* shouldCreateSpanForRequest: (url: string) => false,
37+
* }
38+
* });
39+
* ],
40+
* });
41+
* ```
2542
*/
2643
shouldCreateSpanForRequest?(url: string): boolean;
2744

0 commit comments

Comments
 (0)