From 903cd87740a22e399990b0e2db27152dedf60892 Mon Sep 17 00:00:00 2001 From: "beltran.bulbarella" Date: Wed, 27 May 2026 11:57:10 +0200 Subject: [PATCH 1/2] Remove start stop action experiment flag, add telemetry usage log --- .../core/src/tools/experimentalFeatures.ts | 2 - .../rum-core/src/boot/preStartRum.spec.ts | 4 -- .../rum-core/src/boot/rumPublicApi.spec.ts | 46 ------------------- packages/rum-core/src/boot/rumPublicApi.ts | 24 ++-------- .../domain/action/trackManualActions.spec.ts | 3 +- test/e2e/scenario/rum/actions.scenario.ts | 14 +++--- test/e2e/scenario/rum/resources.scenario.ts | 10 ++-- 7 files changed, 17 insertions(+), 86 deletions(-) diff --git a/packages/core/src/tools/experimentalFeatures.ts b/packages/core/src/tools/experimentalFeatures.ts index 568e1a4004..1fc658d946 100644 --- a/packages/core/src/tools/experimentalFeatures.ts +++ b/packages/core/src/tools/experimentalFeatures.ts @@ -16,8 +16,6 @@ import { objectHasValue } from './utils/objectUtils' export enum ExperimentalFeature { TRACK_INTAKE_REQUESTS = 'track_intake_requests', FEATURE_OPERATION_VITAL = 'feature_operation_vital', - START_STOP_ACTION = 'start_stop_action', - START_STOP_RESOURCE = 'start_stop_resource', TOO_MANY_REQUESTS_INVESTIGATION = 'too_many_requests_investigation', SESSION_RENEWAL_DEBUG_CONTEXT = 'session_renewal_debug_context', } diff --git a/packages/rum-core/src/boot/preStartRum.spec.ts b/packages/rum-core/src/boot/preStartRum.spec.ts index 27171983bc..f7df5a25d1 100644 --- a/packages/rum-core/src/boot/preStartRum.spec.ts +++ b/packages/rum-core/src/boot/preStartRum.spec.ts @@ -11,9 +11,7 @@ import { TrackingConsent, createTrackingConsentState, DefaultPrivacyLevel, - ExperimentalFeature, startTelemetry, - addExperimentalFeatures, startSessionManager, } from '@datadog/browser-core' import type { Clock } from '@datadog/browser-core/test' @@ -918,8 +916,6 @@ describe('preStartRum', () => { }) it('startAction / stopAction', async () => { - addExperimentalFeatures([ExperimentalFeature.START_STOP_ACTION]) - const startActionSpy = jasmine.createSpy() const stopActionSpy = jasmine.createSpy() doStartRumSpy.and.returnValue({ diff --git a/packages/rum-core/src/boot/rumPublicApi.spec.ts b/packages/rum-core/src/boot/rumPublicApi.spec.ts index 8ef51ad65c..a6db1e5416 100644 --- a/packages/rum-core/src/boot/rumPublicApi.spec.ts +++ b/packages/rum-core/src/boot/rumPublicApi.spec.ts @@ -4,10 +4,8 @@ import { display, DefaultPrivacyLevel, timeStampToClocks, - ExperimentalFeature, ResourceType, startTelemetry, - addExperimentalFeatures, startSessionManager, getTimeStamp, } from '@datadog/browser-core' @@ -852,7 +850,6 @@ describe('rum public api', () => { describe('startAction / stopAction', () => { it('should call startAction and stopAction on the strategy', async () => { const clock = mockClock() - addExperimentalFeatures([ExperimentalFeature.START_STOP_ACTION]) const startActionSpy = jasmine.createSpy('startAction') const stopActionSpy = jasmine.createSpy('stopAction') @@ -894,8 +891,6 @@ describe('rum public api', () => { }) it('should sanitize startAction and stopAction inputs', async () => { - addExperimentalFeatures([ExperimentalFeature.START_STOP_ACTION]) - const startActionSpy = jasmine.createSpy() const { rumPublicApi } = makeRumPublicApiWithDefaults({ startRumResult: { @@ -920,31 +915,11 @@ describe('rum public api', () => { }) ) }) - - it('should not call startAction/stopAction when feature flag is disabled', async () => { - const startActionSpy = jasmine.createSpy() - const stopActionSpy = jasmine.createSpy() - const { rumPublicApi, startRumSpy } = makeRumPublicApiWithDefaults({ - startRumResult: { - startAction: startActionSpy, - stopAction: stopActionSpy, - }, - }) - - rumPublicApi.init(DEFAULT_INIT_CONFIGURATION) - rumPublicApi.startAction('purchase', { type: ActionType.CUSTOM }) - rumPublicApi.stopAction('purchase') - await collectAsyncCalls(startRumSpy, 1) - - expect(startActionSpy).not.toHaveBeenCalled() - expect(stopActionSpy).not.toHaveBeenCalled() - }) }) describe('startResource / stopResource', () => { it('should call startResource and stopResource on the strategy', async () => { const clock = mockClock() - addExperimentalFeatures([ExperimentalFeature.START_STOP_RESOURCE]) const startResourceSpy = jasmine.createSpy('startResource') const stopResourceSpy = jasmine.createSpy('stopResource') @@ -993,8 +968,6 @@ describe('rum public api', () => { }) it('should sanitize startResource and stopResource inputs', async () => { - addExperimentalFeatures([ExperimentalFeature.START_STOP_RESOURCE]) - const startResourceSpy = jasmine.createSpy() const { rumPublicApi } = makeRumPublicApiWithDefaults({ startRumResult: { @@ -1020,25 +993,6 @@ describe('rum public api', () => { }) ) }) - - it('should not call startResource/stopResource when feature flag is disabled', async () => { - const startResourceSpy = jasmine.createSpy() - const stopResourceSpy = jasmine.createSpy() - const { rumPublicApi, startRumSpy } = makeRumPublicApiWithDefaults({ - startRumResult: { - startResource: startResourceSpy, - stopResource: stopResourceSpy, - }, - }) - - rumPublicApi.init(DEFAULT_INIT_CONFIGURATION) - rumPublicApi.startResource('https://api.example.com/data', { type: ResourceType.FETCH }) - rumPublicApi.stopResource('https://api.example.com/data') - await collectAsyncCalls(startRumSpy, 1) - - expect(startResourceSpy).not.toHaveBeenCalled() - expect(stopResourceSpy).not.toHaveBeenCalled() - }) }) describe('addDurationVital', () => { diff --git a/packages/rum-core/src/boot/rumPublicApi.ts b/packages/rum-core/src/boot/rumPublicApi.ts index f8c7a8f47c..861715555d 100644 --- a/packages/rum-core/src/boot/rumPublicApi.ts +++ b/packages/rum-core/src/boot/rumPublicApi.ts @@ -34,8 +34,6 @@ import { CustomerContextKey, defineContextMethod, startBufferingData, - isExperimentalFeatureEnabled, - ExperimentalFeature, mockable, generateUUID, timeStampNow, @@ -727,11 +725,7 @@ export function makeRumPublicApi( }, startAction: monitor((name, options) => { - // Check feature flag only after init; pre-init calls should be buffered - if (strategy.initConfiguration && !isExperimentalFeatureEnabled(ExperimentalFeature.START_STOP_ACTION)) { - return - } - // addTelemetryUsage({ feature: 'start-action' }) + addTelemetryUsage({ feature: 'start-action' }) strategy.startAction(sanitize(name)!, { type: sanitize(options && options.type) as ActionType | undefined, context: sanitize(options && options.context) as Context, @@ -740,10 +734,7 @@ export function makeRumPublicApi( }), stopAction: monitor((name, options) => { - if (strategy.initConfiguration && !isExperimentalFeatureEnabled(ExperimentalFeature.START_STOP_ACTION)) { - return - } - // addTelemetryUsage({ feature: 'stop-action' }) + addTelemetryUsage({ feature: 'stop-action' }) strategy.stopAction(sanitize(name)!, { type: sanitize(options && options.type) as ActionType | undefined, context: sanitize(options && options.context) as Context, @@ -752,11 +743,7 @@ export function makeRumPublicApi( }), startResource: monitor((url, options) => { - // Check feature flag only after init; pre-init calls should be buffered - if (strategy.initConfiguration && !isExperimentalFeatureEnabled(ExperimentalFeature.START_STOP_RESOURCE)) { - return - } - // addTelemetryUsage({ feature: 'start-resource' }) + addTelemetryUsage({ feature: 'start-resource' }) strategy.startResource(sanitize(url)!, { type: sanitize(options && options.type) as ResourceType | undefined, method: sanitize(options && options.method) as string | undefined, @@ -766,10 +753,7 @@ export function makeRumPublicApi( }), stopResource: monitor((url, options) => { - if (strategy.initConfiguration && !isExperimentalFeatureEnabled(ExperimentalFeature.START_STOP_RESOURCE)) { - return - } - // addTelemetryUsage({ feature: 'stop-resource' }) + addTelemetryUsage({ feature: 'stop-resource' }) strategy.stopResource(sanitize(url)!, { type: sanitize(options && options.type) as ResourceType | undefined, statusCode: options && options.statusCode, diff --git a/packages/rum-core/src/domain/action/trackManualActions.spec.ts b/packages/rum-core/src/domain/action/trackManualActions.spec.ts index bf69126453..539ffa949a 100644 --- a/packages/rum-core/src/domain/action/trackManualActions.spec.ts +++ b/packages/rum-core/src/domain/action/trackManualActions.spec.ts @@ -1,5 +1,5 @@ import type { Duration, ServerDuration } from '@datadog/browser-core' -import { addExperimentalFeatures, ExperimentalFeature, Observable } from '@datadog/browser-core' +import { Observable } from '@datadog/browser-core' import type { Clock } from '@datadog/browser-core/test' import { mockClock, registerCleanupTask } from '@datadog/browser-core/test' import { collectAndValidateRawRumEvents, mockRumConfiguration } from '../../../test' @@ -21,7 +21,6 @@ describe('trackManualActions', () => { beforeEach(() => { clock = mockClock() - addExperimentalFeatures([ExperimentalFeature.START_STOP_ACTION]) const domMutationObservable = new Observable() const windowOpenObservable = new Observable() diff --git a/test/e2e/scenario/rum/actions.scenario.ts b/test/e2e/scenario/rum/actions.scenario.ts index c26b752519..7a70e7e8fa 100644 --- a/test/e2e/scenario/rum/actions.scenario.ts +++ b/test/e2e/scenario/rum/actions.scenario.ts @@ -607,7 +607,7 @@ test.describe('action collection with shadow DOM', () => { test.describe('custom actions with startAction/stopAction', () => { createTest('track a custom action with startAction/stopAction') - .withRum({ enableExperimentalFeatures: ['start_stop_action'] }) + .withRum() .run(async ({ intakeRegistry, flushEvents, page }) => { await page.evaluate(() => { window.DD_RUM!.startAction('checkout') @@ -623,7 +623,7 @@ test.describe('custom actions with startAction/stopAction', () => { }) createTest('associate an error to a custom action') - .withRum({ enableExperimentalFeatures: ['start_stop_action'] }) + .withRum() .run(async ({ intakeRegistry, flushEvents, page }) => { await page.evaluate(() => { window.DD_RUM!.startAction('checkout') @@ -646,7 +646,7 @@ test.describe('custom actions with startAction/stopAction', () => { }) createTest('associate a resource to a custom action') - .withRum({ enableExperimentalFeatures: ['start_stop_action'] }) + .withRum() .run(async ({ intakeRegistry, flushEvents, page }) => { await page.evaluate(() => { window.DD_RUM!.startAction('load-data') @@ -671,7 +671,7 @@ test.describe('custom actions with startAction/stopAction', () => { }) createTest('track multiple concurrent custom actions with actionKey') - .withRum({ enableExperimentalFeatures: ['start_stop_action'] }) + .withRum() .run(async ({ intakeRegistry, flushEvents, page }) => { await page.evaluate(() => { window.DD_RUM!.startAction('click', { actionKey: 'button1' }) @@ -687,7 +687,7 @@ test.describe('custom actions with startAction/stopAction', () => { }) createTest('merge contexts from start and stop') - .withRum({ enableExperimentalFeatures: ['start_stop_action'] }) + .withRum() .run(async ({ intakeRegistry, flushEvents, page }) => { await page.evaluate(() => { window.DD_RUM!.startAction('purchase', { context: { cart_id: 'abc123' } }) @@ -706,7 +706,7 @@ test.describe('custom actions with startAction/stopAction', () => { }) createTest('preserve timing when startAction is called before init') - .withRum({ enableExperimentalFeatures: ['start_stop_action'] }) + .withRum() .withRumInit((configuration) => { window.DD_RUM!.startAction('pre_init_action') @@ -725,7 +725,7 @@ test.describe('custom actions with startAction/stopAction', () => { }) createTest('attribute errors and resources to action started before init') - .withRum({ enableExperimentalFeatures: ['start_stop_action'] }) + .withRum() .withRumInit((configuration) => { window.DD_RUM!.startAction('pre_init_action') diff --git a/test/e2e/scenario/rum/resources.scenario.ts b/test/e2e/scenario/rum/resources.scenario.ts index 40beb4ffbc..a4837560c8 100644 --- a/test/e2e/scenario/rum/resources.scenario.ts +++ b/test/e2e/scenario/rum/resources.scenario.ts @@ -506,7 +506,7 @@ test.describe('resource headers with trackResourceHeaders', () => { test.describe('manual resources with startResource/stopResource', () => { createTest('track a manual resource with startResource/stopResource') - .withRum({ enableExperimentalFeatures: ['start_stop_resource'] }) + .withRum() .run(async ({ intakeRegistry, flushEvents, page }) => { await page.evaluate(() => { window.DD_RUM!.startResource('https://api.example.com/data') @@ -524,7 +524,7 @@ test.describe('manual resources with startResource/stopResource', () => { }) createTest('track a manual resource with type and method') - .withRum({ enableExperimentalFeatures: ['start_stop_resource'] }) + .withRum() .run(async ({ intakeRegistry, flushEvents, page }) => { await page.evaluate(() => { window.DD_RUM!.startResource('https://api.example.com/users', { @@ -547,7 +547,7 @@ test.describe('manual resources with startResource/stopResource', () => { }) createTest('track multiple concurrent manual resources with resourceKey') - .withRum({ enableExperimentalFeatures: ['start_stop_resource'] }) + .withRum() .run(async ({ intakeRegistry, flushEvents, page }) => { await page.evaluate(() => { window.DD_RUM!.startResource('https://api.example.com/data', { resourceKey: 'request1' }) @@ -565,7 +565,7 @@ test.describe('manual resources with startResource/stopResource', () => { }) createTest('merge contexts from start and stop') - .withRum({ enableExperimentalFeatures: ['start_stop_resource'] }) + .withRum() .run(async ({ intakeRegistry, flushEvents, page }) => { await page.evaluate(() => { window.DD_RUM!.startResource('https://api.example.com/data', { @@ -590,7 +590,7 @@ test.describe('manual resources with startResource/stopResource', () => { }) createTest('preserve timing when startResource is called before init') - .withRum({ enableExperimentalFeatures: ['start_stop_resource'] }) + .withRum() .withRumInit((configuration) => { window.DD_RUM!.startResource('https://api.example.com/early') From 82c3c6ab6d1897c4a2e3e0bf3562fd43122a037e Mon Sep 17 00:00:00 2001 From: "beltran.bulbarella" Date: Wed, 27 May 2026 13:06:38 +0200 Subject: [PATCH 2/2] Update tsdoc --- packages/rum-core/src/boot/rumPublicApi.ts | 33 +++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/rum-core/src/boot/rumPublicApi.ts b/packages/rum-core/src/boot/rumPublicApi.ts index 861715555d..6e97d35d96 100644 --- a/packages/rum-core/src/boot/rumPublicApi.ts +++ b/packages/rum-core/src/boot/rumPublicApi.ts @@ -174,16 +174,29 @@ export interface RumPublicApi extends PublicApi { addAction: (name: string, context?: object) => void /** - * [Experimental] Start an action, stored in `@action` + * Start tracking a custom action. + * + * Call {@link stopAction} with the same name (and optional `actionKey`) to send a RUM action event + * with the elapsed duration. Errors and resources triggered between start and stop are associated + * with the action. * * @category Data Collection * @param name - Name of the action * @param options - Options of the action (@default type: 'custom') + * @example + * ```ts + * datadogRum.startAction('checkout', { context: { cartId: 'abc' } }) + * // ... user completes checkout + * datadogRum.stopAction('checkout') + * ``` */ startAction: (name: string, options?: ActionOptions) => void /** - * [Experimental] Stop an action, stored in `@action` + * Stop tracking a custom action started with {@link startAction}. + * + * Sends a RUM action event with the elapsed duration since the matching start call. Context from + * start and stop calls is merged into the event. * * @category Data Collection * @param name - Name of the action @@ -192,16 +205,28 @@ export interface RumPublicApi extends PublicApi { stopAction: (name: string, options?: ActionOptions) => void /** - * [Experimental] Start tracking a resource, stored in `@resource` + * Start tracking a resource manually. + * + * Use this for network activity that the SDK cannot automatically instrument. Call {@link stopResource} + * with the same URL (and optional `resourceKey`) to send a RUM resource event with the elapsed duration. * * @category Data Collection * @param url - URL of the resource * @param options - Options of the resource (@default type: 'other') + * @example + * ```ts + * datadogRum.startResource('https://api.example.com/users', { type: 'fetch', method: 'POST' }) + * // ... perform the request + * datadogRum.stopResource('https://api.example.com/users', { statusCode: 201 }) + * ``` */ startResource: (url: string, options?: ResourceOptions) => void /** - * [Experimental] Stop tracking a resource, stored in `@resource` + * Stop tracking a resource started with {@link startResource}. + * + * Sends a RUM resource event with the elapsed duration since the matching start call. Context from + * start and stop calls is merged into the event. * * @category Data Collection * @param url - URL of the resource