diff --git a/packages/core/src/utils/featureFlags.ts b/packages/core/src/utils/featureFlags.ts index 4fa3cdc5ac8d..c7551c379d3c 100644 --- a/packages/core/src/utils/featureFlags.ts +++ b/packages/core/src/utils/featureFlags.ts @@ -28,6 +28,12 @@ const SPAN_FLAG_ATTRIBUTE_PREFIX = 'flag.evaluation.'; * Copies feature flags that are in current scope context to the event context */ export function _INTERNAL_copyFlagsFromScopeToEvent(event: Event): Event { + if (event.type) { + // No need to add the flags context to transaction events. + // Spans already get the flag.evaluation attributes. + return event; + } + const scope = getCurrentScope(); const flagContext = scope.getScopeData().contexts.flags; const flagBuffer = flagContext ? flagContext.values : []; diff --git a/packages/core/test/lib/utils/featureFlags.test.ts b/packages/core/test/lib/utils/featureFlags.test.ts index 7813452ad419..534285b4f9f4 100644 --- a/packages/core/test/lib/utils/featureFlags.test.ts +++ b/packages/core/test/lib/utils/featureFlags.test.ts @@ -2,11 +2,15 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { getCurrentScope } from '../../../src/currentScopes'; import { debug } from '../../../src/utils/debug-logger'; import { + _INTERNAL_copyFlagsFromScopeToEvent, _INTERNAL_insertFlagToScope, _INTERNAL_insertToFlagBuffer, type FeatureFlag, } from '../../../src/utils/featureFlags'; +import * as currentScopeModule from '../../../src/currentScopes'; +import type { Event } from '../../../src/types-hoist/event'; + describe('flags', () => { describe('insertFlagToScope()', () => { it('adds flags to the current scope context', () => { @@ -109,4 +113,82 @@ describe('flags', () => { ]); }); }); + + describe('copyFlagsFromScopeToEvent()', () => { + it.each(['transaction', 'replay_event', 'feedback', 'profile'])('does not add flags context to %s events', type => { + vi.spyOn(currentScopeModule, 'getCurrentScope').mockReturnValue({ + // @ts-expect-error - only returning partial scope data + getScopeData: () => ({ + contexts: { + flags: { values: [{ flag: 'feat1', result: true }] }, + }, + }), + }); + + const event = { + type: type, + spans: [], + } as Event; + + const result = _INTERNAL_copyFlagsFromScopeToEvent(event); + + expect(result).toEqual(event); + expect(getCurrentScope).not.toHaveBeenCalled(); + }); + + it('adds add flags context to error events', () => { + vi.spyOn(currentScopeModule, 'getCurrentScope').mockReturnValue({ + // @ts-expect-error - only returning partial scope data + getScopeData: () => ({ + contexts: { + flags: { + values: [ + { flag: 'feat1', result: true }, + { flag: 'feat2', result: false }, + ], + }, + }, + }), + }); + + const event: Event = { + exception: { + values: [ + { + type: 'Error', + value: 'error message', + }, + ], + }, + }; + + const result = _INTERNAL_copyFlagsFromScopeToEvent(event); + + expect(result).toEqual({ + contexts: { + flags: { + values: [ + { + flag: 'feat1', + result: true, + }, + { + flag: 'feat2', + result: false, + }, + ], + }, + }, + exception: { + values: [ + { + type: 'Error', + value: 'error message', + }, + ], + }, + }); + expect(getCurrentScope).toHaveBeenCalled(); + }); + }); });