Skip to content

Commit ee5395b

Browse files
committed
use generic merge instead
1 parent 4705e11 commit ee5395b

File tree

10 files changed

+99
-185
lines changed

10 files changed

+99
-185
lines changed

packages/core/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ export { hasTracingEnabled } from './utils/hasTracingEnabled';
6868
export { isSentryRequestUrl } from './utils/isSentryRequestUrl';
6969
export { handleCallbackErrors } from './utils/handleCallbackErrors';
7070
export { parameterize } from './utils/parameterize';
71-
export { setRequestEventData } from './utils/sdkProcessingMetadata';
7271
export {
7372
spanToTraceHeader,
7473
spanToJSON,

packages/core/src/scope.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import type {
2424
import { dateTimestampInSeconds, generatePropagationContext, isPlainObject, logger, uuid4 } from '@sentry/utils';
2525

2626
import { updateSession } from './session';
27+
import { merge } from './utils/merge';
2728
import { _getSpanForScope, _setSpanForScope } from './utils/spanOnScope';
2829

2930
/**
@@ -479,7 +480,7 @@ class ScopeClass implements ScopeInterface {
479480
* @inheritDoc
480481
*/
481482
public setSDKProcessingMetadata(newData: { [key: string]: unknown }): this {
482-
this._sdkProcessingMetadata = { ...this._sdkProcessingMetadata, ...newData };
483+
this._sdkProcessingMetadata = merge(this._sdkProcessingMetadata, newData, 2);
483484
return this;
484485
}
485486

packages/core/src/utils/applyScopeDataToEvent.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Breadcrumb, Event, ScopeData, Span } from '@sentry/types';
22
import { arrayify, dropUndefinedKeys } from '@sentry/utils';
33
import { getDynamicSamplingContextFromSpan } from '../tracing/dynamicSamplingContext';
4-
import { mergeSdkProcessingMetadata } from './sdkProcessingMetadata';
4+
import { merge } from './merge';
55
import { getRootSpan, spanToJSON, spanToTraceContext } from './spanUtils';
66

77
/**
@@ -48,7 +48,7 @@ export function mergeScopeData(data: ScopeData, mergeData: ScopeData): void {
4848
mergeAndOverwriteScopeData(data, 'user', user);
4949
mergeAndOverwriteScopeData(data, 'contexts', contexts);
5050

51-
data.sdkProcessingMetadata = mergeSdkProcessingMetadata(data.sdkProcessingMetadata, sdkProcessingMetadata);
51+
data.sdkProcessingMetadata = merge(data.sdkProcessingMetadata, sdkProcessingMetadata, 2);
5252

5353
if (level) {
5454
data.level = level;
@@ -89,15 +89,7 @@ export function mergeAndOverwriteScopeData<
8989
Prop extends 'extra' | 'tags' | 'user' | 'contexts' | 'sdkProcessingMetadata',
9090
Data extends ScopeData,
9191
>(data: Data, prop: Prop, mergeVal: Data[Prop]): void {
92-
if (mergeVal && Object.keys(mergeVal).length) {
93-
// Clone object
94-
data[prop] = { ...data[prop] };
95-
for (const key in mergeVal) {
96-
if (Object.prototype.hasOwnProperty.call(mergeVal, key)) {
97-
data[prop][key] = mergeVal[key];
98-
}
99-
}
100-
}
92+
data[prop] = merge(data[prop], mergeVal, 1);
10193
}
10294

10395
/** Exported only for tests */

packages/core/src/utils/merge.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Shallow merge two objects.
3+
* Does not mutate the passed in objects.
4+
* By default, this merges 2 levels deep.
5+
*/
6+
export function merge<T>(initialObj: T, mergeObj: T, levels = 2): T {
7+
// If the merge value is not an object, or we have no merge levels left,
8+
// we just set the value to the merge value
9+
if (typeof mergeObj !== 'object' || levels <= 0) {
10+
return mergeObj;
11+
}
12+
13+
// If the merge object is an empty object, and the initial object is not undefined, we return the initial object
14+
if (initialObj && mergeObj && Object.keys(mergeObj).length === 0) {
15+
return initialObj;
16+
}
17+
18+
// Clone object
19+
const output = { ...initialObj };
20+
21+
// Merge values into output, resursively
22+
for (const key in mergeObj) {
23+
if (Object.prototype.hasOwnProperty.call(mergeObj, key)) {
24+
output[key] = merge(output[key], mergeObj[key], levels - 1);
25+
}
26+
}
27+
28+
return output;
29+
}

packages/core/src/utils/sdkProcessingMetadata.ts

Lines changed: 0 additions & 47 deletions
This file was deleted.

packages/core/test/lib/scope.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,13 @@ describe('Scope', () => {
216216
scope.setSDKProcessingMetadata({ dogs: 'are great!' });
217217
scope.setSDKProcessingMetadata({ dogs: 'are really great!' });
218218
scope.setSDKProcessingMetadata({ cats: 'are also great!' });
219-
scope.setSDKProcessingMetadata({ obj: { nested: 'value1' } });
220-
scope.setSDKProcessingMetadata({ obj: { nested2: 'value2' } });
219+
scope.setSDKProcessingMetadata({ obj: { nested1: 'value1', nested: 'value1' } });
220+
scope.setSDKProcessingMetadata({ obj: { nested2: 'value2', nested: 'value2' } });
221221

222222
expect(scope['_sdkProcessingMetadata']).toEqual({
223223
dogs: 'are really great!',
224224
cats: 'are also great!',
225-
obj: { nested2: 'value2' },
225+
obj: { nested2: 'value2', nested: 'value2', nested1: 'value1' },
226226
});
227227
});
228228
});

packages/core/test/lib/utils/applyScopeDataToEvent.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,7 @@ describe('mergeScopeData', () => {
157157
sdkProcessingMetadata: {
158158
bb: 'bb',
159159
cc: 'bb',
160-
// Regular objects are not deep merged
161160
obj: { key2: 'value2' },
162-
// Only normalizedRequest is deep merged
163161
normalizedRequest: {
164162
url: 'newUrl',
165163
headers: {},
@@ -181,7 +179,7 @@ describe('mergeScopeData', () => {
181179
aa: 'aa',
182180
bb: 'bb',
183181
cc: 'bb',
184-
obj: { key2: 'value2' },
182+
obj: { key: 'value', key2: 'value2' },
185183
normalizedRequest: {
186184
url: 'newUrl',
187185
method: 'oldMethod',
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { merge } from '../../../src/utils/merge';
2+
3+
describe('merge', () => {
4+
it('works with empty objects', () => {
5+
const oldData = {};
6+
const newData = {};
7+
8+
const actual = merge(oldData, newData);
9+
10+
expect(actual).toEqual({});
11+
expect(actual).toBe(oldData);
12+
expect(actual).not.toBe(newData);
13+
});
14+
15+
it('works with empty merge object', () => {
16+
const oldData = { aa: 'aha' };
17+
const newData = {};
18+
19+
const actual = merge(oldData, newData);
20+
21+
expect(actual).toEqual({ aa: 'aha' });
22+
expect(actual).toBe(oldData);
23+
expect(actual).not.toBe(newData);
24+
});
25+
26+
it('works with arbitrary data', () => {
27+
const oldData = {
28+
old1: 'old1',
29+
old2: 'old2',
30+
obj: { key: 'value1', key1: 'value1', deep: { key: 'value' } },
31+
} as any;
32+
const newData = {
33+
new1: 'new1',
34+
old2: 'new2',
35+
obj: { key2: 'value2', key: 'value2', deep: { key2: 'value2' } },
36+
} as any;
37+
38+
const actual = merge(oldData, newData);
39+
40+
expect(actual).toEqual({
41+
old1: 'old1',
42+
old2: 'new2',
43+
new1: 'new1',
44+
obj: {
45+
key2: 'value2',
46+
key: 'value2',
47+
key1: 'value1',
48+
deep: { key2: 'value2' },
49+
},
50+
});
51+
expect(actual).not.toBe(oldData);
52+
expect(actual).not.toBe(newData);
53+
});
54+
});

packages/core/test/lib/utils/sdkProcessingMetadata.test.ts

Lines changed: 0 additions & 115 deletions
This file was deleted.

packages/node/src/integrations/http/SentryHttpInstrumentation.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { VERSION } from '@opentelemetry/core';
55
import type { InstrumentationConfig } from '@opentelemetry/instrumentation';
66
import { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
77
import { getRequestInfo } from '@opentelemetry/instrumentation-http';
8-
import { addBreadcrumb, getClient, getIsolationScope, setRequestEventData, withIsolationScope } from '@sentry/core';
8+
import { addBreadcrumb, getClient, getIsolationScope, withIsolationScope } from '@sentry/core';
99
import type { PolymorphicRequest, RequestEventData, SanitizedRequestData, Scope } from '@sentry/types';
1010
import {
1111
getBreadcrumbLogLevelFromHttpStatusCode,
@@ -154,8 +154,10 @@ export class SentryHttpInstrumentation extends InstrumentationBase<SentryHttpIns
154154

155155
// Update the isolation scope, isolate this request
156156
// TODO(v9): Stop setting `request`, we only rely on normalizedRequest anymore
157-
isolationScope.setSDKProcessingMetadata({ request });
158-
setRequestEventData(normalizedRequest, isolationScope);
157+
isolationScope.setSDKProcessingMetadata({
158+
request,
159+
normalizedRequest,
160+
});
159161

160162
const client = getClient<NodeClient>();
161163
if (client && client.getOptions().autoSessionTracking) {
@@ -399,7 +401,8 @@ function patchRequestToCaptureBody(req: IncomingMessage, isolationScope: Scope):
399401
const body = Buffer.concat(chunks).toString('utf-8');
400402

401403
if (body) {
402-
setRequestEventData({ data: body }, isolationScope);
404+
const normalizedRequest = { data: body } satisfies RequestEventData;
405+
isolationScope.setSDKProcessingMetadata({ normalizedRequest });
403406
}
404407
} catch {
405408
// ignore errors here

0 commit comments

Comments
 (0)