Skip to content

Commit 8d72477

Browse files
committed
fix(core): Ignore non-primitive values passed to setTag(s)
1 parent 3be2092 commit 8d72477

File tree

2 files changed

+60
-16
lines changed

2 files changed

+60
-16
lines changed

packages/core/src/scope.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import type { Span } from './types-hoist/span';
1717
import type { PropagationContext } from './types-hoist/tracing';
1818
import type { User } from './types-hoist/user';
1919
import { debug } from './utils/debug-logger';
20-
import { isPlainObject } from './utils/is';
20+
import { isPlainObject, isPrimitive } from './utils/is';
2121
import { merge } from './utils/merge';
2222
import { uuid4 } from './utils/misc';
2323
import { generateTraceId } from './utils/propagationContext';
@@ -279,10 +279,11 @@ export class Scope {
279279
* and will be sent as tags data with the event.
280280
*/
281281
public setTags(tags: { [key: string]: Primitive }): this {
282-
this._tags = {
283-
...this._tags,
284-
...tags,
285-
};
282+
for (const [key, value] of Object.entries(tags)) {
283+
if (isPrimitive(value)) {
284+
this._tags[key] = value;
285+
}
286+
}
286287
this._notifyScopeListeners();
287288
return this;
288289
}
@@ -291,9 +292,7 @@ export class Scope {
291292
* Set a single tag that will be sent as tags data with the event.
292293
*/
293294
public setTag(key: string, value: Primitive): this {
294-
this._tags = { ...this._tags, [key]: value };
295-
this._notifyScopeListeners();
296-
return this;
295+
return this.setTags({ [key]: value });
297296
}
298297

299298
/**

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

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,61 @@ describe('Scope', () => {
140140
expect(scope['_extra']).toEqual({ a: undefined });
141141
});
142142

143-
test('setTag', () => {
144-
const scope = new Scope();
145-
scope.setTag('a', 'b');
146-
expect(scope['_tags']).toEqual({ a: 'b' });
143+
describe('setTag', () => {
144+
it('sets a tag', () => {
145+
const scope = new Scope();
146+
scope.setTag('a', 'b');
147+
expect(scope['_tags']).toEqual({ a: 'b' });
148+
});
149+
150+
it('sets a tag with undefined', () => {
151+
const scope = new Scope();
152+
scope.setTag('a', 'b');
153+
scope.setTag('a', undefined);
154+
expect(scope['_tags']).toEqual({ a: undefined });
155+
});
156+
157+
it('notifies scope listeners once per call', () => {
158+
const scope = new Scope();
159+
const listener = vi.fn();
160+
161+
scope.addScopeListener(listener);
162+
scope.setTag('a', 'b');
163+
scope.setTag('a', 'c');
164+
165+
expect(listener).toHaveBeenCalledTimes(2);
166+
});
167+
168+
it('discards non-primitive values', () => {
169+
const scope = new Scope();
170+
// @ts-expect-error we want to test with a non-primitive value despite types not allowing it
171+
scope.setTag('a', { b: 'c' });
172+
expect(scope['_tags']).toEqual({});
173+
});
147174
});
148175

149-
test('setTags', () => {
150-
const scope = new Scope();
151-
scope.setTags({ a: 'b' });
152-
expect(scope['_tags']).toEqual({ a: 'b' });
176+
describe('setTags', () => {
177+
it('sets tags', () => {
178+
const scope = new Scope();
179+
scope.setTags({ a: 'b' });
180+
expect(scope['_tags']).toEqual({ a: 'b' });
181+
});
182+
183+
it('notifies scope listeners once per call', () => {
184+
const scope = new Scope();
185+
const listener = vi.fn();
186+
scope.addScopeListener(listener);
187+
scope.setTags({ a: 'b', c: 'd' });
188+
scope.setTags({ a: 'e', f: 'g' });
189+
expect(listener).toHaveBeenCalledTimes(2);
190+
});
191+
192+
it('discards non-primitive values', () => {
193+
const scope = new Scope();
194+
// @ts-expect-error we want to test with a non-primitive value despite types not allowing it
195+
scope.setTags({ a: { b: 'c' }, b: [1, 2, 3], c: new Map(), d: () => {} });
196+
expect(scope['_tags']).toEqual({});
197+
});
153198
});
154199

155200
test('setUser', () => {

0 commit comments

Comments
 (0)