Skip to content

Commit 1b04113

Browse files
authored
ref(node): Clean up Undici options (#7646)
1 parent 3a91a62 commit 1b04113

File tree

3 files changed

+78
-32
lines changed

3 files changed

+78
-32
lines changed

packages/node/src/integrations/undici/index.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@ export interface UndiciOptions {
2727
* Defaults to true
2828
*/
2929
breadcrumbs: boolean;
30+
/**
31+
* Function determining whether or not to create spans to track outgoing requests to the given URL.
32+
* By default, spans will be created for all outgoing requests.
33+
*/
34+
shouldCreateSpanForRequest: (url: string) => boolean;
3035
}
3136

32-
const DEFAULT_UNDICI_OPTIONS: UndiciOptions = {
33-
breadcrumbs: true,
34-
};
35-
3637
// Please note that you cannot use `console.log` to debug the callbacks registered to the `diagnostics_channel` API.
3738
// To debug, you can use `writeFileSync` to write to a file:
3839
// https://nodejs.org/api/async_hooks.html#printing-in-asynchook-callbacks
@@ -60,8 +61,8 @@ export class Undici implements Integration {
6061

6162
public constructor(_options: Partial<UndiciOptions> = {}) {
6263
this._options = {
63-
...DEFAULT_UNDICI_OPTIONS,
64-
..._options,
64+
breadcrumbs: _options.breadcrumbs === undefined ? true : _options.breadcrumbs,
65+
shouldCreateSpanForRequest: _options.shouldCreateSpanForRequest || (() => true),
6566
};
6667
}
6768

@@ -88,6 +89,11 @@ export class Undici implements Integration {
8889

8990
// https://github.com/nodejs/undici/blob/e6fc80f809d1217814c044f52ed40ef13f21e43c/docs/api/DiagnosticsChannel.md
9091
ds.subscribe(ChannelName.RequestCreate, message => {
92+
const hub = getCurrentHub();
93+
if (!hub.getIntegration(Undici)) {
94+
return;
95+
}
96+
9197
const { request } = message as RequestCreateMessage;
9298

9399
const url = new URL(request.path, request.origin);
@@ -97,20 +103,14 @@ export class Undici implements Integration {
97103
return;
98104
}
99105

100-
const hub = getCurrentHub();
101106
const client = hub.getClient<NodeClient>();
102107
const scope = hub.getScope();
103108

104109
const activeSpan = scope.getSpan();
105110

106111
if (activeSpan && client) {
107112
const clientOptions = client.getOptions();
108-
109-
// eslint-disable-next-line deprecation/deprecation
110-
const shouldCreateSpan = clientOptions.shouldCreateSpanForRequest
111-
? // eslint-disable-next-line deprecation/deprecation
112-
clientOptions.shouldCreateSpanForRequest(stringUrl)
113-
: true;
113+
const shouldCreateSpan = this._options.shouldCreateSpanForRequest(stringUrl);
114114

115115
if (shouldCreateSpan) {
116116
const data: Record<string, unknown> = {};
@@ -129,10 +129,8 @@ export class Undici implements Integration {
129129
});
130130
request.__sentry__ = span;
131131

132-
// eslint-disable-next-line deprecation/deprecation
133132
const shouldPropagate = clientOptions.tracePropagationTargets
134-
? // eslint-disable-next-line deprecation/deprecation
135-
stringMatchesSomePattern(stringUrl, clientOptions.tracePropagationTargets)
133+
? stringMatchesSomePattern(stringUrl, clientOptions.tracePropagationTargets)
136134
: true;
137135

138136
if (shouldPropagate) {
@@ -150,6 +148,11 @@ export class Undici implements Integration {
150148
});
151149

152150
ds.subscribe(ChannelName.RequestEnd, message => {
151+
const hub = getCurrentHub();
152+
if (!hub.getIntegration(Undici)) {
153+
return;
154+
}
155+
153156
const { request, response } = message as RequestEndMessage;
154157

155158
const url = new URL(request.path, request.origin);
@@ -166,7 +169,7 @@ export class Undici implements Integration {
166169
}
167170

168171
if (this._options.breadcrumbs) {
169-
getCurrentHub().addBreadcrumb(
172+
hub.addBreadcrumb(
170173
{
171174
category: 'http',
172175
data: {
@@ -186,6 +189,11 @@ export class Undici implements Integration {
186189
});
187190

188191
ds.subscribe(ChannelName.RequestError, message => {
192+
const hub = getCurrentHub();
193+
if (!hub.getIntegration(Undici)) {
194+
return;
195+
}
196+
189197
const { request } = message as RequestErrorMessage;
190198

191199
const url = new URL(request.path, request.origin);
@@ -202,7 +210,7 @@ export class Undici implements Integration {
202210
}
203211

204212
if (this._options.breadcrumbs) {
205-
getCurrentHub().addBreadcrumb(
213+
hub.addBreadcrumb(
206214
{
207215
category: 'http',
208216
data: {

packages/node/src/types.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,27 @@ export interface BaseNodeOptions {
3232
*/
3333
includeLocalVariables?: boolean;
3434

35-
// TODO (v8): Remove this in v8
3635
/**
37-
* @deprecated Moved to constructor options of the `Http` integration.
36+
* List of strings/regex controlling to which outgoing requests
37+
* the SDK will attach tracing headers.
38+
*
39+
* By default the SDK will attach those headers to all outgoing
40+
* requests. If this option is provided, the SDK will match the
41+
* request URL of outgoing requests against the items in this
42+
* array, and only attach tracing headers if a match was found.
43+
*
3844
* @example
3945
* ```js
4046
* Sentry.init({
41-
* integrations: [
42-
* new Sentry.Integrations.Http({
43-
* tracing: {
44-
* tracePropagationTargets: ['api.site.com'],
45-
* }
46-
* });
47-
* ],
47+
* tracePropagationTargets: ['api.site.com'],
4848
* });
4949
* ```
5050
*/
5151
tracePropagationTargets?: TracePropagationTargets;
5252

5353
// TODO (v8): Remove this in v8
5454
/**
55-
* @deprecated Moved to constructor options of the `Http` integration.
55+
* @deprecated Moved to constructor options of the `Http` and `Undici` integration.
5656
* @example
5757
* ```js
5858
* Sentry.init({

packages/node/test/integrations/undici.test.ts

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as http from 'http';
44
import type { fetch as FetchType } from 'undici';
55

66
import { NodeClient } from '../../src/client';
7+
import type { UndiciOptions } from '../../src/integrations/undici';
78
import { Undici } from '../../src/integrations/undici';
89
import { getDefaultNodeClientOptions } from '../helper/node-client-options';
910
import { conditionalTest } from '../utils';
@@ -150,8 +151,7 @@ conditionalTest({ min: 16 })('Undici integration', () => {
150151
const transaction = hub.startTransaction({ name: 'test-transaction' }) as Transaction;
151152
hub.getScope().setSpan(transaction);
152153

153-
const client = new NodeClient({ ...DEFAULT_OPTIONS, shouldCreateSpanForRequest: url => url.includes('yes') });
154-
hub.bindClient(client);
154+
const undoPatch = patchUndici(hub, { shouldCreateSpanForRequest: url => url.includes('yes') });
155155

156156
await fetch('http://localhost:18099/no', { method: 'POST' });
157157

@@ -160,6 +160,8 @@ conditionalTest({ min: 16 })('Undici integration', () => {
160160
await fetch('http://localhost:18099/yes', { method: 'POST' });
161161

162162
expect(transaction.spanRecorder?.spans.length).toBe(2);
163+
164+
undoPatch();
163165
});
164166

165167
it('attaches the sentry trace and baggage headers', async () => {
@@ -181,8 +183,7 @@ conditionalTest({ min: 16 })('Undici integration', () => {
181183
const transaction = hub.startTransaction({ name: 'test-transaction' }) as Transaction;
182184
hub.getScope().setSpan(transaction);
183185

184-
const client = new NodeClient({ ...DEFAULT_OPTIONS, shouldCreateSpanForRequest: url => url.includes('yes') });
185-
hub.bindClient(client);
186+
const undoPatch = patchUndici(hub, { shouldCreateSpanForRequest: url => url.includes('yes') });
186187

187188
await fetch('http://localhost:18099/no', { method: 'POST' });
188189

@@ -193,6 +194,8 @@ conditionalTest({ min: 16 })('Undici integration', () => {
193194

194195
expect(requestHeaders['sentry-trace']).toBeDefined();
195196
expect(requestHeaders['baggage']).toBeDefined();
197+
198+
undoPatch();
196199
});
197200

198201
it('uses tracePropagationTargets', async () => {
@@ -270,6 +273,16 @@ conditionalTest({ min: 16 })('Undici integration', () => {
270273
// ignore
271274
}
272275
});
276+
277+
it('does not add a breadcrumb if disabled', async () => {
278+
expect.assertions(0);
279+
280+
const undoPatch = patchUndici(hub, { breadcrumbs: false });
281+
282+
await fetch('http://localhost:18099', { method: 'POST' });
283+
284+
undoPatch();
285+
});
273286
});
274287

275288
interface TestServerOptions {
@@ -318,3 +331,28 @@ function setupTestServer() {
318331
testServer?.on('listening', resolve);
319332
});
320333
}
334+
335+
function patchUndici(hub: Hub, userOptions: Partial<UndiciOptions>): () => void {
336+
let options: any = {};
337+
const client = hub.getClient();
338+
if (client) {
339+
const undici = client.getIntegration(Undici);
340+
if (undici) {
341+
// @ts-ignore need to access private property
342+
options = { ...undici._options };
343+
// @ts-ignore need to access private property
344+
undici._options = Object.assign(undici._options, userOptions);
345+
}
346+
}
347+
348+
return () => {
349+
const client = hub.getClient();
350+
if (client) {
351+
const undici = client.getIntegration(Undici);
352+
if (undici) {
353+
// @ts-ignore need to access private property
354+
undici._options = { ...options };
355+
}
356+
}
357+
};
358+
}

0 commit comments

Comments
 (0)