Skip to content

Commit 7f1087d

Browse files
authored
feat: Stop using dropUndefinedKeys (#15796)
This removes the last remaining usages of `dropUndefinedKeys` in the SDK. It also deprecates the export from `@sentry/core` for future removal.
1 parent c276386 commit 7f1087d

File tree

15 files changed

+61
-58
lines changed

15 files changed

+61
-58
lines changed

dev-packages/e2e-tests/test-applications/nuxt-3/server/plugins/customNitroErrorHandler.ts

+13-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Context, GLOBAL_OBJ, dropUndefinedKeys, flush, logger, vercelWaitUntil } from '@sentry/core';
1+
import { Context, GLOBAL_OBJ, flush, logger, vercelWaitUntil } from '@sentry/core';
22
import * as SentryNode from '@sentry/node';
33
import { H3Error } from 'h3';
44
import type { CapturedErrorContext } from 'nitropack';
@@ -36,24 +36,22 @@ export default defineNitroPlugin(nitroApp => {
3636
});
3737

3838
function extractErrorContext(errorContext: CapturedErrorContext): Context {
39-
const structuredContext: Context = {
40-
method: undefined,
41-
path: undefined,
42-
tags: undefined,
43-
};
39+
const ctx: Context = {};
4440

45-
if (errorContext) {
46-
if (errorContext.event) {
47-
structuredContext.method = errorContext.event._method || undefined;
48-
structuredContext.path = errorContext.event._path || undefined;
49-
}
41+
if (!errorContext) {
42+
return ctx;
43+
}
5044

51-
if (Array.isArray(errorContext.tags)) {
52-
structuredContext.tags = errorContext.tags || undefined;
53-
}
45+
if (errorContext.event) {
46+
ctx.method = errorContext.event._method;
47+
ctx.path = errorContext.event._path;
48+
}
49+
50+
if (Array.isArray(errorContext.tags)) {
51+
ctx.tags = errorContext.tags;
5452
}
5553

56-
return dropUndefinedKeys(structuredContext);
54+
return ctx;
5755
}
5856

5957
async function flushIfServerless(): Promise<void> {

packages/browser/test/tracing/browserTracingIntegration.test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@ describe('browserTracingIntegration', () => {
728728
sampled: true,
729729
sampleRand: expect.any(Number),
730730
dsc: {
731+
release: undefined,
731732
environment: 'production',
732733
public_key: 'examplePublicKey',
733734
sample_rate: '1',
@@ -768,6 +769,7 @@ describe('browserTracingIntegration', () => {
768769
sampled: false,
769770
sampleRand: expect.any(Number),
770771
dsc: {
772+
release: undefined,
771773
environment: 'production',
772774
public_key: 'examplePublicKey',
773775
sample_rate: '0',
@@ -892,6 +894,7 @@ describe('browserTracingIntegration', () => {
892894

893895
expect(dynamicSamplingContext).toBeDefined();
894896
expect(dynamicSamplingContext).toStrictEqual({
897+
release: undefined,
895898
environment: 'production',
896899
public_key: 'examplePublicKey',
897900
sample_rate: '1',

packages/core/src/tracing/dynamicSamplingContext.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
baggageHeaderToDynamicSamplingContext,
99
dynamicSamplingContextToSentryBaggageHeader,
1010
} from '../utils-hoist/baggage';
11-
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
11+
import { addNonEnumerableProperty } from '../utils-hoist/object';
1212
import { hasSpansEnabled } from '../utils/hasSpansEnabled';
1313
import { getRootSpan, spanIsSampled, spanToJSON } from '../utils/spanUtils';
1414
import { getCapturedScopesOnSpan } from './utils';
@@ -41,12 +41,14 @@ export function getDynamicSamplingContextFromClient(trace_id: string, client: Cl
4141

4242
const { publicKey: public_key } = client.getDsn() || {};
4343

44-
const dsc = dropUndefinedKeys({
44+
// Instead of conditionally adding non-undefined values, we add them and then remove them if needed
45+
// otherwise, the order of baggage entries changes, which "breaks" a bunch of tests etc.
46+
const dsc: DynamicSamplingContext = {
4547
environment: options.environment || DEFAULT_ENVIRONMENT,
4648
release: options.release,
4749
public_key,
4850
trace_id,
49-
}) satisfies DynamicSamplingContext;
51+
};
5052

5153
client.emit('createDsc', dsc);
5254

packages/core/src/utils-hoist/anr.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { StackFrame } from '../types-hoist';
22
import { filenameIsInApp } from './node-stack-trace';
3-
import { dropUndefinedKeys } from './object';
43
import { UNKNOWN_FUNCTION } from './stacktrace';
54

65
type WatchdogReturn = {
@@ -81,12 +80,12 @@ export function callFrameToStackFrame(
8180
const colno = frame.location.columnNumber ? frame.location.columnNumber + 1 : undefined;
8281
const lineno = frame.location.lineNumber ? frame.location.lineNumber + 1 : undefined;
8382

84-
return dropUndefinedKeys({
83+
return {
8584
filename,
8685
module: getModuleFromFilename(filename),
8786
function: frame.functionName || UNKNOWN_FUNCTION,
8887
colno,
8988
lineno,
9089
in_app: filename ? filenameIsInApp(filename) : undefined,
91-
});
90+
};
9291
}

packages/core/src/utils-hoist/envelope.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import type {
1818

1919
import { dsnToString } from './dsn';
2020
import { normalize } from './normalize';
21-
import { dropUndefinedKeys } from './object';
2221
import { GLOBAL_OBJ } from './worldwide';
2322

2423
/**
@@ -196,13 +195,13 @@ export function createAttachmentEnvelopeItem(attachment: Attachment): Attachment
196195
const buffer = typeof attachment.data === 'string' ? encodeUTF8(attachment.data) : attachment.data;
197196

198197
return [
199-
dropUndefinedKeys({
198+
{
200199
type: 'attachment',
201200
length: buffer.length,
202201
filename: attachment.filename,
203202
content_type: attachment.contentType,
204203
attachment_type: attachment.attachmentType,
205-
}),
204+
},
206205
buffer,
207206
];
208207
}

packages/core/src/utils-hoist/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export { normalize, normalizeToSize, normalizeUrlToBase } from './normalize';
4545
export {
4646
addNonEnumerableProperty,
4747
convertToPlainObject,
48+
// eslint-disable-next-line deprecation/deprecation
4849
dropUndefinedKeys,
4950
extractExceptionKeysForMessage,
5051
fill,

packages/core/src/utils-hoist/object.ts

+2
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ export function extractExceptionKeysForMessage(exception: Record<string, unknown
210210
* Works recursively on objects and arrays.
211211
*
212212
* Attention: This function keeps circular references in the returned object.
213+
*
214+
* @deprecated This function is no longer used by the SDK and will be removed in a future major version.
213215
*/
214216
export function dropUndefinedKeys<T>(inputValue: T): T {
215217
// This map keeps track of what already visited nodes map to.

packages/core/src/utils/request.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { PolymorphicRequest, RequestEventData } from '../types-hoist';
22
import type { WebFetchHeaders, WebFetchRequest } from '../types-hoist/webfetchapi';
3-
import { dropUndefinedKeys } from '../utils-hoist/object';
43

54
/**
65
* Transforms a `Headers` object that implements the `Web Fetch API` (https://developer.mozilla.org/en-US/docs/Web/API/Headers) into a simple key-value dict.
@@ -91,14 +90,14 @@ export function httpRequestToRequestData(request: {
9190
// This is non-standard, but may be set on e.g. Next.js or Express requests
9291
const cookies = (request as PolymorphicRequest).cookies;
9392

94-
return dropUndefinedKeys({
93+
return {
9594
url: absoluteUrl,
9695
method: request.method,
9796
query_string: extractQueryParamsFromUrl(url),
9897
headers: headersToDict(headers),
9998
cookies,
10099
data,
101-
});
100+
};
102101
}
103102

104103
function getAbsoluteUrl({

packages/core/src/utils/spanUtils.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import type {
2121
} from '../types-hoist';
2222
import type { SpanLink, SpanLinkJSON } from '../types-hoist/link';
2323
import { consoleSandbox } from '../utils-hoist/logger';
24-
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
24+
import { addNonEnumerableProperty } from '../utils-hoist/object';
2525
import { generateSpanId } from '../utils-hoist/propagationContext';
2626
import { timestampInSeconds } from '../utils-hoist/time';
2727
import { generateSentryTraceHeader } from '../utils-hoist/tracing';
@@ -42,7 +42,7 @@ export function spanToTransactionTraceContext(span: Span): TraceContext {
4242
const { spanId: span_id, traceId: trace_id } = span.spanContext();
4343
const { data, op, parent_span_id, status, origin, links } = spanToJSON(span);
4444

45-
return dropUndefinedKeys({
45+
return {
4646
parent_span_id,
4747
span_id,
4848
trace_id,
@@ -51,7 +51,7 @@ export function spanToTransactionTraceContext(span: Span): TraceContext {
5151
status,
5252
origin,
5353
links,
54-
});
54+
};
5555
}
5656

5757
/**
@@ -67,11 +67,11 @@ export function spanToTraceContext(span: Span): TraceContext {
6767

6868
const span_id = isRemote ? scope?.getPropagationContext().propagationSpanId || generateSpanId() : spanId;
6969

70-
return dropUndefinedKeys({
70+
return {
7171
parent_span_id,
7272
span_id,
7373
trace_id,
74-
});
74+
};
7575
}
7676

7777
/**

packages/core/src/utils/transactionEvent.ts

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME, SEMANTIC_ATTRIBUTE_PROFILE_ID } from '../semanticAttributes';
22
import type { SpanJSON, TransactionEvent } from '../types-hoist';
3-
import { dropUndefinedKeys } from '../utils-hoist';
43

54
/**
65
* Converts a transaction event to a span JSON object.
76
*/
87
export function convertTransactionEventToSpanJson(event: TransactionEvent): SpanJSON {
98
const { trace_id, parent_span_id, span_id, status, origin, data, op } = event.contexts?.trace ?? {};
109

11-
return dropUndefinedKeys({
10+
return {
1211
data: data ?? {},
1312
description: event.transaction,
1413
op,
@@ -23,14 +22,14 @@ export function convertTransactionEventToSpanJson(event: TransactionEvent): Span
2322
exclusive_time: data?.[SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME] as number | undefined,
2423
measurements: event.measurements,
2524
is_segment: true,
26-
});
25+
};
2726
}
2827

2928
/**
3029
* Converts a span JSON object to a transaction event.
3130
*/
3231
export function convertSpanJsonToTransactionEvent(span: SpanJSON): TransactionEvent {
33-
const event: TransactionEvent = {
32+
return {
3433
type: 'transaction',
3534
timestamp: span.timestamp,
3635
start_timestamp: span.start_timestamp,
@@ -52,6 +51,4 @@ export function convertSpanJsonToTransactionEvent(span: SpanJSON): TransactionEv
5251
},
5352
measurements: span.measurements,
5453
};
55-
56-
return dropUndefinedKeys(event);
5754
}

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

+4
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ describe('getDynamicSamplingContextFromSpan', () => {
7070
const dynamicSamplingContext = getDynamicSamplingContextFromSpan(rootSpan);
7171

7272
expect(dynamicSamplingContext).toStrictEqual({
73+
public_key: undefined,
7374
release: '1.0.1',
7475
environment: 'production',
7576
sampled: 'true',
@@ -88,6 +89,7 @@ describe('getDynamicSamplingContextFromSpan', () => {
8889
const dynamicSamplingContext = getDynamicSamplingContextFromSpan(rootSpan);
8990

9091
expect(dynamicSamplingContext).toStrictEqual({
92+
public_key: undefined,
9193
release: '1.0.1',
9294
environment: 'production',
9395
sampled: 'true',
@@ -111,6 +113,7 @@ describe('getDynamicSamplingContextFromSpan', () => {
111113
const dynamicSamplingContext = getDynamicSamplingContextFromSpan(rootSpan);
112114

113115
expect(dynamicSamplingContext).toStrictEqual({
116+
public_key: undefined,
114117
release: '1.0.1',
115118
environment: 'production',
116119
sampled: 'true',
@@ -166,6 +169,7 @@ describe('getDynamicSamplingContextFromSpan', () => {
166169
const dynamicSamplingContext = getDynamicSamplingContextFromSpan(rootSpan);
167170

168171
expect(dynamicSamplingContext).toStrictEqual({
172+
public_key: undefined,
169173
release: '1.0.1',
170174
environment: 'production',
171175
trace_id: expect.stringMatching(/^[a-f0-9]{32}$/),

packages/core/test/utils-hoist/object.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ describe('extractExceptionKeysForMessage()', () => {
169169
});
170170
});
171171

172+
/* eslint-disable deprecation/deprecation */
172173
describe('dropUndefinedKeys()', () => {
173174
test('simple case', () => {
174175
expect(
@@ -314,6 +315,7 @@ describe('dropUndefinedKeys()', () => {
314315
expect(droppedChicken.lays[0] === droppedChicken).toBe(true);
315316
});
316317
});
318+
/* eslint-enable deprecation/deprecation */
317319

318320
describe('objectify()', () => {
319321
describe('stringifies nullish values', () => {

packages/nuxt/src/runtime/utils.ts

+14-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ClientOptions, Context } from '@sentry/core';
2-
import { captureException, dropUndefinedKeys, getClient, getTraceMetaTags } from '@sentry/core';
2+
import { captureException, getClient, getTraceMetaTags } from '@sentry/core';
33
import type { VueOptions } from '@sentry/vue/src/types';
44
import type { CapturedErrorContext } from 'nitropack';
55
import type { NuxtRenderHTMLContext } from 'nuxt/app';
@@ -9,25 +9,23 @@ import type { ComponentPublicInstance } from 'vue';
99
* Extracts the relevant context information from the error context (H3Event in Nitro Error)
1010
* and created a structured context object.
1111
*/
12-
export function extractErrorContext(errorContext: CapturedErrorContext): Context {
13-
const structuredContext: Context = {
14-
method: undefined,
15-
path: undefined,
16-
tags: undefined,
17-
};
12+
export function extractErrorContext(errorContext: CapturedErrorContext | undefined): Context {
13+
const ctx: Context = {};
1814

19-
if (errorContext) {
20-
if (errorContext.event) {
21-
structuredContext.method = errorContext.event._method || undefined;
22-
structuredContext.path = errorContext.event._path || undefined;
23-
}
15+
if (!errorContext) {
16+
return ctx;
17+
}
2418

25-
if (Array.isArray(errorContext.tags)) {
26-
structuredContext.tags = errorContext.tags || undefined;
27-
}
19+
if (errorContext.event) {
20+
ctx.method = errorContext.event._method;
21+
ctx.path = errorContext.event._path;
22+
}
23+
24+
if (Array.isArray(errorContext.tags)) {
25+
ctx.tags = errorContext.tags;
2826
}
2927

30-
return dropUndefinedKeys(structuredContext);
28+
return ctx;
3129
}
3230

3331
/**

packages/replay-internal/src/integration.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { BrowserClientReplayOptions, Client, Integration, IntegrationFn, ReplayRecordingMode } from '@sentry/core';
2-
import { consoleSandbox, dropUndefinedKeys, isBrowser, parseSampleRate } from '@sentry/core';
2+
import { consoleSandbox, isBrowser, parseSampleRate } from '@sentry/core';
33
import {
44
DEFAULT_FLUSH_MAX_DELAY,
55
DEFAULT_FLUSH_MIN_DELAY,
@@ -356,7 +356,7 @@ function loadReplayOptionsFromClient(initialOptions: InitialReplayPluginOptions,
356356
const finalOptions: ReplayPluginOptions = {
357357
sessionSampleRate: 0,
358358
errorSampleRate: 0,
359-
...dropUndefinedKeys(initialOptions),
359+
...initialOptions,
360360
};
361361

362362
const replaysSessionSampleRate = parseSampleRate(opt.replaysSessionSampleRate);

packages/sveltekit/src/vite/sentryVitePlugins.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { dropUndefinedKeys } from '@sentry/core';
21
import type { Plugin } from 'vite';
32
import type { AutoInstrumentSelection } from './autoInstrument';
43
import { makeAutoInstrumentationPlugin } from './autoInstrument';
@@ -104,5 +103,5 @@ export function generateVitePluginOptions(
104103
}
105104
}
106105

107-
return dropUndefinedKeys(sentryVitePluginsOptions);
106+
return sentryVitePluginsOptions;
108107
}

0 commit comments

Comments
 (0)