Skip to content

Commit

Permalink
[RUMF-819] postpone start recording (#688)
Browse files Browse the repository at this point in the history
* [RUMF-819] split rum recorder API creation and global definition

* ⚗✨ [RUMF-819] postpone recording
  • Loading branch information
BenoitZugmeyer authored Jan 22, 2021
1 parent d17c295 commit d1c757e
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 21 deletions.
2 changes: 1 addition & 1 deletion packages/rum-core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { RumUserConfiguration, RumPublicApi, makeRumPublicApi } from './boot/rumPublicApi'
export { RumUserConfiguration, RumPublicApi, makeRumPublicApi, StartRum } from './boot/rumPublicApi'
export { ProvidedSource } from './domain/rumEventsCollection/error/errorCollection'
export {
RumEvent,
Expand Down
23 changes: 3 additions & 20 deletions packages/rum-recorder/src/boot/recorder.entry.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,10 @@
import { defineGlobal, getGlobalObject } from '@datadog/browser-core'
import {
CommonContext,
makeRumPublicApi,
RumPublicApi,
RumUserConfiguration,
startRum,
} from '@datadog/browser-rum-core'
import { RumPublicApi, startRum } from '@datadog/browser-rum-core'

import { startRecording } from './recorder'
import { makeRumRecorderPublicApi } from './rumRecorderPublicApi'

function startRumAndRecording(userConfiguration: RumUserConfiguration, getCommonContext: () => CommonContext) {
const startRumResult = startRum(userConfiguration, () => ({
...getCommonContext(),
hasReplay: true,
}))

const { lifeCycle, parentContexts, configuration, session } = startRumResult
startRecording(lifeCycle, userConfiguration.applicationId, configuration, session, parentContexts)

return startRumResult
}

export const datadogRum = makeRumPublicApi(startRumAndRecording)
export const datadogRum = makeRumRecorderPublicApi(startRum, startRecording)

interface BrowserWindow extends Window {
DD_RUM?: RumPublicApi
Expand Down
87 changes: 87 additions & 0 deletions packages/rum-recorder/src/boot/rumRecorderPublicApi.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Configuration } from '@datadog/browser-core'
import { RumPublicApi, StartRum } from '@datadog/browser-rum-core'
import { makeRumRecorderPublicApi, StartRecording } from './rumRecorderPublicApi'

const DEFAULT_INIT_CONFIGURATION = { applicationId: 'xxx', clientToken: 'xxx' }

describe('makeRumRecorderPublicApi', () => {
let rumGlobal: RumPublicApi & { startSessionRecord?(): void }
let startRecordingSpy: jasmine.Spy<StartRecording>
let startRumSpy: jasmine.Spy<StartRum>
let enabledFlags: string[] = []

beforeEach(() => {
enabledFlags = []
startRecordingSpy = jasmine.createSpy()
startRumSpy = jasmine.createSpy().and.callFake(() => {
const configuration: Partial<Configuration> = {
isEnabled(flag: string) {
return enabledFlags.indexOf(flag) >= 0
},
}
return ({ configuration } as unknown) as ReturnType<StartRum>
})
rumGlobal = makeRumRecorderPublicApi(startRumSpy, startRecordingSpy)
})

function getCommonContext() {
return startRumSpy.calls.first().args[1]()
}

describe('init', () => {
it('should start RUM when init is called', () => {
expect(startRumSpy).not.toHaveBeenCalled()
rumGlobal.init(DEFAULT_INIT_CONFIGURATION)
expect(startRumSpy).toHaveBeenCalled()
})

it('should start recording when init is called', () => {
expect(startRecordingSpy).not.toHaveBeenCalled()
rumGlobal.init(DEFAULT_INIT_CONFIGURATION)
expect(startRecordingSpy).toHaveBeenCalled()
})

it('should set commonContext.hasReplay to true', () => {
rumGlobal.init(DEFAULT_INIT_CONFIGURATION)
expect(getCommonContext().hasReplay).toBe(true)
})
})

describe('experimental flag postpone_start_recording', () => {
it('if disabled, startSessionRecord should not be defined', () => {
expect(rumGlobal.startSessionRecord).toBeUndefined()
rumGlobal.init(DEFAULT_INIT_CONFIGURATION)
expect(rumGlobal.startSessionRecord).toBeUndefined()
})

it('if enabled, recording should not start when calling init()', () => {
enabledFlags = ['postpone_start_recording']
rumGlobal.init(DEFAULT_INIT_CONFIGURATION)
expect(startRecordingSpy).not.toHaveBeenCalled()
})

it('if enabled, startSessionRecord should be defined', () => {
enabledFlags = ['postpone_start_recording']
expect(rumGlobal.startSessionRecord).toBeUndefined()
rumGlobal.init(DEFAULT_INIT_CONFIGURATION)
expect(rumGlobal.startSessionRecord).toEqual(jasmine.any(Function))
})

it('if enabled, commonContext.hasReplay should be true only if startSessionRecord is called', () => {
enabledFlags = ['postpone_start_recording']
rumGlobal.init(DEFAULT_INIT_CONFIGURATION)
expect(getCommonContext().hasReplay).toBe(false)
rumGlobal.startSessionRecord!()
expect(getCommonContext().hasReplay).toBe(true)
})

it('if enabled, calling startSessionRecord multiple times should only start recording once', () => {
enabledFlags = ['postpone_start_recording']
rumGlobal.init(DEFAULT_INIT_CONFIGURATION)
rumGlobal.startSessionRecord!()
rumGlobal.startSessionRecord!()
rumGlobal.startSessionRecord!()
expect(startRecordingSpy).toHaveBeenCalledTimes(1)
})
})
})
37 changes: 37 additions & 0 deletions packages/rum-recorder/src/boot/rumRecorderPublicApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { monitor } from '@datadog/browser-core'
import { makeRumPublicApi, StartRum } from '@datadog/browser-rum-core'

import { startRecording } from './recorder'

export type StartRecording = typeof startRecording

export function makeRumRecorderPublicApi(startRumImpl: StartRum, startRecordingImpl: StartRecording) {
const rumRecorderGlobal = makeRumPublicApi((userConfiguration, getCommonContext) => {
let isRecording = false

const startRumResult = startRumImpl(userConfiguration, () => ({
...getCommonContext(),
hasReplay: isRecording,
}))

const { lifeCycle, parentContexts, configuration, session } = startRumResult

if (configuration.isEnabled('postpone_start_recording')) {
;(rumRecorderGlobal as any).startSessionRecord = monitor(startSessionRecord)
} else {
startSessionRecord()
}

function startSessionRecord() {
if (isRecording) {
return
}

isRecording = true
startRecordingImpl(lifeCycle, userConfiguration.applicationId, configuration, session, parentContexts)
}

return startRumResult
})
return rumRecorderGlobal
}

0 comments on commit d1c757e

Please sign in to comment.