Skip to content
Draft
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 @@ -31,6 +31,7 @@ const RUM_EVENT_TYPE_COLOR = {
error: 'red',
long_task: 'yellow',
view: 'blue',
view_update: 'blue',
resource: 'cyan',
telemetry: 'teal',
vital: 'orange',
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/tools/experimentalFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export enum ExperimentalFeature {
USE_CHANGE_RECORDS = 'use_change_records',
SOURCE_CODE_CONTEXT = 'source_code_context',
LCP_SUBPARTS = 'lcp_subparts',
VIEW_UPDATE = 'view_update',
VIEW_UPDATE_CHAOS = 'view_update_chaos',
}

const enabledExperimentalFeatures: Set<ExperimentalFeature> = new Set()
Expand Down
56 changes: 55 additions & 1 deletion packages/rum-core/src/domain/assembly.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ describe('rum assembly', () => {
})

expect(serverRumEvents[0].view.id).toBe('aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee')
expect(displaySpy).toHaveBeenCalledWith("Can't dismiss view events using beforeSend!")
expect(displaySpy).toHaveBeenCalledWith("Can't dismiss view or view_update events using beforeSend!")
})
})

Expand Down Expand Up @@ -570,6 +570,60 @@ describe('rum assembly', () => {
})
})
})

describe('view_update events', () => {
it('should not allow dismissing view_update events', () => {
const { lifeCycle, serverRumEvents } = setupAssemblyTestWithDefaults({
partialConfiguration: {
beforeSend: () => false,
},
})

const displaySpy = spyOn(display, 'warn')
notifyRawRumEvent(lifeCycle, {
rawRumEvent: createRawRumEvent(RumEventType.VIEW_UPDATE, {
view: { id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' },
}),
})

expect(serverRumEvents.length).toBe(1)
expect(displaySpy).toHaveBeenCalledWith("Can't dismiss view or view_update events using beforeSend!")
})

it('should allow modification of view_update events via beforeSend', () => {
const { lifeCycle, serverRumEvents } = setupAssemblyTestWithDefaults({
partialConfiguration: {
beforeSend: (event) => {
event.view.name = 'modified name'
},
},
})

notifyRawRumEvent(lifeCycle, {
rawRumEvent: createRawRumEvent(RumEventType.VIEW_UPDATE),
})

expect(serverRumEvents[0].view.name).toBe('modified name')
})

it('should not rate-limit view_update events', () => {
const { lifeCycle, serverRumEvents } = setupAssemblyTestWithDefaults({
eventRateLimit: 1,
})

notifyRawRumEvent(lifeCycle, {
rawRumEvent: createRawRumEvent(RumEventType.VIEW_UPDATE, { date: 100 as TimeStamp }),
})
notifyRawRumEvent(lifeCycle, {
rawRumEvent: createRawRumEvent(RumEventType.VIEW_UPDATE, { date: 200 as TimeStamp }),
})
notifyRawRumEvent(lifeCycle, {
rawRumEvent: createRawRumEvent(RumEventType.VIEW_UPDATE, { date: 300 as TimeStamp }),
})

expect(serverRumEvents.length).toBe(3)
})
})
})

function notifyRawRumEvent<E extends RawRumEvent>(
Expand Down
9 changes: 7 additions & 2 deletions packages/rum-core/src/domain/assembly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ export function startRumAssembly(
...VIEW_MODIFIABLE_FIELD_PATHS,
...ROOT_MODIFIABLE_FIELD_PATHS,
},
[RumEventType.VIEW_UPDATE]: {
...USER_CUSTOMIZABLE_FIELD_PATHS,
...VIEW_MODIFIABLE_FIELD_PATHS,
...ROOT_MODIFIABLE_FIELD_PATHS,
},
}
const eventRateLimiters = {
[RumEventType.ERROR]: createEventRateLimiter(RumEventType.ERROR, reportError, eventRateLimit),
Expand Down Expand Up @@ -129,11 +134,11 @@ function shouldSend(
const result = limitModification(event, modifiableFieldPathsByEvent[event.type], (event) =>
beforeSend(event, domainContext)
)
if (result === false && event.type !== RumEventType.VIEW) {
if (result === false && event.type !== RumEventType.VIEW && event.type !== RumEventType.VIEW_UPDATE) {
return false
}
if (result === false) {
display.warn("Can't dismiss view events using beforeSend!")
display.warn("Can't dismiss view or view_update events using beforeSend!")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,25 @@ describe('featureFlagContexts', () => {
},
})
})
it('should add feature flag evaluations on VIEW_UPDATE by default', () => {
lifeCycle.notify(LifeCycleEventType.BEFORE_VIEW_CREATED, {
startClocks: relativeToClocks(0 as RelativeTime),
} as ViewCreatedEvent)

featureFlagContexts.addFeatureFlagEvaluation('feature', 'foo')

const defaultViewUpdateAttributes = hooks.triggerHook(HookNames.Assemble, {
eventType: 'view_update',
startTime: 0 as RelativeTime,
} as AssembleHookParams)

expect(defaultViewUpdateAttributes).toEqual({
type: 'view_update',
feature_flags: {
feature: 'foo',
},
})
})
;[RumEventType.VITAL, RumEventType.ACTION, RumEventType.LONG_TASK, RumEventType.RESOURCE].forEach((eventType) => {
it(`should add feature flag evaluations on ${eventType} when specified in trackFeatureFlagsForEvents`, () => {
trackFeatureFlagsForEvents.push(eventType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export function startFeatureFlagContexts(
hooks.register(HookNames.Assemble, ({ startTime, eventType }): DefaultRumEventAttributes | SKIPPED => {
const trackFeatureFlagsForEvents = (configuration.trackFeatureFlagsForEvents as RumEventType[]).concat([
RumEventType.VIEW,
RumEventType.VIEW_UPDATE,
RumEventType.ERROR,
])
if (!trackFeatureFlagsForEvents.includes(eventType as RumEventType)) {
Expand Down
14 changes: 14 additions & 0 deletions packages/rum-core/src/domain/contexts/sessionContext.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,20 @@ describe('session context', () => {
expect(eventSampledOutForReplay.session!.sampled_for_replay).toBe(false)
})

it('should set hasReplay and sampled_for_replay on view_update events', () => {
getReplayStatsSpy.and.returnValue(fakeStats)
sessionManager.setTrackedWithSessionReplay()

const viewUpdateAttributes = hooks.triggerHook(HookNames.Assemble, {
eventType: 'view_update',
startTime: 0 as RelativeTime,
} as AssembleHookParams) as DefaultRumEventAttributes

expect(getReplayStatsSpy).toHaveBeenCalled()
expect(viewUpdateAttributes.session!.has_replay).toEqual(true)
expect(viewUpdateAttributes.session!.sampled_for_replay).toBe(true)
})

it('should discard the event if no session', () => {
sessionManager.setNotTracked()
const defaultRumEventAttributes = hooks.triggerHook(HookNames.Assemble, {
Expand Down
2 changes: 1 addition & 1 deletion packages/rum-core/src/domain/contexts/sessionContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function startSessionContext(
let hasReplay
let sampledForReplay
let isActive
if (eventType === RumEventType.VIEW) {
if (eventType === RumEventType.VIEW || eventType === RumEventType.VIEW_UPDATE) {
hasReplay = recorderApi.getReplayStats(view.id) ? true : undefined
sampledForReplay = session.sessionReplay === SessionReplayState.SAMPLED
isActive = view.sessionIsActive ? undefined : false
Expand Down
2 changes: 1 addition & 1 deletion packages/rum-core/src/domain/trackEventCounts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('trackEventCounts', () => {
notifyCollectedRawRumEvent({ type: RumEventType.LONG_TASK })
expect(eventCounts.longTaskCount).toBe(1)
})
;[RumEventType.VIEW, RumEventType.VITAL].forEach((eventType) => {
;[RumEventType.VIEW, RumEventType.VIEW_UPDATE, RumEventType.VITAL].forEach((eventType) => {
it(`doesn't track ${eventType} events`, () => {
const { eventCounts } = trackEventCounts({ lifeCycle, isChildEvent: () => true })
notifyCollectedRawRumEvent({ type: eventType })
Expand Down
2 changes: 1 addition & 1 deletion packages/rum-core/src/domain/trackEventCounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function trackEventCounts({
}

const subscription = lifeCycle.subscribe(LifeCycleEventType.RUM_EVENT_COLLECTED, (event): void => {
if (event.type === 'view' || event.type === 'vital' || !isChildEvent(event)) {
if (event.type === 'view' || event.type === 'view_update' || event.type === 'vital' || !isChildEvent(event)) {
return
}
switch (event.type) {
Expand Down
Loading