diff --git a/packages/rum-core/src/domain/rumEventsCollection/view/trackViews.spec.ts b/packages/rum-core/src/domain/rumEventsCollection/view/trackViews.spec.ts index a5f2adbe3e..0ef6323abe 100644 --- a/packages/rum-core/src/domain/rumEventsCollection/view/trackViews.spec.ts +++ b/packages/rum-core/src/domain/rumEventsCollection/view/trackViews.spec.ts @@ -61,7 +61,7 @@ describe('rum view referrer', () => { initialViewCreatedEvent = event subscription.unsubscribe() }) - return trackViews(location, lifeCycle) + return trackViews(location, lifeCycle, true) }) createSpy = jasmine.createSpy('create') }) @@ -128,7 +128,7 @@ describe('rum track renew session', () => { initialViewId = id subscription.unsubscribe() }) - return trackViews(location, lifeCycle) + return trackViews(location, lifeCycle, true) }) }) @@ -171,7 +171,7 @@ describe('rum track loading type', () => { .withFakeLocation('/foo') .beforeBuild(({ location, lifeCycle }) => { lifeCycle.subscribe(LifeCycleEventType.VIEW_UPDATED, handler) - return trackViews(location, lifeCycle) + return trackViews(location, lifeCycle, true) }) }) @@ -207,7 +207,7 @@ describe('rum track view is active', () => { .withFakeLocation('/foo') .beforeBuild(({ location, lifeCycle }) => { lifeCycle.subscribe(LifeCycleEventType.VIEW_UPDATED, handler) - return trackViews(location, lifeCycle) + return trackViews(location, lifeCycle, true) }) }) @@ -247,7 +247,7 @@ describe('rum view timings', () => { .withFakeLocation('/foo') .beforeBuild(({ location, lifeCycle }) => { lifeCycle.subscribe(LifeCycleEventType.VIEW_UPDATED, handler) - return trackViews(location, lifeCycle) + return trackViews(location, lifeCycle, true) }) }) @@ -375,7 +375,7 @@ describe('rum track custom timings', () => { .withFakeClock() .beforeBuild(({ location, lifeCycle }) => { lifeCycle.subscribe(LifeCycleEventType.VIEW_UPDATED, handler) - ;({ addTiming } = trackViews(location, lifeCycle)) + ;({ addTiming } = trackViews(location, lifeCycle, true)) }) }) @@ -472,7 +472,7 @@ describe('track hasReplay', () => { .withFakeClock() .beforeBuild(({ location, lifeCycle }) => { lifeCycle.subscribe(LifeCycleEventType.VIEW_UPDATED, handler) - return trackViews(location, lifeCycle) + return trackViews(location, lifeCycle, true) }) }) @@ -540,7 +540,7 @@ describe('rum start view', () => { setupBuilder = setup().beforeBuild(({ location, lifeCycle }) => { lifeCycle.subscribe(LifeCycleEventType.VIEW_UPDATED, handler) - ;({ startView } = trackViews(location, lifeCycle)) + ;({ startView } = trackViews(location, lifeCycle, true)) }) }) diff --git a/packages/rum-core/src/domain/rumEventsCollection/view/trackViews.ts b/packages/rum-core/src/domain/rumEventsCollection/view/trackViews.ts index 851ccac0e2..cab8738f34 100644 --- a/packages/rum-core/src/domain/rumEventsCollection/view/trackViews.ts +++ b/packages/rum-core/src/domain/rumEventsCollection/view/trackViews.ts @@ -53,62 +53,43 @@ export interface ViewEndedEvent { export const THROTTLE_VIEW_UPDATE_PERIOD = 3000 export const SESSION_KEEP_ALIVE_INTERVAL = 5 * ONE_MINUTE -export function trackViews(location: Location, lifeCycle: LifeCycle) { +type View = ReturnType + +export function trackViews(location: Location, lifeCycle: LifeCycle, areViewsTrackedAutomatically: boolean) { let isRecording = false + let hasInitialView = false + let currentView: View + let stopInitialViewTracking: () => void + let stopViewLifeCycle: () => void + let stopLocationChangesTracking: (() => void) | undefined - // eslint-disable-next-line prefer-const - let { stop: stopInitialViewTracking, initialView: currentView } = trackInitialView() - const { stop: stopLocationChangesTracking } = trackLocationChanges(() => { - if (areDifferentLocation(currentView.getLocation(), location)) { - // Renew view on location changes - currentView.end() - currentView.triggerUpdate() - currentView = trackViewChange() - return - } - currentView.updateLocation(location) - currentView.triggerUpdate() - }) - - // Renew view on session renewal - lifeCycle.subscribe(LifeCycleEventType.SESSION_RENEWED, () => { - // do not trigger view update to avoid wrong data - currentView.end() - currentView = trackViewChange() - }) - - // End the current view on page unload - lifeCycle.subscribe(LifeCycleEventType.BEFORE_UNLOAD, () => { - currentView.end() - currentView.triggerUpdate() - }) - - lifeCycle.subscribe(LifeCycleEventType.RECORD_STARTED, () => { - isRecording = true - currentView.updateHasReplay(true) - }) - - lifeCycle.subscribe(LifeCycleEventType.RECORD_STOPPED, () => { - isRecording = false - }) - - // Session keep alive - const keepAliveInterval = window.setInterval( - monitor(() => { + if (areViewsTrackedAutomatically) { + ;({ stop: stopInitialViewTracking, initialView: currentView } = trackInitialView()) + ;({ stop: stopViewLifeCycle } = startViewLifeCycle()) + ;({ stop: stopLocationChangesTracking } = trackLocationChanges(() => { + if (areDifferentLocation(currentView.getLocation(), location)) { + // Renew view on location changes + currentView.end() + currentView.triggerUpdate() + currentView = trackViewChange() + return + } + currentView.updateLocation(location) currentView.triggerUpdate() - }), - SESSION_KEEP_ALIVE_INTERVAL - ) + })) + } - function trackInitialView() { + function trackInitialView(name?: string) { const initialView = newView( lifeCycle, location, isRecording, ViewLoadingType.INITIAL_LOAD, document.referrer, - clocksOrigin() + clocksOrigin(), + name ) + hasInitialView = true const { stop } = trackInitialViewTimings(lifeCycle, (timings) => { initialView.updateTimings(timings) initialView.scheduleUpdate() @@ -120,21 +101,69 @@ export function trackViews(location: Location, lifeCycle: LifeCycle) { return newView(lifeCycle, location, isRecording, ViewLoadingType.ROUTE_CHANGE, currentView.url, startClocks, name) } + function startViewLifeCycle() { + lifeCycle.subscribe(LifeCycleEventType.SESSION_RENEWED, () => { + // do not trigger view update to avoid wrong data + currentView.end() + if (areViewsTrackedAutomatically) { + // Renew view on session renewal + currentView = trackViewChange() + } + }) + + // End the current view on page unload + lifeCycle.subscribe(LifeCycleEventType.BEFORE_UNLOAD, () => { + currentView.end() + currentView.triggerUpdate() + }) + + lifeCycle.subscribe(LifeCycleEventType.RECORD_STARTED, () => { + isRecording = true + currentView.updateHasReplay(true) + }) + + lifeCycle.subscribe(LifeCycleEventType.RECORD_STOPPED, () => { + isRecording = false + }) + + // Session keep alive + const keepAliveInterval = window.setInterval( + monitor(() => { + currentView.triggerUpdate() + }), + SESSION_KEEP_ALIVE_INTERVAL + ) + return { + stop: () => { + clearInterval(keepAliveInterval) + }, + } + } + return { addTiming: (name: string, time = timeStampNow()) => { - currentView.addTiming(name, time) - currentView.triggerUpdate() + if (hasInitialView) { + currentView.addTiming(name, time) + currentView.triggerUpdate() + } }, startView: (name?: string, startClocks?: ClocksState) => { - currentView.end(startClocks) - currentView.triggerUpdate() - currentView = trackViewChange(startClocks, name) + if (!hasInitialView) { + ;({ stop: stopInitialViewTracking, initialView: currentView } = trackInitialView(name)) + ;({ stop: stopViewLifeCycle } = startViewLifeCycle()) + } else { + currentView.end(startClocks) + currentView.triggerUpdate() + currentView = trackViewChange(startClocks, name) + } }, stop: () => { - stopInitialViewTracking() - stopLocationChangesTracking() - currentView.end() - clearInterval(keepAliveInterval) + stopLocationChangesTracking && stopLocationChangesTracking() + if (hasInitialView) { + stopInitialViewTracking() + stopViewLifeCycle() + currentView.end() + } }, } }