Skip to content

Commit af90bfa

Browse files
authored
ref(node): Use new performance APIs in legacy http & undici (#11055)
Extraced this out from #11051, as it's actually not fully related.
1 parent 2ee0c18 commit af90bfa

File tree

4 files changed

+44
-41
lines changed

4 files changed

+44
-41
lines changed

packages/core/src/tracing/dynamicSamplingContext.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,29 +49,29 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
4949
const dsc = getDynamicSamplingContextFromClient(spanToJSON(span).trace_id || '', client);
5050

5151
// TODO (v8): Remove v7FrozenDsc as a Transaction will no longer have _frozenDynamicSamplingContext
52-
const txn = getRootSpan(span) as TransactionWithV7FrozenDsc | undefined;
53-
if (!txn) {
52+
const rootSpan = getRootSpan(span);
53+
if (!rootSpan) {
5454
return dsc;
5555
}
5656

5757
// TODO (v8): Remove v7FrozenDsc as a Transaction will no longer have _frozenDynamicSamplingContext
5858
// For now we need to avoid breaking users who directly created a txn with a DSC, where this field is still set.
5959
// @see Transaction class constructor
60-
const v7FrozenDsc = txn && txn._frozenDynamicSamplingContext;
60+
const v7FrozenDsc = rootSpan && (rootSpan as TransactionWithV7FrozenDsc)._frozenDynamicSamplingContext;
6161
if (v7FrozenDsc) {
6262
return v7FrozenDsc;
6363
}
6464

6565
// TODO (v8): Replace txn.metadata with txn.attributes[]
6666
// We can't do this yet because attributes aren't always set yet.
6767
// eslint-disable-next-line deprecation/deprecation
68-
const { sampleRate: maybeSampleRate } = txn.metadata;
68+
const { sampleRate: maybeSampleRate } = (rootSpan as TransactionWithV7FrozenDsc).metadata || {};
6969
if (maybeSampleRate != null) {
7070
dsc.sample_rate = `${maybeSampleRate}`;
7171
}
7272

7373
// We don't want to have a transaction name in the DSC if the source is "url" because URLs might contain PII
74-
const jsonSpan = spanToJSON(txn);
74+
const jsonSpan = spanToJSON(rootSpan);
7575

7676
const source = (jsonSpan.data || {})[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
7777

@@ -80,7 +80,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
8080
dsc.transaction = jsonSpan.description;
8181
}
8282

83-
dsc.sampled = String(spanIsSampled(txn));
83+
dsc.sampled = String(spanIsSampled(rootSpan));
8484

8585
client.emit('createDsc', dsc);
8686

packages/node/src/integrations/http.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/* eslint-disable max-lines */
22
import type * as http from 'http';
33
import type * as https from 'https';
4-
import type { Hub, SentrySpan } from '@sentry/core';
4+
import type { Hub } from '@sentry/core';
5+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan } from '@sentry/core';
56
import { defineIntegration, getIsolationScope, hasTracingEnabled } from '@sentry/core';
67
import {
78
addBreadcrumb,
8-
getActiveSpan,
99
getClient,
1010
getCurrentHub,
1111
getCurrentScope,
@@ -319,17 +319,18 @@ function _createWrappedRequestMethodFactory(
319319

320320
const scope = getCurrentScope();
321321
const isolationScope = getIsolationScope();
322-
const parentSpan = getActiveSpan() as SentrySpan;
323322

324-
const data = getRequestSpanData(requestUrl, requestOptions);
323+
const attributes = getRequestSpanData(requestUrl, requestOptions);
325324

326325
const requestSpan = shouldCreateSpan(rawRequestUrl)
327-
? // eslint-disable-next-line deprecation/deprecation
328-
parentSpan?.startChild({
326+
? startInactiveSpan({
327+
onlyIfParent: true,
329328
op: 'http.client',
330-
origin: 'auto.http.node.http',
331-
name: `${data['http.method']} ${data.url}`,
332-
data,
329+
name: `${attributes['http.method']} ${attributes.url}`,
330+
attributes: {
331+
...attributes,
332+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.node.http',
333+
},
333334
})
334335
: undefined;
335336

@@ -365,7 +366,7 @@ function _createWrappedRequestMethodFactory(
365366
// eslint-disable-next-line @typescript-eslint/no-this-alias
366367
const req = this;
367368
if (breadcrumbsEnabled) {
368-
addRequestBreadcrumb('response', data, req, res);
369+
addRequestBreadcrumb('response', attributes, req, res);
369370
}
370371
if (requestSpan) {
371372
if (res.statusCode) {
@@ -380,7 +381,7 @@ function _createWrappedRequestMethodFactory(
380381
const req = this;
381382

382383
if (breadcrumbsEnabled) {
383-
addRequestBreadcrumb('error', data, req);
384+
addRequestBreadcrumb('error', attributes, req);
384385
}
385386
if (requestSpan) {
386387
setHttpStatus(requestSpan, 500);

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

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import type { SentrySpan } from '@sentry/core';
1+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan } from '@sentry/core';
22
import {
33
SPAN_STATUS_ERROR,
44
addBreadcrumb,
55
defineIntegration,
6-
getActiveSpan,
76
getClient,
87
getCurrentScope,
98
getDynamicSamplingContextFromClient,
@@ -14,7 +13,14 @@ import {
1413
setHttpStatus,
1514
spanToTraceHeader,
1615
} from '@sentry/core';
17-
import type { EventProcessor, Integration, IntegrationFn, IntegrationFnResult, Span } from '@sentry/types';
16+
import type {
17+
EventProcessor,
18+
Integration,
19+
IntegrationFn,
20+
IntegrationFnResult,
21+
Span,
22+
SpanAttributes,
23+
} from '@sentry/types';
1824
import {
1925
LRUMap,
2026
dynamicSamplingContextToSentryBaggageHeader,
@@ -185,9 +191,8 @@ export class Undici implements Integration {
185191
const clientOptions = client.getOptions();
186192
const scope = getCurrentScope();
187193
const isolationScope = getIsolationScope();
188-
const parentSpan = getActiveSpan() as SentrySpan;
189194

190-
const span = this._shouldCreateSpan(stringUrl) ? createRequestSpan(parentSpan, request, stringUrl) : undefined;
195+
const span = this._shouldCreateSpan(stringUrl) ? createRequestSpan(request, stringUrl) : undefined;
191196
if (span) {
192197
request.__sentry_span__ = span;
193198
}
@@ -326,28 +331,24 @@ function setHeadersOnRequest(
326331
}
327332
}
328333

329-
function createRequestSpan(
330-
activeSpan: SentrySpan | undefined,
331-
request: RequestWithSentry,
332-
stringUrl: string,
333-
): Span | undefined {
334+
function createRequestSpan(request: RequestWithSentry, stringUrl: string): Span {
334335
const url = parseUrl(stringUrl);
335336

336337
const method = request.method || 'GET';
337-
const data: Record<string, unknown> = {
338+
const attributes: SpanAttributes = {
338339
'http.method': method,
340+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.node.undici',
339341
};
340342
if (url.search) {
341-
data['http.query'] = url.search;
343+
attributes['http.query'] = url.search;
342344
}
343345
if (url.hash) {
344-
data['http.fragment'] = url.hash;
346+
attributes['http.fragment'] = url.hash;
345347
}
346-
// eslint-disable-next-line deprecation/deprecation
347-
return activeSpan?.startChild({
348+
return startInactiveSpan({
349+
onlyIfParent: true,
348350
op: 'http.client',
349-
origin: 'auto.http.node.undici',
350351
name: `${method} ${getSanitizedUrlString(url)}`,
351-
data,
352+
attributes,
352353
});
353354
}

packages/node/test/integrations/http.test.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as http from 'http';
22
import * as https from 'https';
3-
import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getSpanDescendants } from '@sentry/core';
3+
import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getSpanDescendants, startSpan } from '@sentry/core';
44
import type { Hub } from '@sentry/core';
55
import { getCurrentHub, getIsolationScope, setCurrentClient } from '@sentry/core';
66
import { Transaction } from '@sentry/core';
@@ -55,7 +55,6 @@ describe('tracing', () => {
5555
});
5656

5757
expect(transaction).toBeInstanceOf(Transaction);
58-
5958
// eslint-disable-next-line deprecation/deprecation
6059
getCurrentScope().setSpan(transaction);
6160

@@ -207,19 +206,20 @@ describe('tracing', () => {
207206

208207
const { traceId } = getCurrentScope().getPropagationContext();
209208

210-
const request = http.get('http://dogs.are.great/');
209+
// Needs an outer span, or else we skip it
210+
const request = startSpan({ name: 'outer' }, () => http.get('http://dogs.are.great/'));
211211
const sentryTraceHeader = request.getHeader('sentry-trace') as string;
212212
const baggageHeader = request.getHeader('baggage') as string;
213213

214214
const parts = sentryTraceHeader.split('-');
215215

216-
// Should not include sampling decision since we don't wanna influence the tracing decisions downstream
217-
expect(parts.length).toEqual(2);
216+
expect(parts.length).toEqual(3);
218217
expect(parts[0]).toEqual(traceId);
219218
expect(parts[1]).toEqual(expect.any(String));
219+
expect(parts[2]).toEqual('1');
220220

221221
expect(baggageHeader).toEqual(
222-
`sentry-environment=production,sentry-release=1.0.0,sentry-public_key=dogsarebadatkeepingsecrets,sentry-trace_id=${traceId}`,
222+
`sentry-environment=production,sentry-release=1.0.0,sentry-public_key=dogsarebadatkeepingsecrets,sentry-trace_id=${traceId},sentry-sample_rate=1,sentry-transaction=outer,sentry-sampled=true`,
223223
);
224224
});
225225

@@ -237,7 +237,8 @@ describe('tracing', () => {
237237
},
238238
});
239239

240-
const request = http.get('http://dogs.are.great/');
240+
// Needs an outer span, or else we skip it
241+
const request = startSpan({ name: 'outer' }, () => http.get('http://dogs.are.great/'));
241242
const sentryTraceHeader = request.getHeader('sentry-trace') as string;
242243
const baggageHeader = request.getHeader('baggage') as string;
243244

0 commit comments

Comments
 (0)