Skip to content

Commit a8d5d72

Browse files
committed
feat(core): Deprecate Transaction.getDynamicSamplingContext in favour of getDynamicSamplingContextFromSpan
1 parent d41e39e commit a8d5d72

File tree

21 files changed

+135
-63
lines changed

21 files changed

+135
-63
lines changed

MIGRATION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ In v8, the Span class is heavily reworked. The following properties & methods ar
9393
* `span.traceId`: Use `span.spanContext().traceId` instead.
9494
* `span.name`: Use `spanToJSON(span).description` instead.
9595
* `span.description`: Use `spanToJSON(span).description` instead.
96+
* `span.getDynamicSamplingContext`: Use `getDynamicSamplingContextFromSpan` utility function instead.
9697
* `transaction.setMetadata()`: Use attributes instead, or set data on the scope.
9798
* `transaction.metadata`: Use attributes instead, or set data on the scope.
9899

dev-packages/rollup-utils/plugins/bundlePlugins.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ export function makeTerserPlugin() {
135135
// These are used by instrument.ts in utils for identifying HTML elements & events
136136
'_sentryCaptured',
137137
'_sentryId',
138+
// For v7 backwards-compatibility we need to access txn._frozenDynamicSamplingContext
139+
// TODO (v8): Remove this reserved word
140+
'_frozenDynamicSamplingContext',
138141
],
139142
},
140143
},

packages/astro/src/server/meta.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { getDynamicSamplingContextFromClient, spanToTraceHeader } from '@sentry/core';
2+
import { getDynamicSamplingContextFromSpan } from '@sentry/core/src/tracing/dynamicSamplingContext';
23
import type { Client, Scope, Span } from '@sentry/types';
34
import {
45
TRACEPARENT_REGEXP,
@@ -33,7 +34,7 @@ export function getTracingMetaTags(
3334
const sentryTrace = span ? spanToTraceHeader(span) : generateSentryTraceHeader(traceId, undefined, sampled);
3435

3536
const dynamicSamplingContext = transaction
36-
? transaction.getDynamicSamplingContext()
37+
? getDynamicSamplingContextFromSpan(transaction)
3738
: dsc
3839
? dsc
3940
: client

packages/core/src/server-runtime-client.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ import { getClient } from './exports';
2121
import { MetricsAggregator } from './metrics/aggregator';
2222
import type { Scope } from './scope';
2323
import { SessionFlusher } from './sessionflusher';
24-
import { addTracingExtensions, getDynamicSamplingContextFromClient } from './tracing';
24+
import {
25+
addTracingExtensions,
26+
getDynamicSamplingContextFromClient,
27+
getDynamicSamplingContextFromSpan,
28+
} from './tracing';
2529
import { spanToTraceContext } from './utils/spanUtils';
2630

2731
export interface ServerRuntimeClientOptions extends ClientOptions<BaseTransportOptions> {
@@ -257,7 +261,7 @@ export class ServerRuntimeClient<
257261

258262
const span = scope.getSpan();
259263
if (span) {
260-
const samplingContext = span.transaction ? span.transaction.getDynamicSamplingContext() : undefined;
264+
const samplingContext = span.transaction ? getDynamicSamplingContextFromSpan(span) : undefined;
261265
return [samplingContext, spanToTraceContext(span)];
262266
}
263267

packages/core/src/tracing/dynamicSamplingContext.ts

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
import type { Client, DynamicSamplingContext, Scope } from '@sentry/types';
1+
import type { Client, DynamicSamplingContext, Scope, Span } from '@sentry/types';
22
import { dropUndefinedKeys } from '@sentry/utils';
33

44
import { DEFAULT_ENVIRONMENT } from '../constants';
5+
import { getClient, getCurrentScope } from '../exports';
56

67
/**
78
* Creates a dynamic sampling context from a client.
89
*
9-
* Dispatchs the `createDsc` lifecycle hook as a side effect.
10+
* Dispatches the `createDsc` lifecycle hook as a side effect.
1011
*/
1112
export function getDynamicSamplingContextFromClient(
1213
trace_id: string,
1314
client: Client,
1415
scope?: Scope,
16+
emitHook: boolean = true,
1517
): DynamicSamplingContext {
1618
const options = client.getOptions();
1719

@@ -26,6 +28,64 @@ export function getDynamicSamplingContextFromClient(
2628
trace_id,
2729
}) as DynamicSamplingContext;
2830

31+
if (emitHook) {
32+
client.emit && client.emit('createDsc', dsc);
33+
}
34+
35+
return dsc;
36+
}
37+
38+
/**
39+
* A Span with a frozen dynamic sampling context.
40+
*/
41+
type TransactionWithV7FrozenDsc = Span & { _frozenDynamicSamplingContext?: DynamicSamplingContext };
42+
43+
/**
44+
* Creates a dynamic sampling context from a span (and client and scope)
45+
*
46+
* @param span the span from which a few values like the root span name and sample rate are extracted.
47+
*
48+
* @returns a dynamic sampling context
49+
*/
50+
export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<DynamicSamplingContext>> {
51+
// TODO (v8): Remove v7FrozenDsc as a Transaction will no longer have _frozenDynamicSamplingContext
52+
// For now we need to avoid breaking users who directly created a txn with a DSC, where this field is still set.
53+
// @see Transaction class constructor
54+
const v7FrozenDsc = (span as TransactionWithV7FrozenDsc)._frozenDynamicSamplingContext;
55+
if (v7FrozenDsc) {
56+
return v7FrozenDsc;
57+
}
58+
59+
const client = getClient();
60+
if (!client) {
61+
return {};
62+
}
63+
64+
// passing emit=false here to only emit later once the DSC is actually populated
65+
const dsc = getDynamicSamplingContextFromClient(span.traceId, client, getCurrentScope(), false);
66+
const txn = span.transaction;
67+
if (!txn) {
68+
return dsc;
69+
}
70+
71+
const maybeSampleRate = txn.metadata.sampleRate;
72+
if (maybeSampleRate !== undefined) {
73+
dsc.sample_rate = `${maybeSampleRate}`;
74+
}
75+
76+
// We don't want to have a transaction name in the DSC if the source is "url" because URLs might contain PII
77+
const source = txn.metadata.source;
78+
if (source && source !== 'url') {
79+
dsc.transaction = txn.name;
80+
}
81+
82+
// TODO: Switch to `spanIsSampled` once we have it
83+
// eslint-disable-next-line deprecation/deprecation
84+
if (txn.sampled !== undefined) {
85+
// eslint-disable-next-line deprecation/deprecation
86+
dsc.sampled = String(txn.sampled);
87+
}
88+
2989
client.emit && client.emit('createDsc', dsc);
3090

3191
return dsc;

packages/core/src/tracing/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ export {
1919
startSpanManual,
2020
continueTrace,
2121
} from './trace';
22-
export { getDynamicSamplingContextFromClient } from './dynamicSamplingContext';
22+
export { getDynamicSamplingContextFromClient, getDynamicSamplingContextFromSpan } from './dynamicSamplingContext';
2323
export { setMeasurement } from './measurement';

packages/core/src/tracing/transaction.ts

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import type { Hub } from '../hub';
1717
import { getCurrentHub } from '../hub';
1818
import { SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '../semanticAttributes';
1919
import { spanTimeInputToSeconds, spanToTraceContext } from '../utils/spanUtils';
20-
import { getDynamicSamplingContextFromClient } from './dynamicSamplingContext';
20+
import { getDynamicSamplingContextFromSpan } from './dynamicSamplingContext';
2121
import { Span as SpanClass, SpanRecorder } from './span';
2222

2323
/** JSDoc */
@@ -227,43 +227,11 @@ export class Transaction extends SpanClass implements TransactionInterface {
227227
* @inheritdoc
228228
*
229229
* @experimental
230+
*
231+
* @deprecated Use top-level `getDynamicSamplingContextFromSpan` instead.
230232
*/
231233
public getDynamicSamplingContext(): Readonly<Partial<DynamicSamplingContext>> {
232-
if (this._frozenDynamicSamplingContext) {
233-
return this._frozenDynamicSamplingContext;
234-
}
235-
236-
const hub = this._hub || getCurrentHub();
237-
const client = hub.getClient();
238-
239-
if (!client) return {};
240-
241-
const { _traceId: traceId, _sampled: sampled } = this;
242-
243-
const scope = hub.getScope();
244-
const dsc = getDynamicSamplingContextFromClient(traceId, client, scope);
245-
246-
// eslint-disable-next-line deprecation/deprecation
247-
const maybeSampleRate = this.metadata.sampleRate;
248-
if (maybeSampleRate !== undefined) {
249-
dsc.sample_rate = `${maybeSampleRate}`;
250-
}
251-
252-
// We don't want to have a transaction name in the DSC if the source is "url" because URLs might contain PII
253-
// eslint-disable-next-line deprecation/deprecation
254-
const source = this.metadata.source;
255-
if (source && source !== 'url') {
256-
dsc.transaction = this._name;
257-
}
258-
259-
if (sampled !== undefined) {
260-
dsc.sampled = String(sampled);
261-
}
262-
263-
// Uncomment if we want to make DSC immutable
264-
// this._frozenDynamicSamplingContext = dsc;
265-
266-
return dsc;
234+
return getDynamicSamplingContextFromSpan(this);
267235
}
268236

269237
/**
@@ -340,7 +308,7 @@ export class Transaction extends SpanClass implements TransactionInterface {
340308
type: 'transaction',
341309
sdkProcessingMetadata: {
342310
...metadata,
343-
dynamicSamplingContext: this.getDynamicSamplingContext(),
311+
dynamicSamplingContext: getDynamicSamplingContextFromSpan(this),
344312
},
345313
...(source && {
346314
transaction_info: {

packages/core/src/utils/applyScopeDataToEvent.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Breadcrumb, Event, PropagationContext, ScopeData, Span } from '@sentry/types';
22
import { arrayify } from '@sentry/utils';
3+
import { getDynamicSamplingContextFromSpan } from '../tracing/dynamicSamplingContext';
34
import { spanToJSON, spanToTraceContext } from './spanUtils';
45

56
/**
@@ -176,7 +177,7 @@ function applySpanToEvent(event: Event, span: Span): void {
176177
const transaction = span.transaction;
177178
if (transaction) {
178179
event.sdkProcessingMetadata = {
179-
dynamicSamplingContext: transaction.getDynamicSamplingContext(),
180+
dynamicSamplingContext: getDynamicSamplingContextFromSpan(span),
180181
...event.sdkProcessingMetadata,
181182
};
182183
const transactionName = spanToJSON(transaction).description;

packages/nextjs/src/common/wrapAppGetInitialPropsWithSentry.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { addTracingExtensions, getClient, getCurrentScope, spanToTraceHeader } from '@sentry/core';
1+
import {
2+
addTracingExtensions,
3+
getClient,
4+
getCurrentScope,
5+
getDynamicSamplingContextFromSpan,
6+
spanToTraceHeader,
7+
} from '@sentry/core';
28
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
39
import type App from 'next/app';
410

@@ -66,7 +72,7 @@ export function wrapAppGetInitialPropsWithSentry(origAppGetInitialProps: AppGetI
6672
if (requestTransaction) {
6773
appGetInitialProps.pageProps._sentryTraceData = spanToTraceHeader(requestTransaction);
6874

69-
const dynamicSamplingContext = requestTransaction.getDynamicSamplingContext();
75+
const dynamicSamplingContext = getDynamicSamplingContextFromSpan(requestTransaction);
7076
appGetInitialProps.pageProps._sentryBaggage =
7177
dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
7278
}

packages/nextjs/src/common/wrapErrorGetInitialPropsWithSentry.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { addTracingExtensions, getClient, getCurrentScope, spanToTraceHeader } from '@sentry/core';
1+
import {
2+
addTracingExtensions,
3+
getClient,
4+
getCurrentScope,
5+
getDynamicSamplingContextFromSpan,
6+
spanToTraceHeader,
7+
} from '@sentry/core';
28
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
39
import type { NextPageContext } from 'next';
410
import type { ErrorProps } from 'next/error';
@@ -58,7 +64,7 @@ export function wrapErrorGetInitialPropsWithSentry(
5864
if (requestTransaction) {
5965
errorGetInitialProps._sentryTraceData = spanToTraceHeader(requestTransaction);
6066

61-
const dynamicSamplingContext = requestTransaction.getDynamicSamplingContext();
67+
const dynamicSamplingContext = getDynamicSamplingContextFromSpan(requestTransaction);
6268
errorGetInitialProps._sentryBaggage = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
6369
}
6470

0 commit comments

Comments
 (0)