Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚗[RUMF-878] add trackViewsManually option (disabled) #867

Merged
merged 10 commits into from
Jun 8, 2021
6 changes: 6 additions & 0 deletions packages/core/src/domain/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const DEFAULT_CONFIGURATION = {
sampleRate: 100,
silentMultipleInit: false,
trackInteractions: false,
trackViewsManually: false,

/**
* arbitrary value, byte precision not needed
Expand Down Expand Up @@ -50,6 +51,7 @@ export interface UserConfiguration {
enableExperimentalFeatures?: string[]
silentMultipleInit?: boolean
trackInteractions?: boolean
trackViewsManually?: boolean
proxyHost?: string
beforeSend?: (event: any) => void

Expand Down Expand Up @@ -131,6 +133,10 @@ export function buildConfiguration(userConfiguration: UserConfiguration, buildEn
configuration.trackInteractions = !!userConfiguration.trackInteractions
}

if ('trackViewsManually' in userConfiguration) {
configuration.trackViewsManually = !!userConfiguration.trackViewsManually
}

return configuration
}

Expand Down
2 changes: 1 addition & 1 deletion packages/rum-core/src/boot/rum.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ function startRum(
)
const { stop: viewCollectionStop } = startViewCollection(
lifeCycle,
configuration,
location,
domMutationObservable,
foregroundContexts
)

return {
stop: () => {
rumEventCollectionStop()
Expand Down
26 changes: 17 additions & 9 deletions packages/rum-core/src/boot/rum.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { combine, commonInit, Configuration } from '@datadog/browser-core'
import { combine, Configuration, InternalMonitoring } from '@datadog/browser-core'
import { createDOMMutationObservable } from '../browser/domMutationObservable'
import { startPerformanceCollection } from '../browser/performanceCollection'
import { startRumAssembly } from '../domain/assembly'
import { startForegroundContexts } from '../domain/foregroundContexts'
import { startInternalContext } from '../domain/internalContext'
import { LifeCycle } from '../domain/lifeCycle'
import { startParentContexts } from '../domain/parentContexts'
import { startForegroundContexts } from '../domain/foregroundContexts'
import { startRequestCollection } from '../domain/requestCollection'
import { startActionCollection } from '../domain/rumEventsCollection/action/actionCollection'
import { startErrorCollection } from '../domain/rumEventsCollection/error/errorCollection'
Expand All @@ -15,13 +15,16 @@ import { startViewCollection } from '../domain/rumEventsCollection/view/viewColl
import { RumSession, startRumSession } from '../domain/rumSession'
import { CommonContext } from '../rawRumEvent.types'
import { startRumBatch } from '../transport/batch'

import { buildEnv } from './buildEnv'
import { RumUserConfiguration } from './rumPublicApi'

export function startRum(userConfiguration: RumUserConfiguration, getCommonContext: () => CommonContext) {
export function startRum(
userConfiguration: RumUserConfiguration,
configuration: Configuration,
internalMonitoring: InternalMonitoring,
getCommonContext: () => CommonContext,
initialViewName?: string
) {
const lifeCycle = new LifeCycle()
const { configuration, internalMonitoring } = commonInit(userConfiguration, buildEnv)
const session = startRumSession(configuration, lifeCycle)
const domMutationObservable = createDOMMutationObservable()

Expand All @@ -45,8 +48,14 @@ export function startRum(userConfiguration: RumUserConfiguration, getCommonConte

startLongTaskCollection(lifeCycle)
startResourceCollection(lifeCycle, session)

const { addTiming, startView } = startViewCollection(lifeCycle, location, domMutationObservable, foregroundContexts)
const { addTiming, startView } = startViewCollection(
lifeCycle,
configuration,
location,
domMutationObservable,
foregroundContexts,
initialViewName
)
const { addError } = startErrorCollection(lifeCycle, configuration, foregroundContexts)
const { addAction } = startActionCollection(lifeCycle, domMutationObservable, configuration, foregroundContexts)

Expand All @@ -60,7 +69,6 @@ export function startRum(userConfiguration: RumUserConfiguration, getCommonConte
addError,
addTiming,
startView,
configuration,
lifeCycle,
parentContexts,
session,
Expand Down
142 changes: 118 additions & 24 deletions packages/rum-core/src/boot/rumPublicApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const noopStartRum = (): ReturnType<StartRum> => ({
addError: () => undefined,
addTiming: () => undefined,
startView: () => undefined,
configuration: { isEnabled: () => true } as any,
getInternalContext: () => undefined,
lifeCycle: {} as any,
parentContexts: {} as any,
Expand Down Expand Up @@ -448,54 +447,149 @@ describe('rum public api', () => {
})
})

describe('startView', () => {
describe('trackViews mode', () => {
const AUTO_CONFIGURATION = { ...DEFAULT_INIT_CONFIGURATION, enableExperimentalFeatures: ['view-renaming'] }
const MANUAL_CONFIGURATION = { ...AUTO_CONFIGURATION, trackViewsManually: true }

let startRumSpy: jasmine.Spy<StartRum>
let startViewSpy: jasmine.Spy<ReturnType<StartRum>['startView']>
let addTimingSpy: jasmine.Spy<ReturnType<StartRum>['addTiming']>
let displaySpy: jasmine.Spy<() => void>
let rumPublicApi: RumPublicApi
let setupBuilder: TestSetupBuilder

beforeEach(() => {
startViewSpy = jasmine.createSpy()
startViewSpy = jasmine.createSpy('startView')
addTimingSpy = jasmine.createSpy('addTiming')
displaySpy = spyOn(display, 'error')
rumPublicApi = makeRumPublicApi(() => ({
startRumSpy = jasmine.createSpy('startRum').and.returnValue({
...noopStartRum(),
addTiming: addTimingSpy,
startView: startViewSpy,
}))
})
rumPublicApi = makeRumPublicApi(startRumSpy)
setupBuilder = setup()
})

afterEach(() => {
setupBuilder.cleanup()
})

it('should allow to start view before init', () => {
const { clock } = setupBuilder.withFakeClock().build()
describe('when auto', () => {
it('should start rum at init', () => {
rumPublicApi.init(AUTO_CONFIGURATION)

clock.tick(10)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
;(rumPublicApi as any).startView('foo')
expect(startRumSpy).toHaveBeenCalled()
})

expect(startViewSpy).not.toHaveBeenCalled()
it('before init startView should be handled after init', () => {
const { clock } = setupBuilder.withFakeClock().build()

clock.tick(20)
rumPublicApi.init(DEFAULT_INIT_CONFIGURATION)
clock.tick(10)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
;(rumPublicApi as any).startView('foo')

expect(startViewSpy).not.toHaveBeenCalled()

clock.tick(20)
rumPublicApi.init(AUTO_CONFIGURATION)

expect(startViewSpy).toHaveBeenCalled()
expect(startViewSpy.calls.argsFor(0)[0]).toEqual('foo')
expect(startViewSpy.calls.argsFor(0)[1]).toEqual({
relative: 10 as RelativeTime,
timeStamp: (jasmine.any(Number) as unknown) as TimeStamp,
})
})

it('after init startView should be handle immediately', () => {
rumPublicApi.init(AUTO_CONFIGURATION)

// eslint-disable-next-line @typescript-eslint/no-unsafe-call
;(rumPublicApi as any).startView('foo')

expect(startViewSpy.calls.argsFor(0)[0]).toEqual('foo')
expect(startViewSpy.calls.argsFor(0)[1]).toEqual({
relative: 10 as RelativeTime,
timeStamp: (jasmine.any(Number) as unknown) as TimeStamp,
expect(startViewSpy).toHaveBeenCalled()
expect(startViewSpy.calls.argsFor(0)[0]).toEqual('foo')
expect(startViewSpy.calls.argsFor(0)[1]).toBeUndefined()
expect(displaySpy).not.toHaveBeenCalled()
})
})

it('should to start view', () => {
rumPublicApi.init(DEFAULT_INIT_CONFIGURATION)
describe('when views are tracked manually', () => {
it('should not start rum at init', () => {
rumPublicApi.init(MANUAL_CONFIGURATION)

// eslint-disable-next-line @typescript-eslint/no-unsafe-call
;(rumPublicApi as any).startView('foo')
expect(startRumSpy).not.toHaveBeenCalled()
})

expect(startViewSpy.calls.argsFor(0)[0]).toEqual('foo')
expect(startViewSpy.calls.argsFor(0)[1]).toBeUndefined()
expect(displaySpy).not.toHaveBeenCalled()
it('before init startView should start rum', () => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
;(rumPublicApi as any).startView('foo')
expect(startRumSpy).not.toHaveBeenCalled()
expect(startViewSpy).not.toHaveBeenCalled()

rumPublicApi.init(MANUAL_CONFIGURATION)
expect(startRumSpy).toHaveBeenCalled()
expect(startRumSpy.calls.argsFor(0)[4]).toEqual('foo')
expect(startViewSpy).not.toHaveBeenCalled()
})

it('after init startView should start rum', () => {
rumPublicApi.init(MANUAL_CONFIGURATION)
expect(startRumSpy).not.toHaveBeenCalled()
expect(startViewSpy).not.toHaveBeenCalled()

// eslint-disable-next-line @typescript-eslint/no-unsafe-call
;(rumPublicApi as any).startView('foo')
expect(startRumSpy).toHaveBeenCalled()
expect(startRumSpy.calls.argsFor(0)[4]).toEqual('foo')
expect(startViewSpy).not.toHaveBeenCalled()
})

it('after start rum startView should start view', () => {
rumPublicApi.init(MANUAL_CONFIGURATION)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
;(rumPublicApi as any).startView('foo')
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
;(rumPublicApi as any).startView('bar')

expect(startRumSpy).toHaveBeenCalled()
expect(startRumSpy.calls.argsFor(0)[4]).toEqual('foo')
expect(startViewSpy).toHaveBeenCalled()
expect(startViewSpy.calls.argsFor(0)[0]).toEqual('bar')
expect(startViewSpy.calls.argsFor(0)[1]).toBeUndefined()
})

it('API calls should be handled in order', () => {
const { clock } = setupBuilder.withFakeClock().build()

clock.tick(10)
rumPublicApi.addTiming('first')

clock.tick(10)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
;(rumPublicApi as any).startView('foo')

clock.tick(10)
rumPublicApi.addTiming('second')

clock.tick(10)
rumPublicApi.init(MANUAL_CONFIGURATION)

clock.tick(10)
rumPublicApi.addTiming('third')

expect(addTimingSpy).toHaveBeenCalledTimes(3)

expect(addTimingSpy.calls.argsFor(0)[0]).toEqual('first')
expect(addTimingSpy.calls.argsFor(0)[1]).toEqual(getTimeStamp(10 as RelativeTime))

expect(addTimingSpy.calls.argsFor(1)[0]).toEqual('second')
expect(addTimingSpy.calls.argsFor(1)[1]).toEqual(getTimeStamp(30 as RelativeTime))

expect(addTimingSpy.calls.argsFor(2)[0]).toEqual('third')
expect(addTimingSpy.calls.argsFor(2)[1]).toBeUndefined() // no time saved when started
})
})
})
})
Loading