Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const RUM_EVENT_TYPE_COLOR = {
telemetry: 'teal',
vital: 'orange',
transition: 'green',
view_update: 'blue',
}

const LOG_STATUS_COLOR = {
Expand Down
41 changes: 21 additions & 20 deletions packages/core/src/domain/telemetry/telemetryEvent.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ export type TelemetryCommonFeaturesUsage =
| AddFeatureFlagEvaluation
| AddOperationStepVital
| GraphQLRequest
| AddViewLoadingTime
/**
* Schema of browser specific features usage
*/
Expand All @@ -543,7 +544,7 @@ export type TelemetryBrowserFeaturesUsage =
/**
* Schema of mobile specific features usage
*/
export type TelemetryMobileFeaturesUsage = AddViewLoadingTime | TrackWebView | AndroidNetworkInstrumentation
export type TelemetryMobileFeaturesUsage = TrackWebView | AndroidNetworkInstrumentation

/**
* Schema of common properties of Telemetry events
Expand Down Expand Up @@ -886,6 +887,25 @@ export interface GraphQLRequest {
feature: 'graphql-request'
[k: string]: unknown
}
export interface AddViewLoadingTime {
/**
* addViewLoadingTime API
*/
feature: 'addViewLoadingTime'
/**
* Whether the view is not available
*/
no_view?: boolean
/**
* Whether the available view is not active
*/
no_active_view?: boolean
/**
* Whether this call overwrote a previously set loading time
*/
overwritten?: boolean
[k: string]: unknown
}
export interface StartSessionReplayRecording {
/**
* startSessionReplayRecording API
Expand Down Expand Up @@ -946,25 +966,6 @@ export interface StopResource {
feature: 'stop-resource'
[k: string]: unknown
}
export interface AddViewLoadingTime {
/**
* addViewLoadingTime API
*/
feature: 'addViewLoadingTime'
/**
* Whether the view is not available
*/
no_view: boolean
/**
* Whether the available view is not active
*/
no_active_view: boolean
/**
* Whether the loading time was overwritten
*/
overwritten: boolean
[k: string]: unknown
}
export interface TrackWebView {
/**
* trackWebView API
Expand Down
27 changes: 27 additions & 0 deletions packages/rum-core/src/boot/preStartRum.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,33 @@ describe('preStartRum', () => {
expect(addTimingSpy).toHaveBeenCalledOnceWith(name, time)
})

it('setLoadingTime', () => {
const setLoadingTimeSpy = jasmine.createSpy()
doStartRumSpy.and.returnValue({ setLoadingTime: setLoadingTimeSpy } as unknown as StartRumResult)

const timestamp = 123 as TimeStamp
strategy.setLoadingTime(timestamp)
strategy.init(DEFAULT_INIT_CONFIGURATION, PUBLIC_API)
expect(setLoadingTimeSpy).toHaveBeenCalledOnceWith(timestamp)
})

it('setLoadingTime should preserve call timestamp', () => {
const clock = mockClock()
const setLoadingTimeSpy = jasmine.createSpy()
doStartRumSpy.and.returnValue({ setLoadingTime: setLoadingTimeSpy } as unknown as StartRumResult)

clock.tick(10)
strategy.setLoadingTime(clock.timeStamp(10))

clock.tick(20)
strategy.init(DEFAULT_INIT_CONFIGURATION, PUBLIC_API)

expect(setLoadingTimeSpy).toHaveBeenCalledOnceWith(jasmine.any(Number))
// Verify the timestamp was captured at call time (tick 10), not at drain time (tick 30)
const capturedTimestamp = setLoadingTimeSpy.calls.argsFor(0)[0] as number
expect(capturedTimestamp).toBe(clock.timeStamp(10))
})

it('setViewContext', () => {
const setViewContextSpy = jasmine.createSpy()
doStartRumSpy.and.returnValue({ setViewContext: setViewContextSpy } as unknown as StartRumResult)
Expand Down
5 changes: 5 additions & 0 deletions packages/rum-core/src/boot/preStartRum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
ContextManager,
BoundedBuffer,
Telemetry,
TimeStamp,
} from '@datadog/browser-core'
import {
createBoundedBuffer,
Expand Down Expand Up @@ -241,6 +242,10 @@ export function createPreStartStrategy(
bufferApiCalls.add((startRumResult) => startRumResult.addTiming(name, time))
},

setLoadingTime: ((callTimestamp: TimeStamp) => {
bufferApiCalls.add((startRumResult) => startRumResult.setLoadingTime(callTimestamp))
}) as Strategy['setLoadingTime'],

startView(options, startClocks = clocksNow()) {
const callback = (startRumResult: StartRumResult) => {
startRumResult.startView(options, startClocks)
Expand Down
29 changes: 29 additions & 0 deletions packages/rum-core/src/boot/rumPublicApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const noopStartRum = (): ReturnType<StartRum> => ({
addError: () => undefined,
addEvent: () => undefined,
addTiming: () => undefined,
setLoadingTime: () => undefined,
addFeatureFlagEvaluation: () => undefined,
startView: () => undefined,
setViewContext: () => undefined,
Expand Down Expand Up @@ -555,6 +556,34 @@ describe('rum public api', () => {
})
})

describe('setViewLoadingTime', () => {
let setLoadingTimeSpy: jasmine.Spy<ReturnType<StartRum>['setLoadingTime']>
let rumPublicApi: RumPublicApi

beforeEach(() => {
setLoadingTimeSpy = jasmine.createSpy()
;({ rumPublicApi } = makeRumPublicApiWithDefaults({
startRumResult: {
setLoadingTime: setLoadingTimeSpy,
},
}))
})

it('should call setLoadingTime with timestamp', () => {
rumPublicApi.init(DEFAULT_INIT_CONFIGURATION)

rumPublicApi.setViewLoadingTime()

expect(setLoadingTimeSpy).toHaveBeenCalledOnceWith(jasmine.any(Number))
})

it('should not throw when called before init', () => {
expect(() => rumPublicApi.setViewLoadingTime()).not.toThrow()

expect(setLoadingTimeSpy).not.toHaveBeenCalled()
})
})

describe('addFeatureFlagEvaluation', () => {
let addFeatureFlagEvaluationSpy: jasmine.Spy<ReturnType<StartRum>['addFeatureFlagEvaluation']>
let displaySpy: jasmine.Spy<() => void>
Expand Down
20 changes: 20 additions & 0 deletions packages/rum-core/src/boot/rumPublicApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
ExperimentalFeature,
mockable,
generateUUID,
timeStampNow,
} from '@datadog/browser-core'

import type { LifeCycle } from '../domain/lifeCycle'
Expand Down Expand Up @@ -236,6 +237,16 @@ export interface RumPublicApi extends PublicApi {
*/
addTiming: (name: string, time?: number) => void

/**
* [Experimental] Manually set the current view's loading time.
*
* Call this method when the view has finished loading. The loading time is computed as the
* elapsed time since the view started. Each call replaces any previously set value (last-call-wins).
*
* @category Data Collection
*/
setViewLoadingTime: () => void

/**
* Set the global context information to all events, stored in `@context`
* See [Global context](https://docs.datadoghq.com/real_user_monitoring/browser/advanced_configuration/#global-context) for further information.
Expand Down Expand Up @@ -553,6 +564,7 @@ export interface Strategy {
getInternalContext: StartRumResult['getInternalContext']
stopSession: StartRumResult['stopSession']
addTiming: StartRumResult['addTiming']
setLoadingTime: StartRumResult['setLoadingTime']
startView: StartRumResult['startView']
setViewName: StartRumResult['setViewName']

Expand Down Expand Up @@ -773,6 +785,14 @@ export function makeRumPublicApi(
strategy.addTiming(sanitize(name)!, time as RelativeTime | TimeStamp | undefined)
}),

setViewLoadingTime: monitor(() => {
const callTimestamp = timeStampNow()
strategy.setLoadingTime(callTimestamp)
addTelemetryUsage({
feature: 'addViewLoadingTime',
})
Comment thread
MaelNamNam marked this conversation as resolved.
}),

setGlobalContext: defineContextMethod(
getStrategy,
CustomerContextKey.globalContext,
Expand Down
2 changes: 2 additions & 0 deletions packages/rum-core/src/boot/startRum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ export function startRumEventCollection(

const {
addTiming,
setLoadingTime,
startView,
setViewName,
setViewContext,
Expand Down Expand Up @@ -253,6 +254,7 @@ export function startRumEventCollection(
addEvent: eventCollection.addEvent,
addError,
addTiming,
setLoadingTime,
addFeatureFlagEvaluation: featureFlagContexts.addFeatureFlagEvaluation,
startView,
setViewContext,
Expand Down
29 changes: 19 additions & 10 deletions packages/rum-core/src/domain/view/setupViewTest.specHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,24 @@ export function setupViewTest(
} = spyOnViews<ViewEndedEvent>()
lifeCycle.subscribe(LifeCycleEventType.VIEW_ENDED, viewEndHandler)

const { stop, startView, setViewName, setViewContext, setViewContextProperty, getViewContext, addTiming } =
trackViews(
lifeCycle,
domMutationObservable,
windowOpenObservable,
configuration,
locationChangeObservable,
!configuration.trackViewsManually,
initialViewOptions
)
const {
stop,
startView,
setViewName,
setViewContext,
setViewContextProperty,
getViewContext,
addTiming,
setLoadingTime,
} = trackViews(
lifeCycle,
domMutationObservable,
windowOpenObservable,
configuration,
locationChangeObservable,
!configuration.trackViewsManually,
initialViewOptions
)
return {
stop,
startView,
Expand All @@ -64,6 +72,7 @@ export function setupViewTest(
changeLocation,
setViewName,
addTiming,
setLoadingTime,
getViewUpdate,
getViewUpdateCount,
getViewCreate,
Expand Down
Loading
Loading