Skip to content

Commit 984b05e

Browse files
authored
fix: User frustrations logic should be gated (#1600)
1 parent 3b787b0 commit 984b05e

File tree

2 files changed

+47
-35
lines changed

2 files changed

+47
-35
lines changed

src/features/generic_events/instrument/index.js

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ export class Instrument extends InstrumentBase {
4141
setupRegisterAPI(agentRef)
4242
setupMeasureAPI(agentRef)
4343

44+
const ufEnabled = agentRef.init.feature_flags.includes('user_frustrations')
45+
let historyEE
46+
if (isBrowserScope && ufEnabled) {
47+
wrapFetch(this.ee)
48+
wrapXhr(this.ee)
49+
historyEE = wrapHistory(this.ee)
50+
}
51+
4452
if (isBrowserScope) {
4553
if (agentRef.init.user_actions.enabled) {
4654
OBSERVED_EVENTS.forEach(eventType =>
@@ -52,7 +60,43 @@ export class Instrument extends InstrumentBase {
5260
}
5361
// Capture is not used here so that we don't get element focus/blur events, only the window's as they do not bubble. They are also not cancellable, so no worries about being front of line.
5462
)
63+
64+
if (ufEnabled) {
65+
globalScope.addEventListener('error', () => {
66+
handle('uaErr', [], undefined, FEATURE_NAMES.genericEvents, this.ee)
67+
}, eventListenerOpts(false, this.removeOnAbort?.signal))
68+
69+
this.ee.on('open-xhr-start', (args, xhr) => {
70+
if (!isInternalTraffic(args[1])) {
71+
xhr.addEventListener('readystatechange', () => {
72+
if (xhr.readyState === 2) { // HEADERS_RECEIVED
73+
handle('uaXhr', [], undefined, FEATURE_NAMES.genericEvents, this.ee)
74+
}
75+
})
76+
}
77+
})
78+
this.ee.on('fetch-start', (fetchArguments) => {
79+
if (fetchArguments.length >= 1 && !isInternalTraffic(extractUrl(fetchArguments[0]))) {
80+
handle('uaXhr', [], undefined, FEATURE_NAMES.genericEvents, this.ee)
81+
}
82+
})
83+
84+
function isInternalTraffic (url) {
85+
const parsedUrl = parseUrl(url)
86+
return agentRef.beacons.includes(parsedUrl.hostname + ':' + parsedUrl.port)
87+
}
88+
89+
historyEE.on('pushState-end', navigationChange)
90+
historyEE.on('replaceState-end', navigationChange)
91+
window.addEventListener('hashchange', navigationChange, eventListenerOpts(true, this.removeOnAbort?.signal))
92+
window.addEventListener('popstate', navigationChange, eventListenerOpts(true, this.removeOnAbort?.signal))
93+
94+
function navigationChange () {
95+
historyEE.emit('navChange')
96+
}
97+
}
5598
}
99+
56100
if (agentRef.init.performance.resources.enabled && globalScope.PerformanceObserver?.supportedEntryTypes.includes('resource')) {
57101
const observer = new PerformanceObserver((list) => {
58102
list.getEntries().forEach(entry => {
@@ -61,15 +105,6 @@ export class Instrument extends InstrumentBase {
61105
})
62106
observer.observe({ type: 'resource', buffered: true })
63107
}
64-
65-
const historyEE = wrapHistory(this.ee)
66-
historyEE.on('pushState-end', navigationChange)
67-
historyEE.on('replaceState-end', navigationChange)
68-
window.addEventListener('hashchange', navigationChange, eventListenerOpts(true, this.removeOnAbort?.signal))
69-
window.addEventListener('popstate', navigationChange, eventListenerOpts(true, this.removeOnAbort?.signal))
70-
function navigationChange () {
71-
historyEE.emit('navChange')
72-
}
73108
}
74109

75110
try {
@@ -81,32 +116,6 @@ export class Instrument extends InstrumentBase {
81116
this.abortHandler = undefined // weakly allow this abort op to run only once
82117
}
83118

84-
globalScope.addEventListener('error', () => {
85-
handle('uaErr', [], undefined, FEATURE_NAMES.genericEvents, this.ee)
86-
}, eventListenerOpts(false, this.removeOnAbort?.signal))
87-
88-
wrapFetch(this.ee)
89-
wrapXhr(this.ee)
90-
this.ee.on('open-xhr-start', (args, xhr) => {
91-
if (!isInternalTraffic(args[1])) {
92-
xhr.addEventListener('readystatechange', () => {
93-
if (xhr.readyState === 2) { // HEADERS_RECEIVED
94-
handle('uaXhr', [], undefined, FEATURE_NAMES.genericEvents, this.ee)
95-
}
96-
})
97-
}
98-
})
99-
this.ee.on('fetch-start', (fetchArguments) => {
100-
if (fetchArguments.length >= 1 && !isInternalTraffic(extractUrl(fetchArguments[0]))) {
101-
handle('uaXhr', [], undefined, FEATURE_NAMES.genericEvents, this.ee)
102-
}
103-
})
104-
105-
function isInternalTraffic (url) {
106-
const parsedUrl = parseUrl(url)
107-
return agentRef.beacons.includes(parsedUrl.hostname + ':' + parsedUrl.port)
108-
}
109-
110119
/** If any of the sources are active, import the aggregator. otherwise deregister */
111120
if (genericEventSourceConfigs.some(x => x)) this.importAggregator(agentRef, () => import(/* webpackChunkName: "generic_events-aggregate" */ '../aggregate'))
112121
else this.deregisterDrain()

tests/components/generic_events/instrument/index.test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ beforeAll(() => {
1515
mainAgent = setupAgent({
1616
info: {
1717
beacon: 'some-agent-endpoint.com:1234'
18+
},
19+
init: {
20+
feature_flags: ['user_frustrations']
1821
}
1922
})
2023
genericEventsInstrument = new GenericEvents(mainAgent)

0 commit comments

Comments
 (0)