Skip to content

Commit 6a7d179

Browse files
authored
fix(core): Don't gate user data for streamed spans at scope read time (#20827)
User data should be gated at write time where it is put on the scope. If data makes it onto the scope we should not gate anymore so that if a user explicitly calls for instance `Sentry.setUser()` the data is set on the span (which is expected since the user made an explicit decision to include this). Closes #20825
1 parent ad47c3c commit 6a7d179

3 files changed

Lines changed: 115 additions & 180 deletions

File tree

packages/core/src/semanticAttributes.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ export const SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME = 'sentry.sdk.name';
5353
/** The version of the Sentry SDK */
5454
export const SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION = 'sentry.sdk.version';
5555

56-
/** The user ID (gated by sendDefaultPii) */
56+
/** The user ID */
5757
export const SEMANTIC_ATTRIBUTE_USER_ID = 'user.id';
58-
/** The user email (gated by sendDefaultPii) */
58+
/** The user email */
5959
export const SEMANTIC_ATTRIBUTE_USER_EMAIL = 'user.email';
60-
/** The user IP address (gated by sendDefaultPii) */
60+
/** The user IP address */
6161
export const SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS = 'user.ip_address';
62-
/** The user username (gated by sendDefaultPii) */
62+
/** The user username */
6363
export const SEMANTIC_ATTRIBUTE_USER_USERNAME = 'user.name';
6464

6565
/**

packages/core/src/tracing/spans/captureSpan.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ function applyCommonSpanAttributes(
125125
scopeData: ScopeData,
126126
): void {
127127
const sdk = client.getSdkMetadata();
128-
const { release, environment, sendDefaultPii } = client.getOptions();
128+
const { release, environment } = client.getOptions();
129129

130130
// avoid overwriting any previously set attributes (from users or potentially our SDK instrumentation)
131131
safeSetSpanJSONAttributes(spanJSON, {
@@ -135,14 +135,10 @@ function applyCommonSpanAttributes(
135135
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: serializedSegmentSpan.span_id,
136136
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME]: sdk?.sdk?.name,
137137
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION]: sdk?.sdk?.version,
138-
...(sendDefaultPii
139-
? {
140-
[SEMANTIC_ATTRIBUTE_USER_ID]: scopeData.user?.id,
141-
[SEMANTIC_ATTRIBUTE_USER_EMAIL]: scopeData.user?.email,
142-
[SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: scopeData.user?.ip_address,
143-
[SEMANTIC_ATTRIBUTE_USER_USERNAME]: scopeData.user?.username,
144-
}
145-
: {}),
138+
[SEMANTIC_ATTRIBUTE_USER_ID]: scopeData.user?.id,
139+
[SEMANTIC_ATTRIBUTE_USER_EMAIL]: scopeData.user?.email,
140+
[SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: scopeData.user?.ip_address,
141+
[SEMANTIC_ATTRIBUTE_USER_USERNAME]: scopeData.user?.username,
146142
...scopeData.attributes,
147143
});
148144
}

packages/core/test/lib/tracing/spans/captureSpan.test.ts

Lines changed: 106 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -25,179 +25,102 @@ import { inferSpanDataFromOtelAttributes, safeSetSpanJSONAttributes } from '../.
2525
import { getDefaultTestClientOptions, TestClient } from '../../../mocks/client';
2626

2727
describe('captureSpan', () => {
28-
it('captures user attributes iff sendDefaultPii is true', () => {
29-
const client = new TestClient(
30-
getDefaultTestClientOptions({
31-
dsn: 'https://dsn@ingest.f00.f00/1',
32-
tracesSampleRate: 1,
33-
release: '1.0.0',
34-
environment: 'staging',
35-
sendDefaultPii: true,
36-
}),
37-
);
38-
39-
const span = withScope(scope => {
40-
scope.setClient(client);
41-
scope.setUser({
42-
id: '123',
43-
email: 'user@example.com',
44-
username: 'testuser',
45-
ip_address: '127.0.0.1',
46-
});
47-
48-
const span = startInactiveSpan({ name: 'my-span', attributes: { 'sentry.op': 'http.client' } });
49-
span.end();
50-
51-
return span;
52-
});
53-
54-
const serializedSpan = captureSpan(span, client);
28+
it.each([true, false, undefined])(
29+
'always applies scope user attributes to spans (sendDefaultPii: %s)',
30+
sendDefaultPii => {
31+
const client = new TestClient(
32+
getDefaultTestClientOptions({
33+
dsn: 'https://dsn@ingest.f00.f00/1',
34+
tracesSampleRate: 1,
35+
release: '1.0.0',
36+
environment: 'staging',
37+
sendDefaultPii,
38+
}),
39+
);
5540

56-
expect(serializedSpan).toStrictEqual({
57-
span_id: expect.stringMatching(/^[\da-f]{16}$/),
58-
trace_id: expect.stringMatching(/^[\da-f]{32}$/),
59-
parent_span_id: undefined,
60-
links: undefined,
61-
start_timestamp: expect.any(Number),
62-
name: 'my-span',
63-
end_timestamp: expect.any(Number),
64-
status: 'ok',
65-
is_segment: true,
66-
attributes: {
67-
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: {
68-
type: 'string',
69-
value: 'http.client',
70-
},
71-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: {
72-
type: 'string',
73-
value: 'manual',
74-
},
75-
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: {
76-
type: 'integer',
77-
value: 1,
78-
},
79-
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: {
80-
value: 'my-span',
81-
type: 'string',
82-
},
83-
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: {
84-
value: span.spanContext().spanId,
85-
type: 'string',
86-
},
87-
'sentry.span.source': {
88-
value: 'custom',
89-
type: 'string',
90-
},
91-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: {
92-
value: 'custom',
93-
type: 'string',
94-
},
95-
[SEMANTIC_ATTRIBUTE_SENTRY_RELEASE]: {
96-
value: '1.0.0',
97-
type: 'string',
98-
},
99-
[SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT]: {
100-
value: 'staging',
101-
type: 'string',
102-
},
103-
[SEMANTIC_ATTRIBUTE_USER_ID]: {
104-
value: '123',
105-
type: 'string',
106-
},
107-
[SEMANTIC_ATTRIBUTE_USER_EMAIL]: {
108-
value: 'user@example.com',
109-
type: 'string',
110-
},
111-
[SEMANTIC_ATTRIBUTE_USER_USERNAME]: {
112-
value: 'testuser',
113-
type: 'string',
114-
},
115-
[SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: {
116-
value: '127.0.0.1',
117-
type: 'string',
118-
},
119-
},
120-
_segmentSpan: span,
121-
});
122-
});
41+
const span = withScope(scope => {
42+
scope.setClient(client);
43+
scope.setUser({
44+
id: '123',
45+
email: 'user@example.com',
46+
username: 'testuser',
47+
ip_address: '127.0.0.1',
48+
});
12349

124-
it.each([false, undefined])("doesn't capture user attributes if sendDefaultPii is %s", sendDefaultPii => {
125-
const client = new TestClient(
126-
getDefaultTestClientOptions({
127-
dsn: 'https://dsn@ingest.f00.f00/1',
128-
tracesSampleRate: 1,
129-
release: '1.0.0',
130-
environment: 'staging',
131-
sendDefaultPii,
132-
}),
133-
);
50+
const span = startInactiveSpan({ name: 'my-span', attributes: { 'sentry.op': 'http.client' } });
51+
span.end();
13452

135-
const span = withScope(scope => {
136-
scope.setClient(client);
137-
scope.setUser({
138-
id: '123',
139-
email: 'user@example.com',
140-
username: 'testuser',
141-
ip_address: '127.0.0.1',
53+
return span;
14254
});
14355

144-
const span = startInactiveSpan({ name: 'my-span', attributes: { 'sentry.op': 'http.client' } });
145-
span.end();
146-
147-
return span;
148-
});
149-
150-
expect(captureSpan(span, client)).toStrictEqual({
151-
span_id: expect.stringMatching(/^[\da-f]{16}$/),
152-
trace_id: expect.stringMatching(/^[\da-f]{32}$/),
153-
parent_span_id: undefined,
154-
links: undefined,
155-
start_timestamp: expect.any(Number),
156-
name: 'my-span',
157-
end_timestamp: expect.any(Number),
158-
status: 'ok',
159-
is_segment: true,
160-
attributes: {
161-
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: {
162-
type: 'string',
163-
value: 'http.client',
164-
},
165-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: {
166-
type: 'string',
167-
value: 'manual',
168-
},
169-
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: {
170-
type: 'integer',
171-
value: 1,
172-
},
173-
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: {
174-
value: 'my-span',
175-
type: 'string',
176-
},
177-
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: {
178-
value: span.spanContext().spanId,
179-
type: 'string',
180-
},
181-
'sentry.span.source': {
182-
value: 'custom',
183-
type: 'string',
184-
},
185-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: {
186-
value: 'custom',
187-
type: 'string',
188-
},
189-
[SEMANTIC_ATTRIBUTE_SENTRY_RELEASE]: {
190-
value: '1.0.0',
191-
type: 'string',
192-
},
193-
[SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT]: {
194-
value: 'staging',
195-
type: 'string',
56+
expect(captureSpan(span, client)).toStrictEqual({
57+
span_id: expect.stringMatching(/^[\da-f]{16}$/),
58+
trace_id: expect.stringMatching(/^[\da-f]{32}$/),
59+
parent_span_id: undefined,
60+
links: undefined,
61+
start_timestamp: expect.any(Number),
62+
name: 'my-span',
63+
end_timestamp: expect.any(Number),
64+
status: 'ok',
65+
is_segment: true,
66+
attributes: {
67+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: {
68+
type: 'string',
69+
value: 'http.client',
70+
},
71+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: {
72+
type: 'string',
73+
value: 'manual',
74+
},
75+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: {
76+
type: 'integer',
77+
value: 1,
78+
},
79+
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: {
80+
value: 'my-span',
81+
type: 'string',
82+
},
83+
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: {
84+
value: span.spanContext().spanId,
85+
type: 'string',
86+
},
87+
'sentry.span.source': {
88+
value: 'custom',
89+
type: 'string',
90+
},
91+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: {
92+
value: 'custom',
93+
type: 'string',
94+
},
95+
[SEMANTIC_ATTRIBUTE_SENTRY_RELEASE]: {
96+
value: '1.0.0',
97+
type: 'string',
98+
},
99+
[SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT]: {
100+
value: 'staging',
101+
type: 'string',
102+
},
103+
[SEMANTIC_ATTRIBUTE_USER_ID]: {
104+
value: '123',
105+
type: 'string',
106+
},
107+
[SEMANTIC_ATTRIBUTE_USER_EMAIL]: {
108+
value: 'user@example.com',
109+
type: 'string',
110+
},
111+
[SEMANTIC_ATTRIBUTE_USER_USERNAME]: {
112+
value: 'testuser',
113+
type: 'string',
114+
},
115+
[SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: {
116+
value: '127.0.0.1',
117+
type: 'string',
118+
},
196119
},
197-
},
198-
_segmentSpan: span,
199-
});
200-
});
120+
_segmentSpan: span,
121+
});
122+
},
123+
);
201124

202125
it('captures sdk name and version if available', () => {
203126
const client = new TestClient(
@@ -286,6 +209,22 @@ describe('captureSpan', () => {
286209
value: '1.0.0',
287210
type: 'string',
288211
},
212+
[SEMANTIC_ATTRIBUTE_USER_ID]: {
213+
value: '123',
214+
type: 'string',
215+
},
216+
[SEMANTIC_ATTRIBUTE_USER_EMAIL]: {
217+
value: 'user@example.com',
218+
type: 'string',
219+
},
220+
[SEMANTIC_ATTRIBUTE_USER_USERNAME]: {
221+
value: 'testuser',
222+
type: 'string',
223+
},
224+
[SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: {
225+
value: '127.0.0.1',
226+
type: 'string',
227+
},
289228
},
290229
_segmentSpan: span,
291230
});

0 commit comments

Comments
 (0)