Skip to content

Commit

Permalink
Update performance entry event subscription
Browse files Browse the repository at this point in the history
  • Loading branch information
amortemousque committed Jan 7, 2022
1 parent 7f67c29 commit dce37e5
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 141 deletions.
16 changes: 9 additions & 7 deletions packages/rum-core/src/boot/startRum.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,14 @@ describe('rum events url', () => {
clock.tick(10)
changeLocation('http://foo.com/?bar=qux')

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, {
entryType: 'longtask',
startTime: relativeNow() - 5,
toJSON: noop,
duration: 5,
} as RumPerformanceEntry)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [
{
entryType: 'longtask',
startTime: relativeNow() - 5,
toJSON: noop,
duration: 5,
} as RumPerformanceEntry,
])

clock.tick(THROTTLE_VIEW_UPDATE_PERIOD)

Expand Down Expand Up @@ -269,7 +271,7 @@ describe('rum events url', () => {

serverRumEvents.length = 0

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_NAVIGATION_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [FAKE_NAVIGATION_ENTRY])
clock.tick(THROTTLE_VIEW_UPDATE_PERIOD)

expect(serverRumEvents.length).toEqual(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,32 +33,31 @@ describe('long task collection', () => {

it('should only listen to long task performance entry', () => {
const { lifeCycle, rawRumEvents } = setupBuilder.build()
;[
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [
LONG_TASK,
{ duration: 100 as Duration, entryType: 'navigation', startTime: 1234 },
{ duration: 100 as Duration, entryType: 'resource', startTime: 1234 },
{ duration: 100 as Duration, entryType: 'paint', startTime: 1234 },
].forEach((entry) => {
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, entry as RumPerformanceEntry)
})
] as RumPerformanceEntry[])

expect(rawRumEvents.length).toBe(1)
})

it('should only collect when session has a replay plan', () => {
const { lifeCycle, rawRumEvents } = setupBuilder.build()

sessionManager.setReplayPlan()
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, LONG_TASK)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [LONG_TASK])
expect(rawRumEvents.length).toBe(1)

sessionManager.setLitePlan()
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, LONG_TASK)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [LONG_TASK])
expect(rawRumEvents.length).toBe(1)
})

it('should create raw rum event from performance entry', () => {
const { lifeCycle, rawRumEvents } = setupBuilder.build()
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, LONG_TASK)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [LONG_TASK])

expect(rawRumEvents[0].startTime).toBe(1234 as RelativeTime)
expect(rawRumEvents[0].rawRumEvent).toEqual({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,29 @@ import { LifeCycle, LifeCycleEventType } from '../../lifeCycle'
import { RumSessionManager } from '../../rumSessionManager'

export function startLongTaskCollection(lifeCycle: LifeCycle, sessionManager: RumSessionManager) {
lifeCycle.subscribe(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, (entry) => {
if (entry.entryType !== 'longtask') {
return
lifeCycle.subscribe(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, (entries) => {
for (const entry of entries) {
if (entry.entryType !== 'longtask') {
break
}
const session = sessionManager.findTrackedSession(entry.startTime)
if (!session || session.hasLitePlan) {
break
}
const startClocks = relativeToClocks(entry.startTime)
const rawRumEvent: RawRumLongTaskEvent = {
date: startClocks.timeStamp,
long_task: {
id: generateUUID(),
duration: toServerDuration(entry.duration),
},
type: RumEventType.LONG_TASK,
}
lifeCycle.notify(LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, {
rawRumEvent,
startTime: startClocks.relative,
domainContext: { performanceEntry: entry.toJSON() },
})
}
const session = sessionManager.findTrackedSession(entry.startTime)
if (!session || session.hasLitePlan) {
return
}
const startClocks = relativeToClocks(entry.startTime)
const rawRumEvent: RawRumLongTaskEvent = {
date: startClocks.timeStamp,
long_task: {
id: generateUUID(),
duration: toServerDuration(entry.duration),
},
type: RumEventType.LONG_TASK,
}
lifeCycle.notify(LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, {
rawRumEvent,
startTime: startClocks.relative,
domainContext: { performanceEntry: entry.toJSON() },
})
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('resourceCollection', () => {
name: 'https://resource.com/valid',
startTime: 1234 as RelativeTime,
})
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, performanceEntry)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [performanceEntry])

expect(rawRumEvents[0].startTime).toBe(1234 as RelativeTime)
expect(rawRumEvents[0].rawRumEvent).toEqual({
Expand Down Expand Up @@ -152,12 +152,11 @@ describe('resourceCollection', () => {
describe('tracing info', () => {
it('should be processed from traced initial document', () => {
const { lifeCycle, rawRumEvents } = setupBuilder.build()
lifeCycle.notify(
LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED,
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [
createResourceEntry({
traceId: '1234',
})
)
}),
])
const traceInfo = (rawRumEvents[0].rawRumEvent as RawRumResourceEvent)._dd!
expect(traceInfo).toBeDefined()
expect(traceInfo.trace_id).toBe('1234')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ export function startResourceCollection(lifeCycle: LifeCycle) {
lifeCycle.notify(LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, processRequest(request))
})

lifeCycle.subscribe(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, (entry) => {
if (entry.entryType === 'resource' && !isRequestKind(entry)) {
lifeCycle.notify(LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, processResourceEntry(entry))
lifeCycle.subscribe(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, (entries) => {
for (const entry of entries) {
if (entry.entryType === 'resource' && !isRequestKind(entry)) {
lifeCycle.notify(LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, processResourceEntry(entry))
}
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@ describe('trackTimings', () => {
it('should merge timings from various sources', () => {
const { lifeCycle } = setupBuilder.build()

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_NAVIGATION_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_PAINT_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_FIRST_INPUT_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [
FAKE_NAVIGATION_ENTRY,
FAKE_PAINT_ENTRY,
FAKE_FIRST_INPUT_ENTRY,
])

expect(timingsCallback).toHaveBeenCalledTimes(3)
expect(timingsCallback.calls.mostRecent().args[0]).toEqual({
Expand Down Expand Up @@ -94,7 +96,7 @@ describe('trackNavigationTimings', () => {
it('should provide the first contentful paint timing', () => {
const { lifeCycle } = setupBuilder.build()

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_NAVIGATION_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [FAKE_NAVIGATION_ENTRY])

expect(navigationTimingsCallback).toHaveBeenCalledTimes(1)
expect(navigationTimingsCallback).toHaveBeenCalledWith({
Expand Down Expand Up @@ -125,7 +127,7 @@ describe('trackFirstContentfulPaintTiming', () => {
it('should provide the first contentful paint timing', () => {
const { lifeCycle } = setupBuilder.build()

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_PAINT_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [FAKE_PAINT_ENTRY])

expect(fcpCallback).toHaveBeenCalledTimes(1 as RelativeTime)
expect(fcpCallback).toHaveBeenCalledWith(123 as RelativeTime)
Expand All @@ -134,17 +136,19 @@ describe('trackFirstContentfulPaintTiming', () => {
it('should be discarded if the page is hidden', () => {
setPageVisibility('hidden')
const { lifeCycle } = setupBuilder.build()
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_PAINT_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [FAKE_PAINT_ENTRY])
expect(fcpCallback).not.toHaveBeenCalled()
})

it('should be discarded if it is reported after a long time', () => {
const { lifeCycle } = setupBuilder.build()

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, {
...FAKE_PAINT_ENTRY,
startTime: TIMING_MAXIMUM_DELAY as RelativeTime,
})
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [
{
...FAKE_PAINT_ENTRY,
startTime: TIMING_MAXIMUM_DELAY as RelativeTime,
},
])
expect(fcpCallback).not.toHaveBeenCalled()
})
})
Expand Down Expand Up @@ -172,7 +176,7 @@ describe('largestContentfulPaintTiming', () => {
it('should provide the largest contentful paint timing', () => {
const { lifeCycle } = setupBuilder.build()

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_LARGEST_CONTENTFUL_PAINT_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [FAKE_LARGEST_CONTENTFUL_PAINT_ENTRY])
expect(lcpCallback).toHaveBeenCalledTimes(1 as RelativeTime)
expect(lcpCallback).toHaveBeenCalledWith(789 as RelativeTime)
})
Expand All @@ -182,26 +186,28 @@ describe('largestContentfulPaintTiming', () => {

emitter.dispatchEvent(createNewEvent(DOM_EVENT.KEY_DOWN, { timeStamp: 1 }))

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_LARGEST_CONTENTFUL_PAINT_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [FAKE_LARGEST_CONTENTFUL_PAINT_ENTRY])
expect(lcpCallback).not.toHaveBeenCalled()
})

it('should be discarded if the page is hidden', () => {
setPageVisibility('hidden')
const { lifeCycle } = setupBuilder.build()

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_LARGEST_CONTENTFUL_PAINT_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [FAKE_LARGEST_CONTENTFUL_PAINT_ENTRY])

expect(lcpCallback).not.toHaveBeenCalled()
})

it('should be discarded if it is reported after a long time', () => {
const { lifeCycle } = setupBuilder.build()

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, {
...FAKE_LARGEST_CONTENTFUL_PAINT_ENTRY,
startTime: TIMING_MAXIMUM_DELAY as RelativeTime,
})
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [
{
...FAKE_LARGEST_CONTENTFUL_PAINT_ENTRY,
startTime: TIMING_MAXIMUM_DELAY as RelativeTime,
},
])
expect(lcpCallback).not.toHaveBeenCalled()
})
})
Expand All @@ -227,7 +233,7 @@ describe('firstInputTimings', () => {
it('should provide the first input timings', () => {
const { lifeCycle } = setupBuilder.build()

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_FIRST_INPUT_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [FAKE_FIRST_INPUT_ENTRY])
expect(fitCallback).toHaveBeenCalledTimes(1)
expect(fitCallback).toHaveBeenCalledWith({ firstInputDelay: 100, firstInputTime: 1000 })
})
Expand All @@ -236,19 +242,21 @@ describe('firstInputTimings', () => {
setPageVisibility('hidden')
const { lifeCycle } = setupBuilder.build()

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, FAKE_FIRST_INPUT_ENTRY)
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [FAKE_FIRST_INPUT_ENTRY])

expect(fitCallback).not.toHaveBeenCalled()
})

it('should be adjusted to 0 if the computed value would be negative due to browser timings imprecisions', () => {
const { lifeCycle } = setupBuilder.build()

lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRY_COLLECTED, {
entryType: 'first-input' as const,
processingStart: 900 as RelativeTime,
startTime: 1000 as RelativeTime,
})
lifeCycle.notify(LifeCycleEventType.PERFORMANCE_ENTRIES_COLLECTED, [
{
entryType: 'first-input' as const,
processingStart: 900 as RelativeTime,
startTime: 1000 as RelativeTime,
},
])

expect(fitCallback).toHaveBeenCalledTimes(1)
expect(fitCallback).toHaveBeenCalledWith({ firstInputDelay: 0, firstInputTime: 1000 })
Expand Down
Loading

0 comments on commit dce37e5

Please sign in to comment.