Skip to content

Commit 8413c59

Browse files
authored
feat: Emit SM on rum response invalid timestamps (#1518)
1 parent 39c9fb5 commit 8413c59

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

docs/supportability-metrics.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ A timeslice metric is harvested to the JSE/XHR consumer. An aggregation service
159159
* Generic/WebDriver/Detected
160160
<!--- A CSP violation was detected --->
161161
* Generic/CSPViolation/Detected
162+
<!-- Invalid timestamp seen in processing RUM response -->
163+
* Generic/TimeKeeper/InvalidTimestamp/Seen
162164

163165
### Frameworks
164166
<!--- React was Detected --->

src/features/page_view_event/aggregate/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,17 @@ export class Aggregate extends AggregateBase {
152152
}
153153

154154
try {
155+
const wasReady = this.agentRef.runtime.timeKeeper.ready
156+
155157
// will do nothing if already done
156158
this.agentRef.runtime.timeKeeper.processRumRequest(xhr, this.rumStartTime, rumEndTime, app.nrServerTime)
157159
if (!this.agentRef.runtime.timeKeeper.ready) throw new Error('TimeKeeper not ready')
160+
161+
// If timeKeeper's origin time is ahead of nrServerTime, then the timestamp is invalid. Report a supportability metric.
162+
const timeDiff = this.agentRef.runtime.timeKeeper.correctedOriginTime - app.nrServerTime
163+
if (wasReady && timeDiff > 0) {
164+
this.reportSupportabilityMetric('Generic/TimeKeeper/InvalidTimestamp/Seen', timeDiff)
165+
}
158166
} catch (error) {
159167
this.ee.abort()
160168
warn(17, error)

tests/components/page_view_event/aggregate.test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,57 @@ test('PageViewEvent does not throw on Harvester driven processes', () => {
3030
sendEmptyBody: true
3131
})).toEqual(true) // mimics the manual trigger in PVE `sendRum`; this should return true as it actually tries to "send"
3232
})
33+
34+
test('PageViewEvent reports SM on invalid timestamp', () => {
35+
const spy = jest.spyOn(pveAggregate, 'reportSupportabilityMetric')
36+
jest.useFakeTimers()
37+
38+
mainAgent.runtime.timeKeeper.processRumRequest(undefined, 0, 2, Date.now() + 20000)
39+
expect(mainAgent.runtime.timeKeeper.ready).toEqual(true)
40+
41+
const originTime = mainAgent.runtime.timeKeeper.correctedOriginTime
42+
pveAggregate.postHarvestCleanup({
43+
status: 200,
44+
responseText: JSON.stringify({
45+
app: {
46+
agents: [{ entityGuid: 'Mjk0MjgxMXxCUk9XU0VSfEFQUExJQ0FUSU9OfDQwNzUwNDQ3NQ' }],
47+
// agent's timestamp is in the future, so it is invalid
48+
nrServerTime: originTime - 10000
49+
}
50+
}),
51+
xhr: { status: 200 },
52+
targetApp: undefined
53+
})
54+
55+
expect(spy).toHaveBeenCalledWith('Generic/TimeKeeper/InvalidTimestamp/Seen', 10000)
56+
57+
jest.useRealTimers()
58+
spy.mockRestore()
59+
})
60+
61+
test('PageViewEvent does not report SM on valid timestamp', () => {
62+
const spy = jest.spyOn(pveAggregate, 'reportSupportabilityMetric')
63+
jest.useFakeTimers()
64+
65+
mainAgent.runtime.timeKeeper.processRumRequest(undefined, 0, 2, Date.now() + 20000)
66+
expect(mainAgent.runtime.timeKeeper.ready).toEqual(true)
67+
68+
const originTime = mainAgent.runtime.timeKeeper.correctedOriginTime
69+
pveAggregate.postHarvestCleanup({
70+
status: 200,
71+
responseText: JSON.stringify({
72+
app: {
73+
agents: [{ entityGuid: 'Mjk0MjgxMXxCUk9XU0VSfEFQUExJQ0FUSU9OfDQwNzUwNDQ3NQ' }],
74+
// agent's timestamp is in the past, so it is valid
75+
nrServerTime: originTime + 10000
76+
}
77+
}),
78+
xhr: { status: 200 },
79+
targetApp: undefined
80+
})
81+
82+
expect(spy).not.toHaveBeenCalled()
83+
84+
jest.useRealTimers()
85+
spy.mockRestore()
86+
})

0 commit comments

Comments
 (0)