diff --git a/packages/rum-core/src/boot/preStartRum.spec.ts b/packages/rum-core/src/boot/preStartRum.spec.ts index 89e3e14397..07fe7e4e2f 100644 --- a/packages/rum-core/src/boot/preStartRum.spec.ts +++ b/packages/rum-core/src/boot/preStartRum.spec.ts @@ -489,6 +489,7 @@ describe('preStartRum', () => { strategy.addError(error) strategy.init(DEFAULT_INIT_CONFIGURATION) expect(addErrorSpy).toHaveBeenCalledOnceWith(error, undefined) + // todo: test with handlingStack }) it('startView', () => { diff --git a/packages/rum-core/src/boot/rumPublicApi.spec.ts b/packages/rum-core/src/boot/rumPublicApi.spec.ts index 576cb07175..bd1f80eae6 100644 --- a/packages/rum-core/src/boot/rumPublicApi.spec.ts +++ b/packages/rum-core/src/boot/rumPublicApi.spec.ts @@ -183,11 +183,26 @@ describe('rum public api', () => { name: 'foo', startClocks: jasmine.any(Object), type: ActionType.CUSTOM, + handlingStack: jasmine.any(String), }, { context: {}, user: {}, hasReplay: undefined }, ]) }) + it('should generate a handling stack', () => { + rumPublicApi.init(DEFAULT_INIT_CONFIGURATION) + + function triggerAction() { + rumPublicApi.addAction('foo', { bar: 'baz' }) + } + + triggerAction() + + expect(addActionSpy).toHaveBeenCalledTimes(1) + const stacktrace = addActionSpy.calls.argsFor(0)[0].handlingStack + expect(stacktrace).toMatch(/^Error:\s+at triggerAction @/) + }) + describe('save context when sending an action', () => { it('saves the date', () => { const { clock } = setupBuilder.withFakeClock().build() diff --git a/packages/rum-core/src/boot/rumPublicApi.ts b/packages/rum-core/src/boot/rumPublicApi.ts index 1846db4108..bfa3574616 100644 --- a/packages/rum-core/src/boot/rumPublicApi.ts +++ b/packages/rum-core/src/boot/rumPublicApi.ts @@ -224,14 +224,19 @@ export function makeRumPublicApi(startRumImpl: StartRum, recorderApi: RecorderAp getInitConfiguration: monitor(() => deepClone(strategy.initConfiguration)), - addAction: monitor((name: string, context?: object) => { - strategy.addAction({ - name: sanitize(name)!, - context: sanitize(context) as Context, - startClocks: clocksNow(), - type: ActionType.CUSTOM, - }) - }), + addAction: (name: string, context?: object) => { + const handlingStack = createHandlingStack(2) + + callMonitored(() => + strategy.addAction({ + name: sanitize(name)!, + context: sanitize(context) as Context, + startClocks: clocksNow(), + type: ActionType.CUSTOM, + handlingStack, + }) + ) + }, addError: (error: unknown, context?: object) => { const handlingStack = createHandlingStack(2) diff --git a/packages/rum-core/src/domain/action/actionCollection.ts b/packages/rum-core/src/domain/action/actionCollection.ts index 4233455daf..a64cea738a 100644 --- a/packages/rum-core/src/domain/action/actionCollection.ts +++ b/packages/rum-core/src/domain/action/actionCollection.ts @@ -1,5 +1,13 @@ import type { ClocksState, Context, Observable } from '@datadog/browser-core' -import { noop, assign, combine, toServerDuration, generateUUID } from '@datadog/browser-core' +import { + noop, + assign, + combine, + toServerDuration, + generateUUID, + isExperimentalFeatureEnabled, + ExperimentalFeature, +} from '@datadog/browser-core' import type { RawRumActionEvent } from '../../rawRumEvent.types' import { ActionType, RumEventType } from '../../rawRumEvent.types' @@ -9,6 +17,7 @@ import type { RumConfiguration } from '../configuration' import type { CommonContext } from '../contexts/commonContext' import type { PageStateHistory } from '../contexts/pageStateHistory' import { PageState } from '../contexts/pageStateHistory' +import type { RumActionEventDomainContext } from '../../domainContext.types' import type { ActionContexts, ClickAction } from './trackClickActions' import { trackClickActions } from './trackClickActions' @@ -19,6 +28,7 @@ export interface CustomAction { name: string startClocks: ClocksState context?: Context + handlingStack?: string } export type AutoAction = ClickAction @@ -101,11 +111,21 @@ function processAction( autoActionProperties ) + const domainContext: RumActionEventDomainContext = isAutoAction(action) ? { events: action.events } : {} + + if ( + !isAutoAction(action) && + action.handlingStack && + isExperimentalFeatureEnabled(ExperimentalFeature.MICRO_FRONTEND) + ) { + domainContext.handlingStack = action.handlingStack + } + return { customerContext, rawRumEvent: actionEvent, startTime: action.startClocks.relative, - domainContext: isAutoAction(action) ? { events: action.events } : {}, + domainContext, } } diff --git a/packages/rum-core/src/domain/error/errorCollection.ts b/packages/rum-core/src/domain/error/errorCollection.ts index e0c83733c5..8207cf0a2f 100644 --- a/packages/rum-core/src/domain/error/errorCollection.ts +++ b/packages/rum-core/src/domain/error/errorCollection.ts @@ -10,6 +10,8 @@ import { Observable, trackRuntimeError, NonErrorPrefix, + isExperimentalFeatureEnabled, + ExperimentalFeature, } from '@datadog/browser-core' import type { RumConfiguration } from '../configuration' import type { RawRumErrorEvent } from '../../rawRumEvent.types' @@ -20,6 +22,7 @@ import type { FeatureFlagContexts } from '../contexts/featureFlagContext' import type { CommonContext } from '../contexts/commonContext' import type { PageStateHistory } from '../contexts/pageStateHistory' import { PageState } from '../contexts/pageStateHistory' +import type { RumErrorEventDomainContext } from '../../domainContext.types' import { trackConsoleError } from './trackConsoleError' import { trackReportError } from './trackReportError' @@ -119,11 +122,17 @@ function processError( rawRumEvent.feature_flags = featureFlagContext } + const domainContext: RumErrorEventDomainContext = { + error: error.originalError, + } + + if (isExperimentalFeatureEnabled(ExperimentalFeature.MICRO_FRONTEND)) { + domainContext.handlingStack = error.handlingStack + } + return { rawRumEvent, startTime: error.startClocks.relative, - domainContext: { - error: error.originalError, - }, + domainContext, } } diff --git a/packages/rum-core/src/domainContext.types.ts b/packages/rum-core/src/domainContext.types.ts index be9f1aee56..d403e0db51 100644 --- a/packages/rum-core/src/domainContext.types.ts +++ b/packages/rum-core/src/domainContext.types.ts @@ -24,6 +24,7 @@ export interface RumViewEventDomainContext { export interface RumActionEventDomainContext { events?: Event[] + handlingStack?: string } export interface RumFetchResourceEventDomainContext { @@ -49,6 +50,7 @@ export interface RumOtherResourceEventDomainContext { export interface RumErrorEventDomainContext { error: unknown + handlingStack?: string } export interface RumLongTaskEventDomainContext {