Skip to content

Commit e0a8e88

Browse files
committed
feat(core): Deprecate Transaction.getDynamicSamplingContext in favour of getDynamicSamplingContextFromSpan
1 parent 2cfb0ef commit e0a8e88

File tree

21 files changed

+135
-60
lines changed

21 files changed

+135
-60
lines changed

MIGRATION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ In v8, the Span class is heavily reworked. The following properties & methods ar
6969
* `span.toTraceparent()`: use `spanToTraceHeader(span)` util instead.
7070
* `span.getTraceContext()`: Use `spanToTraceContext(span)` utility function instead.
7171
* `span.sampled`: Use `span.isRecording()` instead.
72+
* `span.getDynamicSamplingContext`: Use `getDynamicSamplingContextFromSpan` utility function instead.
7273

7374
## Deprecate `pushScope` & `popScope` in favor of `withScope`
7475

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 & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { DEBUG_BUILD } from '../debug-build';
1616
import type { Hub } from '../hub';
1717
import { getCurrentHub } from '../hub';
1818
import { spanTimeInputToSeconds, spanToTraceContext } from '../utils/spanUtils';
19-
import { getDynamicSamplingContextFromClient } from './dynamicSamplingContext';
19+
import { getDynamicSamplingContextFromSpan } from './dynamicSamplingContext';
2020
import { Span as SpanClass, SpanRecorder } from './span';
2121

2222
/** JSDoc */
@@ -189,39 +189,11 @@ export class Transaction extends SpanClass implements TransactionInterface {
189189
* @inheritdoc
190190
*
191191
* @experimental
192+
*
193+
* @deprecated Use top-level `getDynamicSamplingContextFromSpan` instead.
192194
*/
193195
public getDynamicSamplingContext(): Readonly<Partial<DynamicSamplingContext>> {
194-
if (this._frozenDynamicSamplingContext) {
195-
return this._frozenDynamicSamplingContext;
196-
}
197-
198-
const hub = this._hub || getCurrentHub();
199-
const client = hub.getClient();
200-
201-
if (!client) return {};
202-
203-
const scope = hub.getScope();
204-
const dsc = getDynamicSamplingContextFromClient(this.traceId, client, scope);
205-
206-
const maybeSampleRate = this.metadata.sampleRate;
207-
if (maybeSampleRate !== undefined) {
208-
dsc.sample_rate = `${maybeSampleRate}`;
209-
}
210-
211-
// We don't want to have a transaction name in the DSC if the source is "url" because URLs might contain PII
212-
const source = this.metadata.source;
213-
if (source && source !== 'url') {
214-
dsc.transaction = this.name;
215-
}
216-
217-
if (this.sampled !== undefined) {
218-
dsc.sampled = String(this.sampled);
219-
}
220-
221-
// Uncomment if we want to make DSC immutable
222-
// this._frozenDynamicSamplingContext = dsc;
223-
224-
return dsc;
196+
return getDynamicSamplingContextFromSpan(this);
225197
}
226198

227199
/**
@@ -295,7 +267,7 @@ export class Transaction extends SpanClass implements TransactionInterface {
295267
type: 'transaction',
296268
sdkProcessingMetadata: {
297269
...metadata,
298-
dynamicSamplingContext: this.getDynamicSamplingContext(),
270+
dynamicSamplingContext: getDynamicSamplingContextFromSpan(this),
299271
},
300272
...(metadata.source && {
301273
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';
34
import { spanToTraceContext } from './spanUtils';
45

56
/**
@@ -166,7 +167,7 @@ function applySpanToEvent(event: Event, span: Span): void {
166167
const transaction = span.transaction;
167168
if (transaction) {
168169
event.sdkProcessingMetadata = {
169-
dynamicSamplingContext: transaction.getDynamicSamplingContext(),
170+
dynamicSamplingContext: getDynamicSamplingContextFromSpan(span),
170171
...event.sdkProcessingMetadata,
171172
};
172173
const transactionName = transaction.name;

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

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

68-
const dynamicSamplingContext = requestTransaction.getDynamicSamplingContext();
74+
const dynamicSamplingContext = getDynamicSamplingContextFromSpan(requestTransaction);
6975
appGetInitialProps.pageProps._sentryBaggage =
7076
dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
7177
}

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';
@@ -57,7 +63,7 @@ export function wrapErrorGetInitialPropsWithSentry(
5763
if (requestTransaction) {
5864
errorGetInitialProps._sentryTraceData = spanToTraceHeader(requestTransaction);
5965

60-
const dynamicSamplingContext = requestTransaction.getDynamicSamplingContext();
66+
const dynamicSamplingContext = getDynamicSamplingContextFromSpan(requestTransaction);
6167
errorGetInitialProps._sentryBaggage = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
6268
}
6369

0 commit comments

Comments
 (0)