Skip to content

Commit bcfde90

Browse files
authored
ref(v8): Remove metadata on transaction (#11397)
Instead, we freeze the DSC explicitly onto the transaction now.
1 parent 5f2295d commit bcfde90

File tree

8 files changed

+46
-210
lines changed

8 files changed

+46
-210
lines changed

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,7 @@ export function makeTerserPlugin() {
121121
// These are used by instrument.ts in utils for identifying HTML elements & events
122122
'_sentryCaptured',
123123
'_sentryId',
124-
// For v7 backwards-compatibility we need to access txn._frozenDynamicSamplingContext
125-
// TODO (v8): Remove this reserved word
126-
'_frozenDynamicSamplingContext',
124+
'_frozenDsc',
127125
// These are used to keep span & scope relationships
128126
'_sentryRootSpan',
129127
'_sentryChildSpans',

packages/core/src/tracing/dynamicSamplingContext.ts

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

44
import { DEFAULT_ENVIRONMENT } from '../constants';
55
import { getClient } from '../currentScopes';
6-
import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '../semanticAttributes';
6+
import { SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '../semanticAttributes';
77
import { getRootSpan, spanIsSampled, spanToJSON } from '../utils/spanUtils';
88

9+
/**
10+
* If you change this value, also update the terser plugin config to
11+
* avoid minification of the object property!
12+
*/
13+
const FROZEN_DSC_FIELD = '_frozenDsc';
14+
15+
type SpanWithMaybeDsc = Span & {
16+
[FROZEN_DSC_FIELD]?: Partial<DynamicSamplingContext> | undefined;
17+
};
18+
19+
/**
20+
* Freeze the given DSC on the given span.
21+
*/
22+
export function freezeDscOnSpan(span: Span, dsc: Partial<DynamicSamplingContext>): void {
23+
const spanWithMaybeDsc = span as SpanWithMaybeDsc;
24+
addNonEnumerableProperty(spanWithMaybeDsc, FROZEN_DSC_FIELD, dsc);
25+
}
26+
927
/**
1028
* Creates a dynamic sampling context from a client.
1129
*
@@ -28,11 +46,6 @@ export function getDynamicSamplingContextFromClient(trace_id: string, client: Cl
2846
return dsc;
2947
}
3048

31-
/**
32-
* A Span with a frozen dynamic sampling context.
33-
*/
34-
type TransactionWithV7FrozenDsc = Transaction & { _frozenDynamicSamplingContext?: DynamicSamplingContext };
35-
3649
/**
3750
* Creates a dynamic sampling context from a span (and client and scope)
3851
*
@@ -48,32 +61,26 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
4861

4962
const dsc = getDynamicSamplingContextFromClient(spanToJSON(span).trace_id || '', client);
5063

51-
// TODO (v8): Remove v7FrozenDsc as a Transaction will no longer have _frozenDynamicSamplingContext
5264
const rootSpan = getRootSpan(span);
5365
if (!rootSpan) {
5466
return dsc;
5567
}
5668

57-
// TODO (v8): Remove v7FrozenDsc as a Transaction will no longer have _frozenDynamicSamplingContext
58-
// For now we need to avoid breaking users who directly created a txn with a DSC, where this field is still set.
59-
// @see Transaction class constructor
60-
const v7FrozenDsc = rootSpan && (rootSpan as TransactionWithV7FrozenDsc)._frozenDynamicSamplingContext;
61-
if (v7FrozenDsc) {
62-
return v7FrozenDsc;
69+
const frozenDsc = (rootSpan as SpanWithMaybeDsc)[FROZEN_DSC_FIELD];
70+
if (frozenDsc) {
71+
return frozenDsc;
6372
}
6473

65-
// TODO (v8): Replace txn.metadata with txn.attributes[]
66-
// We can't do this yet because attributes aren't always set yet.
67-
// eslint-disable-next-line deprecation/deprecation
68-
const { sampleRate: maybeSampleRate } = (rootSpan as TransactionWithV7FrozenDsc).metadata || {};
74+
const jsonSpan = spanToJSON(rootSpan);
75+
const attributes = jsonSpan.data || {};
76+
const maybeSampleRate = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE];
77+
6978
if (maybeSampleRate != null) {
7079
dsc.sample_rate = `${maybeSampleRate}`;
7180
}
7281

7382
// 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(rootSpan);
75-
76-
const source = (jsonSpan.data || {})[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
83+
const source = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
7784

7885
// after JSON conversion, txn.name becomes jsonSpan.description
7986
if (source && source !== 'url') {

packages/core/src/tracing/trace.ts

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
spanTimeInputToSeconds,
2626
spanToJSON,
2727
} from '../utils/spanUtils';
28-
import { getDynamicSamplingContextFromSpan } from './dynamicSamplingContext';
28+
import { freezeDscOnSpan, getDynamicSamplingContextFromSpan } from './dynamicSamplingContext';
2929
import { logSpanStart } from './logSpans';
3030
import { sampleSpan } from './sampling';
3131
import { SentryNonRecordingSpan } from './sentryNonRecordingSpan';
@@ -245,12 +245,9 @@ function createChildSpanOrTransaction({
245245
parentSpanId,
246246
parentSampled: sampled,
247247
...spanContext,
248-
metadata: {
249-
dynamicSamplingContext: dsc,
250-
// eslint-disable-next-line deprecation/deprecation
251-
...spanContext.metadata,
252-
},
253248
});
249+
250+
freezeDscOnSpan(span, dsc);
254251
} else {
255252
const { traceId, dsc, parentSpanId, sampled } = {
256253
...isolationScope.getPropagationContext(),
@@ -262,23 +259,15 @@ function createChildSpanOrTransaction({
262259
parentSpanId,
263260
parentSampled: sampled,
264261
...spanContext,
265-
metadata: {
266-
dynamicSamplingContext: dsc,
267-
// eslint-disable-next-line deprecation/deprecation
268-
...spanContext.metadata,
269-
},
270262
});
263+
264+
if (dsc) {
265+
freezeDscOnSpan(span, dsc);
266+
}
271267
}
272268

273269
logSpanStart(span);
274270

275-
// TODO v8: Technically `startTransaction` can return undefined, which is not reflected by the types
276-
// This happens if tracing extensions have not been added
277-
// In this case, we just want to return a non-recording span
278-
if (!span) {
279-
return new SentryNonRecordingSpan();
280-
}
281-
282271
setCapturedScopesOnSpan(span, scope, isolationScope);
283272

284273
return span;

packages/core/src/tracing/transaction.ts

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type {
22
Contexts,
3-
DynamicSamplingContext,
43
Hub,
54
MeasurementUnit,
65
Measurements,
@@ -9,15 +8,14 @@ import type {
98
Transaction as TransactionInterface,
109
TransactionArguments,
1110
TransactionEvent,
12-
TransactionMetadata,
1311
TransactionSource,
1412
} from '@sentry/types';
1513
import { dropUndefinedKeys, logger } from '@sentry/utils';
1614

1715
import { DEBUG_BUILD } from '../debug-build';
1816
import { getCurrentHub } from '../hub';
1917
import { getMetricSummaryJsonForSpan } from '../metrics/metric-summary';
20-
import { SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '../semanticAttributes';
18+
import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '../semanticAttributes';
2119
import { getSpanDescendants, spanTimeInputToSeconds, spanToJSON, spanToTraceContext } from '../utils/spanUtils';
2220
import { getDynamicSamplingContextFromSpan } from './dynamicSamplingContext';
2321
import { SentrySpan } from './sentrySpan';
@@ -38,11 +36,6 @@ export class Transaction extends SentrySpan implements TransactionInterface {
3836

3937
private _trimEnd?: boolean | undefined;
4038

41-
// DO NOT yet remove this property, it is used in a hack for v7 backwards compatibility.
42-
private _frozenDynamicSamplingContext: Readonly<Partial<DynamicSamplingContext>> | undefined;
43-
44-
private _metadata: Partial<TransactionMetadata>;
45-
4639
/**
4740
* This constructor should never be called manually.
4841
* @internal
@@ -61,56 +54,14 @@ export class Transaction extends SentrySpan implements TransactionInterface {
6154

6255
this._name = transactionContext.name || '';
6356

64-
this._metadata = {
65-
// eslint-disable-next-line deprecation/deprecation
66-
...transactionContext.metadata,
67-
};
68-
6957
this._trimEnd = transactionContext.trimEnd;
7058

7159
this._attributes = {
7260
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'custom',
7361
...this._attributes,
7462
};
75-
76-
// If Dynamic Sampling Context is provided during the creation of the transaction, we freeze it as it usually means
77-
// there is incoming Dynamic Sampling Context. (Either through an incoming request, a baggage meta-tag, or other means)
78-
const incomingDynamicSamplingContext = this._metadata.dynamicSamplingContext;
79-
if (incomingDynamicSamplingContext) {
80-
// We shallow copy this in case anything writes to the original reference of the passed in `dynamicSamplingContext`
81-
this._frozenDynamicSamplingContext = { ...incomingDynamicSamplingContext };
82-
}
83-
}
84-
85-
// This sadly conflicts with the getter/setter ordering :(
86-
87-
/**
88-
* Get the metadata for this transaction.
89-
* @deprecated Use `spanGetMetadata(transaction)` instead.
90-
*/
91-
public get metadata(): TransactionMetadata {
92-
// We merge attributes in for backwards compatibility
93-
return {
94-
// Legacy metadata
95-
...this._metadata,
96-
97-
// From attributes
98-
...(this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE] && {
99-
sampleRate: this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE] as TransactionMetadata['sampleRate'],
100-
}),
101-
};
102-
}
103-
104-
/**
105-
* Update the metadata for this transaction.
106-
* @deprecated Use `spanGetMetadata(transaction)` instead.
107-
*/
108-
public set metadata(metadata: TransactionMetadata) {
109-
this._metadata = metadata;
11063
}
11164

112-
/* eslint-enable @typescript-eslint/member-ordering */
113-
11465
/** @inheritdoc */
11566
public updateName(name: string): this {
11667
this._name = name;
@@ -127,14 +78,6 @@ export class Transaction extends SentrySpan implements TransactionInterface {
12778
this._measurements[name] = { value, unit };
12879
}
12980

130-
/**
131-
* Store metadata on this transaction.
132-
* @deprecated Use attributes or store data on the scope instead.
133-
*/
134-
public setMetadata(newMetadata: Partial<TransactionMetadata>): void {
135-
this._metadata = { ...this._metadata, ...newMetadata };
136-
}
137-
13881
/**
13982
* @inheritDoc
14083
*/
@@ -198,9 +141,6 @@ export class Transaction extends SentrySpan implements TransactionInterface {
198141

199142
const { scope: capturedSpanScope, isolationScope: capturedSpanIsolationScope } = getCapturedScopesOnSpan(this);
200143

201-
// eslint-disable-next-line deprecation/deprecation
202-
const { metadata } = this;
203-
204144
const source = this._attributes['sentry.source'] as TransactionSource | undefined;
205145

206146
const transaction: TransactionEvent = {
@@ -215,7 +155,6 @@ export class Transaction extends SentrySpan implements TransactionInterface {
215155
transaction: this._name,
216156
type: 'transaction',
217157
sdkProcessingMetadata: {
218-
...metadata,
219158
capturedSpanScope,
220159
capturedSpanIsolationScope,
221160
...dropUndefinedKeys({

packages/core/test/lib/tracing/dynamicSamplingContext.test.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
getDynamicSamplingContextFromSpan,
1111
startInactiveSpan,
1212
} from '../../../src/tracing';
13+
import { freezeDscOnSpan } from '../../../src/tracing/dynamicSamplingContext';
1314
import { TestClient, getDefaultTestClientOptions } from '../../mocks/client';
1415

1516
describe('getDynamicSamplingContextFromSpan', () => {
@@ -25,13 +26,15 @@ describe('getDynamicSamplingContextFromSpan', () => {
2526
jest.resetAllMocks();
2627
});
2728

28-
test('returns the DSC provided during transaction creation', () => {
29+
test('uses frozen DSC from span', () => {
2930
// eslint-disable-next-line deprecation/deprecation -- using old API on purpose
3031
const transaction = new Transaction({
3132
name: 'tx',
32-
metadata: { dynamicSamplingContext: { environment: 'myEnv' } },
33+
sampled: true,
3334
});
3435

36+
freezeDscOnSpan(transaction, { environment: 'myEnv' });
37+
3538
const dynamicSamplingContext = getDynamicSamplingContextFromSpan(transaction);
3639

3740
expect(dynamicSamplingContext).toStrictEqual({ environment: 'myEnv' });
@@ -77,10 +80,8 @@ describe('getDynamicSamplingContextFromSpan', () => {
7780
// eslint-disable-next-line deprecation/deprecation -- using old API on purpose
7881
const transaction = new Transaction({
7982
name: 'tx',
80-
metadata: {
81-
sampleRate: 0.56,
82-
},
8383
attributes: {
84+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 0.56,
8485
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
8586
},
8687
sampled: true,
@@ -103,11 +104,9 @@ describe('getDynamicSamplingContextFromSpan', () => {
103104
// eslint-disable-next-line deprecation/deprecation -- using old API on purpose
104105
const transaction = new Transaction({
105106
name: 'tx',
106-
metadata: {
107-
sampleRate: 0.56,
108-
},
109107
attributes: {
110108
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
109+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 0.56,
111110
},
112111
});
113112

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import {
2-
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
3-
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
4-
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
5-
Transaction,
6-
spanToJSON,
7-
} from '../../../src';
1+
import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, Transaction, spanToJSON } from '../../../src';
82

93
describe('transaction', () => {
104
describe('name', () => {
@@ -27,53 +21,4 @@ describe('transaction', () => {
2721
});
2822
/* eslint-enable deprecation/deprecation */
2923
});
30-
31-
describe('metadata', () => {
32-
/* eslint-disable deprecation/deprecation */
33-
it('works with defaults', () => {
34-
const transaction = new Transaction({ name: 'span name' });
35-
expect(transaction.metadata).toEqual({});
36-
});
37-
38-
it('allows to set metadata in constructor', () => {
39-
const transaction = new Transaction({ name: 'span name', metadata: { request: {} } });
40-
expect(transaction.metadata).toEqual({
41-
request: {},
42-
});
43-
});
44-
45-
it('allows to set source & sample rate data in constructor', () => {
46-
const transaction = new Transaction({
47-
name: 'span name',
48-
metadata: { request: {} },
49-
attributes: {
50-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
51-
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 0.5,
52-
},
53-
});
54-
55-
expect(transaction.metadata).toEqual({
56-
sampleRate: 0.5,
57-
request: {},
58-
});
59-
60-
expect(spanToJSON(transaction).data).toEqual({
61-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'manual',
62-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
63-
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 0.5,
64-
});
65-
});
66-
67-
it('allows to update metadata via setMetadata', () => {
68-
const transaction = new Transaction({ name: 'span name', metadata: {} });
69-
70-
transaction.setMetadata({ request: {} });
71-
72-
expect(transaction.metadata).toEqual({
73-
request: {},
74-
});
75-
});
76-
77-
/* eslint-enable deprecation/deprecation */
78-
});
7924
});

packages/types/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ export type {
111111
TraceparentData,
112112
Transaction,
113113
TransactionArguments,
114-
TransactionMetadata,
115114
TransactionSource,
116115
} from './transaction';
117116
export type {

0 commit comments

Comments
 (0)