@newrelic/browser-agent 1.252.1 → 1.253.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/dist/cjs/cdn/experimental.js +6 -2
- package/dist/cjs/cdn/spa.js +5 -3
- package/dist/cjs/common/aggregate/aggregator.js +1 -8
- package/dist/cjs/common/config/state/init.js +7 -0
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/context/observation-context-manager.js +56 -0
- package/dist/cjs/common/event-emitter/contextual-ee.js +12 -9
- package/dist/cjs/common/session/constants.js +2 -1
- package/dist/cjs/common/timing/nav-timing.js +8 -3
- package/dist/cjs/common/timing/now.js +1 -1
- package/dist/cjs/common/util/feature-flags.js +1 -1
- package/dist/cjs/common/wrap/index.js +0 -7
- package/dist/cjs/common/wrap/wrap-events.js +2 -2
- package/dist/cjs/common/wrap/wrap-fetch.js +2 -1
- package/dist/cjs/common/wrap/wrap-function.js +5 -7
- package/dist/cjs/common/wrap/wrap-promise.js +2 -1
- package/dist/cjs/features/ajax/aggregate/index.js +34 -16
- package/dist/cjs/features/jserrors/aggregate/index.js +77 -66
- package/dist/cjs/features/page_view_event/aggregate/index.js +1 -1
- package/dist/cjs/features/page_view_event/aggregate/initialized-features.js +1 -0
- package/dist/cjs/features/session_replay/aggregate/index.js +96 -94
- package/dist/cjs/features/session_replay/constants.js +5 -1
- package/dist/cjs/features/session_replay/instrument/index.js +24 -8
- package/dist/cjs/features/session_replay/shared/utils.js +26 -0
- package/dist/cjs/features/soft_navigations/aggregate/ajax-node.js +50 -0
- package/dist/cjs/features/soft_navigations/aggregate/bel-node.js +29 -0
- package/dist/cjs/features/soft_navigations/aggregate/index.js +263 -0
- package/dist/cjs/features/soft_navigations/aggregate/initial-page-load-interaction.js +62 -0
- package/dist/cjs/features/soft_navigations/aggregate/interaction.js +146 -0
- package/dist/cjs/features/soft_navigations/constants.js +31 -0
- package/dist/cjs/features/soft_navigations/index.js +12 -0
- package/dist/cjs/features/soft_navigations/instrument/index.js +79 -0
- package/dist/cjs/features/spa/aggregate/index.js +4 -4
- package/dist/cjs/features/utils/agent-session.js +2 -1
- package/dist/cjs/features/utils/instrument-base.js +6 -9
- package/dist/cjs/features/utils/lazy-feature-loader.js +2 -0
- package/dist/cjs/loaders/agent-base.js +18 -3
- package/dist/cjs/loaders/agent.js +15 -18
- package/dist/cjs/loaders/api/api-methods.js +2 -1
- package/dist/cjs/loaders/api/api.js +14 -11
- package/dist/cjs/loaders/configure/configure.js +4 -1
- package/dist/cjs/loaders/features/enabled-features.js +1 -1
- package/dist/cjs/loaders/features/features.js +3 -1
- package/dist/esm/cdn/experimental.js +5 -2
- package/dist/esm/cdn/spa.js +3 -1
- package/dist/esm/common/aggregate/aggregator.js +1 -8
- package/dist/esm/common/config/state/init.js +7 -0
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/context/observation-context-manager.js +49 -0
- package/dist/esm/common/event-emitter/contextual-ee.js +12 -9
- package/dist/esm/common/session/constants.js +1 -0
- package/dist/esm/common/timing/nav-timing.js +8 -3
- package/dist/esm/common/timing/now.js +1 -1
- package/dist/esm/common/util/feature-flags.js +1 -1
- package/dist/esm/common/wrap/index.js +1 -2
- package/dist/esm/common/wrap/wrap-events.js +3 -3
- package/dist/esm/common/wrap/wrap-fetch.js +3 -2
- package/dist/esm/common/wrap/wrap-function.js +4 -5
- package/dist/esm/common/wrap/wrap-promise.js +3 -2
- package/dist/esm/features/ajax/aggregate/index.js +36 -18
- package/dist/esm/features/jserrors/aggregate/index.js +77 -66
- package/dist/esm/features/page_view_event/aggregate/index.js +1 -1
- package/dist/esm/features/page_view_event/aggregate/initialized-features.js +1 -0
- package/dist/esm/features/session_replay/aggregate/index.js +97 -95
- package/dist/esm/features/session_replay/constants.js +4 -0
- package/dist/esm/features/session_replay/instrument/index.js +25 -9
- package/dist/esm/features/session_replay/shared/utils.js +17 -0
- package/dist/esm/features/soft_navigations/aggregate/ajax-node.js +43 -0
- package/dist/esm/features/soft_navigations/aggregate/bel-node.js +22 -0
- package/dist/esm/features/soft_navigations/aggregate/index.js +256 -0
- package/dist/esm/features/soft_navigations/aggregate/initial-page-load-interaction.js +55 -0
- package/dist/esm/features/soft_navigations/aggregate/interaction.js +140 -0
- package/dist/esm/features/soft_navigations/constants.js +25 -0
- package/dist/esm/features/soft_navigations/index.js +1 -0
- package/dist/esm/features/soft_navigations/instrument/index.js +73 -0
- package/dist/esm/features/spa/aggregate/index.js +4 -4
- package/dist/esm/features/utils/agent-session.js +2 -1
- package/dist/esm/features/utils/instrument-base.js +7 -10
- package/dist/esm/features/utils/lazy-feature-loader.js +2 -0
- package/dist/esm/loaders/agent-base.js +18 -3
- package/dist/esm/loaders/agent.js +15 -18
- package/dist/esm/loaders/api/api-methods.js +2 -1
- package/dist/esm/loaders/api/api.js +14 -11
- package/dist/esm/loaders/configure/configure.js +4 -1
- package/dist/esm/loaders/features/enabled-features.js +1 -1
- package/dist/esm/loaders/features/features.js +3 -1
- package/dist/types/common/aggregate/aggregator.d.ts.map +1 -1
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- package/dist/types/common/context/event-context.d.ts.map +1 -0
- package/dist/types/common/context/observation-context-manager.d.ts +28 -0
- package/dist/types/common/context/observation-context-manager.d.ts.map +1 -0
- package/dist/types/common/event-emitter/contextual-ee.d.ts +2 -2
- package/dist/types/common/event-emitter/contextual-ee.d.ts.map +1 -1
- package/dist/types/common/session/constants.d.ts +1 -0
- package/dist/types/common/session/constants.d.ts.map +1 -1
- package/dist/types/common/timing/nav-timing.d.ts.map +1 -1
- package/dist/types/common/wrap/index.d.ts +1 -2
- package/dist/types/common/wrap/index.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-function.d.ts +0 -1
- package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-promise.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +4 -3
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/initialized-features.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/constants.d.ts +4 -0
- package/dist/types/features/session_replay/constants.d.ts.map +1 -1
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/utils.d.ts +4 -0
- package/dist/types/features/session_replay/shared/utils.d.ts.map +1 -0
- package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts +19 -0
- package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts.map +1 -0
- package/dist/types/features/soft_navigations/aggregate/bel-node.d.ts +16 -0
- package/dist/types/features/soft_navigations/aggregate/bel-node.d.ts.map +1 -0
- package/dist/types/features/soft_navigations/aggregate/index.d.ts +36 -0
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -0
- package/dist/types/features/soft_navigations/aggregate/initial-page-load-interaction.d.ts +12 -0
- package/dist/types/features/soft_navigations/aggregate/initial-page-load-interaction.d.ts.map +1 -0
- package/dist/types/features/soft_navigations/aggregate/interaction.d.ts +50 -0
- package/dist/types/features/soft_navigations/aggregate/interaction.d.ts.map +1 -0
- package/dist/types/features/soft_navigations/constants.d.ts +20 -0
- package/dist/types/features/soft_navigations/constants.d.ts.map +1 -0
- package/dist/types/features/soft_navigations/index.d.ts +2 -0
- package/dist/types/features/soft_navigations/index.d.ts.map +1 -0
- package/dist/types/features/soft_navigations/instrument/index.d.ts +7 -0
- package/dist/types/features/soft_navigations/instrument/index.d.ts.map +1 -0
- package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/agent-session.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts +1 -7
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/features/utils/lazy-feature-loader.d.ts.map +1 -1
- package/dist/types/loaders/agent-base.d.ts +5 -1
- package/dist/types/loaders/agent-base.d.ts.map +1 -1
- package/dist/types/loaders/agent.d.ts +2 -2
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/api/api-methods.d.ts.map +1 -1
- package/dist/types/loaders/api/api.d.ts +3 -5
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/dist/types/loaders/features/features.d.ts +1 -0
- package/dist/types/loaders/features/features.d.ts.map +1 -1
- package/dist/types/loaders/micro-agent.d.ts +0 -1
- package/dist/types/loaders/micro-agent.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cdn/experimental.js +4 -2
- package/src/cdn/spa.js +3 -1
- package/src/common/aggregate/aggregator.js +2 -11
- package/src/common/config/state/init.js +3 -1
- package/src/common/context/observation-context-manager.js +55 -0
- package/src/common/event-emitter/contextual-ee.js +20 -10
- package/src/common/session/constants.js +1 -0
- package/src/common/timing/nav-timing.js +7 -3
- package/src/common/timing/now.js +1 -1
- package/src/common/util/feature-flags.js +1 -1
- package/src/common/wrap/index.js +1 -2
- package/src/common/wrap/wrap-events.js +3 -3
- package/src/common/wrap/wrap-fetch.js +3 -2
- package/src/common/wrap/wrap-function.js +4 -6
- package/src/common/wrap/wrap-promise.js +3 -2
- package/src/features/ajax/aggregate/index.js +36 -18
- package/src/features/jserrors/aggregate/index.js +70 -73
- package/src/features/page_view_event/aggregate/index.js +1 -1
- package/src/features/page_view_event/aggregate/initialized-features.js +1 -0
- package/src/features/session_replay/aggregate/index.js +92 -95
- package/src/features/session_replay/constants.js +5 -0
- package/src/features/session_replay/instrument/index.js +24 -9
- package/src/features/session_replay/shared/utils.js +19 -0
- package/src/features/soft_navigations/aggregate/ajax-node.js +57 -0
- package/src/features/soft_navigations/aggregate/bel-node.js +26 -0
- package/src/features/soft_navigations/aggregate/index.js +254 -0
- package/src/features/soft_navigations/aggregate/initial-page-load-interaction.js +53 -0
- package/src/features/soft_navigations/aggregate/interaction.js +159 -0
- package/src/features/soft_navigations/constants.js +29 -0
- package/src/features/soft_navigations/index.js +1 -0
- package/src/features/soft_navigations/instrument/index.js +67 -0
- package/src/features/spa/aggregate/index.js +5 -4
- package/src/features/utils/agent-session.js +2 -1
- package/src/features/utils/instrument-base.js +7 -10
- package/src/features/utils/lazy-feature-loader.js +2 -0
- package/src/loaders/agent-base.js +18 -3
- package/src/loaders/agent.js +18 -17
- package/src/loaders/api/api-methods.js +4 -1
- package/src/loaders/api/api.js +14 -12
- package/src/loaders/configure/configure.js +4 -1
- package/src/loaders/features/enabled-features.js +1 -1
- package/src/loaders/features/features.js +3 -1
- package/dist/cjs/common/wrap/wrap-raf.js +0 -55
- package/dist/esm/common/wrap/wrap-raf.js +0 -48
- package/dist/types/common/event-emitter/event-context.d.ts.map +0 -1
- package/dist/types/common/wrap/wrap-raf.d.ts +0 -16
- package/dist/types/common/wrap/wrap-raf.d.ts.map +0 -1
- package/src/common/wrap/wrap-raf.js +0 -52
- /package/dist/cjs/common/{event-emitter → context}/event-context.js +0 -0
- /package/dist/esm/common/{event-emitter → context}/event-context.js +0 -0
- /package/dist/types/common/{event-emitter → context}/event-context.d.ts +0 -0
- /package/src/common/{event-emitter → context}/event-context.js +0 -0
|
@@ -25,7 +25,7 @@ var RESPONSE = 'response'
|
|
|
25
25
|
var LOAD_EVENT = 'loadEvent'
|
|
26
26
|
var DOM_CONTENT_LOAD_EVENT = 'domContentLoadedEvent'
|
|
27
27
|
|
|
28
|
-
export
|
|
28
|
+
export const navTimingValues = []
|
|
29
29
|
|
|
30
30
|
function getPntType (type) {
|
|
31
31
|
if (typeof type === 'number') return type
|
|
@@ -72,6 +72,10 @@ export function addPN (pn, v) {
|
|
|
72
72
|
return v
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* By side effect, this modifies 'obj' with a mapping of the 'prop' provided to a 'value', and invalid values are not added.
|
|
77
|
+
* On the other hand, the local navTimingValues array gets the value appended if valid and 'undefined' appended if invalid, regardless.
|
|
78
|
+
*/
|
|
75
79
|
function handleValue (value, obj, prop, isOldApi) {
|
|
76
80
|
/*
|
|
77
81
|
For L2 Timing API, the value will already be a relative-to-previous-document DOMHighResTimeStamp.
|
|
@@ -85,6 +89,6 @@ function handleValue (value, obj, prop, isOldApi) {
|
|
|
85
89
|
}
|
|
86
90
|
value = Math.round(value)
|
|
87
91
|
obj[prop] = value
|
|
88
|
-
|
|
89
|
-
navTimingValues.push(
|
|
92
|
+
navTimingValues.push(value)
|
|
93
|
+
} else navTimingValues.push(undefined)
|
|
90
94
|
}
|
package/src/common/timing/now.js
CHANGED
|
@@ -11,7 +11,7 @@ const bucketMap = {
|
|
|
11
11
|
stn: [FEATURE_NAMES.sessionTrace],
|
|
12
12
|
err: [FEATURE_NAMES.jserrors, FEATURE_NAMES.metrics],
|
|
13
13
|
ins: [FEATURE_NAMES.pageAction],
|
|
14
|
-
spa: [FEATURE_NAMES.spa],
|
|
14
|
+
spa: [FEATURE_NAMES.spa, FEATURE_NAMES.softNav],
|
|
15
15
|
sr: [FEATURE_NAMES.sessionReplay, FEATURE_NAMES.sessionTrace]
|
|
16
16
|
}
|
|
17
17
|
|
package/src/common/wrap/index.js
CHANGED
|
@@ -8,10 +8,9 @@ import { wrapHistory } from './wrap-history'
|
|
|
8
8
|
import { wrapJsonP } from './wrap-jsonp'
|
|
9
9
|
import { wrapMutation } from './wrap-mutation'
|
|
10
10
|
import { wrapPromise } from './wrap-promise'
|
|
11
|
-
import { wrapRaf } from './wrap-raf'
|
|
12
11
|
import { wrapTimer } from './wrap-timer'
|
|
13
12
|
import { wrapXhr } from './wrap-xhr'
|
|
14
13
|
|
|
15
14
|
export {
|
|
16
|
-
wrapEvents, wrapFetch, wrapHistory, wrapJsonP, wrapMutation, wrapPromise,
|
|
15
|
+
wrapEvents, wrapFetch, wrapHistory, wrapJsonP, wrapMutation, wrapPromise, wrapTimer, wrapXhr
|
|
17
16
|
}
|
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
* This module is used directly by: session_trace.
|
|
8
8
|
* It is also called by -> wrapXhr <-, so see "wrap-xhr.js" for features that use this indirectly.
|
|
9
9
|
*/
|
|
10
|
-
import { ee as baseEE
|
|
10
|
+
import { ee as baseEE } from '../event-emitter/contextual-ee'
|
|
11
11
|
import { createWrapperWithEmitter as wfn } from './wrap-function'
|
|
12
12
|
import { getOrSet } from '../util/get-or-set'
|
|
13
13
|
import { globalScope, isBrowserScope } from '../constants/runtime'
|
|
14
|
+
import { ObservationContextManager } from '../context/observation-context-manager'
|
|
14
15
|
|
|
15
16
|
const wrapped = {}
|
|
16
17
|
const XHR = globalScope.XMLHttpRequest
|
|
17
18
|
const ADD_EVENT_LISTENER = 'addEventListener'
|
|
18
19
|
const REMOVE_EVENT_LISTENER = 'removeEventListener'
|
|
19
|
-
const flag = `nr@wrapped:${contextId}`
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Wraps `addEventListener` and `removeEventListener` on: global scope; the prototype of `XMLHttpRequest`, and
|
|
@@ -49,7 +49,7 @@ export function wrapEvents (sharedEE) {
|
|
|
49
49
|
return
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
var wrapped = getOrSet(originalListener,
|
|
52
|
+
var wrapped = getOrSet(originalListener, ObservationContextManager.contextWrappedId, function () {
|
|
53
53
|
var listener = {
|
|
54
54
|
object: wrapHandleEvent,
|
|
55
55
|
function: originalListener
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* @file Wraps `fetch` and related methods for instrumentation.
|
|
7
7
|
* This module is used by: ajax, spa.
|
|
8
8
|
*/
|
|
9
|
-
import { ee as baseEE
|
|
9
|
+
import { ee as baseEE } from '../event-emitter/contextual-ee'
|
|
10
10
|
import { globalScope } from '../constants/runtime'
|
|
11
|
+
import { ObservationContextManager } from '../context/observation-context-manager'
|
|
11
12
|
|
|
12
13
|
var prefix = 'fetch-'
|
|
13
14
|
var bodyPrefix = prefix + 'body-'
|
|
@@ -74,7 +75,7 @@ export function wrapFetch (sharedEE) {
|
|
|
74
75
|
// we are wrapping args in an array so we can preserve the reference
|
|
75
76
|
ee.emit(prefix + 'before-start', [args], ctx)
|
|
76
77
|
var dtPayload
|
|
77
|
-
if (ctx[contextId] && ctx[contextId].dt) dtPayload = ctx[contextId].dt
|
|
78
|
+
if (ctx[ObservationContextManager.contextId] && ctx[ObservationContextManager.contextId].dt) dtPayload = ctx[ObservationContextManager.contextId].dt
|
|
78
79
|
|
|
79
80
|
var origPromiseFromFetch = fn.apply(this, args)
|
|
80
81
|
|
|
@@ -7,9 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { ee } from '../event-emitter/contextual-ee'
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
export const flag = `nr@original:${bundleId}`
|
|
10
|
+
import { ObservationContextManager } from '../context/observation-context-manager'
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* A convenience alias of `hasOwnProperty`.
|
|
@@ -42,7 +40,7 @@ export function createWrapperWithEmitter (emitter, always) {
|
|
|
42
40
|
* As a property on a wrapped function, contains the original function.
|
|
43
41
|
* @type {string}
|
|
44
42
|
*/
|
|
45
|
-
wrapFn.flag =
|
|
43
|
+
wrapFn.flag = ObservationContextManager.contextOriginalId
|
|
46
44
|
|
|
47
45
|
return wrapFn
|
|
48
46
|
|
|
@@ -61,7 +59,7 @@ export function createWrapperWithEmitter (emitter, always) {
|
|
|
61
59
|
|
|
62
60
|
if (!prefix) prefix = ''
|
|
63
61
|
|
|
64
|
-
nrWrapper[
|
|
62
|
+
nrWrapper[ObservationContextManager.contextOriginalId] = fn
|
|
65
63
|
copy(fn, nrWrapper, emitter)
|
|
66
64
|
return nrWrapper
|
|
67
65
|
|
|
@@ -215,5 +213,5 @@ function copy (from, to, emitter) {
|
|
|
215
213
|
* @returns {boolean} Whether the passed function is ineligible to be wrapped.
|
|
216
214
|
*/
|
|
217
215
|
function notWrappable (fn) {
|
|
218
|
-
return !(fn && typeof fn === 'function' && fn.apply && !fn[
|
|
216
|
+
return !(fn && typeof fn === 'function' && fn.apply && !fn[ObservationContextManager.contextOriginalId])
|
|
219
217
|
}
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
* This module is used by: spa.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { createWrapperWithEmitter as wrapFn
|
|
10
|
+
import { createWrapperWithEmitter as wrapFn } from './wrap-function'
|
|
11
11
|
import { ee as baseEE } from '../event-emitter/contextual-ee'
|
|
12
12
|
import { globalScope } from '../constants/runtime'
|
|
13
|
+
import { ObservationContextManager } from '../context/observation-context-manager'
|
|
13
14
|
|
|
14
15
|
const wrapped = {}
|
|
15
16
|
|
|
@@ -122,7 +123,7 @@ export function wrapPromise (sharedEE) {
|
|
|
122
123
|
|
|
123
124
|
return origFnCallWithThis
|
|
124
125
|
}
|
|
125
|
-
prevPromiseObj.prototype.then[
|
|
126
|
+
prevPromiseObj.prototype.then[ObservationContextManager.contextOriginalId] = prevPromiseOrigThen
|
|
126
127
|
|
|
127
128
|
promiseEE.on('executor-start', function (args) {
|
|
128
129
|
args[0] = promiseWrapper(args[0], 'resolve-', this, null, false)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
import { registerHandler
|
|
5
|
+
import { registerHandler } from '../../../common/event-emitter/register-handler'
|
|
6
6
|
import { stringify } from '../../../common/util/stringify'
|
|
7
7
|
import { nullable, numeric, getAddStringContext, addCustomAttributes } from '../../../common/serialize/bel-serializer'
|
|
8
8
|
import { handle } from '../../../common/event-emitter/handle'
|
|
@@ -14,6 +14,7 @@ import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
|
14
14
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
15
15
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
16
16
|
import { parseGQL } from './gql'
|
|
17
|
+
import { getNREUMInitializedAgent } from '../../../common/window/nreum'
|
|
17
18
|
|
|
18
19
|
export class Aggregate extends AggregateBase {
|
|
19
20
|
static featureName = FEATURE_NAME
|
|
@@ -22,7 +23,7 @@ export class Aggregate extends AggregateBase {
|
|
|
22
23
|
const agentInit = getConfiguration(agentIdentifier)
|
|
23
24
|
const allAjaxIsEnabled = agentInit.ajax.enabled !== false
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
registerHandler('xhr', storeXhr, this.featureName, this.ee)
|
|
26
27
|
if (!allAjaxIsEnabled) {
|
|
27
28
|
this.drain()
|
|
28
29
|
return // feature will only collect timeslice metrics & ajax trace nodes if it's not fully enabled
|
|
@@ -44,20 +45,21 @@ export class Aggregate extends AggregateBase {
|
|
|
44
45
|
this.prepareHarvest = prepareHarvest
|
|
45
46
|
this.getStoredEvents = function () { return { ajaxEvents, spaAjaxEvents } }
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// remove from the spaAjaxEvents buffer, and let spa harvest it
|
|
50
|
-
delete spaAjaxEvents[interaction.id]
|
|
51
|
-
})
|
|
52
|
-
ee.on('interactionDiscarded', (interaction) => {
|
|
48
|
+
// --- v Used by old spa feature
|
|
49
|
+
ee.on('interactionDone', (interaction, wasSaved) => {
|
|
53
50
|
if (!spaAjaxEvents[interaction.id]) return
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
if (!wasSaved) { // if the ixn was saved, then its ajax reqs are part of the payload whereas if it was discarded, it should still be harvested in the ajax feature itself
|
|
53
|
+
spaAjaxEvents[interaction.id].forEach(function (item) {
|
|
54
|
+
ajaxEvents.push(item)
|
|
55
|
+
})
|
|
56
|
+
}
|
|
59
57
|
delete spaAjaxEvents[interaction.id]
|
|
60
58
|
})
|
|
59
|
+
// --- ^
|
|
60
|
+
// --- v Used by new soft nav
|
|
61
|
+
registerHandler('returnAjax', event => ajaxEvents.push(event), this.featureName, this.ee)
|
|
62
|
+
// --- ^
|
|
61
63
|
|
|
62
64
|
const scheduler = new HarvestScheduler('events', {
|
|
63
65
|
onFinished: onEventsHarvestFinished,
|
|
@@ -82,17 +84,30 @@ export class Aggregate extends AggregateBase {
|
|
|
82
84
|
hash = stringify([params.status, params.host, params.pathname])
|
|
83
85
|
}
|
|
84
86
|
|
|
87
|
+
const shouldCollect = shouldCollectEvent(params)
|
|
88
|
+
const ajaxMetricDenyListEnabled = agentInit.feature_flags?.includes('ajax_metrics_deny_list')
|
|
89
|
+
|
|
85
90
|
// store as metric
|
|
86
|
-
|
|
91
|
+
if (shouldCollect || !ajaxMetricDenyListEnabled) {
|
|
92
|
+
aggregator.store('xhr', hash, params, metrics)
|
|
93
|
+
}
|
|
87
94
|
|
|
88
95
|
if (!allAjaxIsEnabled) return
|
|
89
96
|
|
|
90
|
-
if (!
|
|
97
|
+
if (!shouldCollect) {
|
|
91
98
|
if (params.hostname === beacon || (proxyBeacon && params.hostname === proxyBeacon)) {
|
|
92
99
|
// This doesn't make a distinction if the same-domain request is going to a different port or path...
|
|
93
100
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Ajax/Events/Excluded/Agent'], undefined, FEATURE_NAMES.metrics, ee)
|
|
101
|
+
|
|
102
|
+
if (ajaxMetricDenyListEnabled) {
|
|
103
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Ajax/Metrics/Excluded/Agent'], undefined, FEATURE_NAMES.metrics, ee)
|
|
104
|
+
}
|
|
94
105
|
} else {
|
|
95
106
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Ajax/Events/Excluded/App'], undefined, FEATURE_NAMES.metrics, ee)
|
|
107
|
+
|
|
108
|
+
if (ajaxMetricDenyListEnabled) {
|
|
109
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['Ajax/Metrics/Excluded/App'], undefined, FEATURE_NAMES.metrics, ee)
|
|
110
|
+
}
|
|
96
111
|
}
|
|
97
112
|
return
|
|
98
113
|
}
|
|
@@ -125,12 +140,14 @@ export class Aggregate extends AggregateBase {
|
|
|
125
140
|
body: this.body,
|
|
126
141
|
query: this?.parsedOrigin?.search
|
|
127
142
|
})
|
|
128
|
-
|
|
129
143
|
if (event.gql) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Ajax/Events/GraphQL/Bytes-Added', stringify(event.gql).length], undefined, FEATURE_NAMES.metrics, ee)
|
|
130
144
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
145
|
+
const softNavInUse = Boolean(getNREUMInitializedAgent(agentIdentifier)?.features?.[FEATURE_NAMES.softNav])
|
|
146
|
+
|
|
147
|
+
if (softNavInUse) { // For newer soft nav (when running), pass the event to it for evaluation -- either part of an interaction or is given back
|
|
148
|
+
handle('ajax', [event], undefined, FEATURE_NAMES.softNav, ee)
|
|
149
|
+
} else if (this.spaNode) { // For old spa (when running), if the ajax happened inside an interaction, hold it until the interaction finishes
|
|
150
|
+
const interactionId = this.spaNode.interaction.id
|
|
134
151
|
spaAjaxEvents[interactionId] = spaAjaxEvents[interactionId] || []
|
|
135
152
|
spaAjaxEvents[interactionId].push(event)
|
|
136
153
|
} else {
|
|
@@ -209,6 +226,7 @@ export class Aggregate extends AggregateBase {
|
|
|
209
226
|
|
|
210
227
|
for (var i = 0; i < events.length; i++) {
|
|
211
228
|
var event = events[i]
|
|
229
|
+
|
|
212
230
|
var fields = [
|
|
213
231
|
numeric(event.startTime),
|
|
214
232
|
numeric(event.endTime - event.startTime),
|
|
@@ -20,6 +20,7 @@ import { globalScope } from '../../../common/constants/runtime'
|
|
|
20
20
|
import { FEATURE_NAME } from '../constants'
|
|
21
21
|
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
22
22
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
23
|
+
import { getNREUMInitializedAgent } from '../../../common/window/nreum'
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* @typedef {import('./compute-stack-trace.js').StackInfo} StackInfo
|
|
@@ -33,18 +34,17 @@ export class Aggregate extends AggregateBase {
|
|
|
33
34
|
this.stackReported = {}
|
|
34
35
|
this.observedAt = {}
|
|
35
36
|
this.pageviewReported = {}
|
|
36
|
-
this.
|
|
37
|
+
this.bufferedErrorsUnderSpa = {}
|
|
37
38
|
this.currentBody = undefined
|
|
38
39
|
this.errorOnPage = false
|
|
39
40
|
|
|
40
41
|
// this will need to change to match whatever ee we use in the instrument
|
|
41
|
-
this.ee.on('
|
|
42
|
-
|
|
43
|
-
// this will need to change to match whatever ee we use in the instrument
|
|
44
|
-
this.ee.on('interactionDiscarded', (interaction) => this.onInteractionDiscarded(interaction))
|
|
42
|
+
this.ee.on('interactionDone', (interaction, wasSaved) => this.onInteractionDone(interaction, wasSaved))
|
|
45
43
|
|
|
46
44
|
register('err', (...args) => this.storeError(...args), this.featureName, this.ee)
|
|
47
45
|
register('ierr', (...args) => this.storeError(...args), this.featureName, this.ee)
|
|
46
|
+
register('softNavFlush', (interactionId, wasFinished, softNavAttrs) =>
|
|
47
|
+
this.onSoftNavNotification(interactionId, wasFinished, softNavAttrs), this.featureName, this.ee) // when an ixn is done or cancelled
|
|
48
48
|
|
|
49
49
|
const harvestTimeSeconds = getConfigurationValue(this.agentIdentifier, 'jserrors.harvestTimeSeconds') || 10
|
|
50
50
|
|
|
@@ -197,98 +197,95 @@ export class Aggregate extends AggregateBase {
|
|
|
197
197
|
var type = internal ? 'ierr' : 'err'
|
|
198
198
|
var newMetrics = { time }
|
|
199
199
|
|
|
200
|
-
//
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
handle('errorAgg',
|
|
204
|
-
handle('errorAgg', msg, undefined, FEATURE_NAMES.spa, this.ee)
|
|
205
|
-
handle('errorAgg', msg, undefined, FEATURE_NAMES.sessionReplay, this.ee)
|
|
206
|
-
|
|
200
|
+
// Trace sends the error in its payload, and both trace & replay simply listens for any error to occur.
|
|
201
|
+
const jsErrorEvent = [type, bucketHash, params, newMetrics, customAttributes]
|
|
202
|
+
handle('errorAgg', jsErrorEvent, undefined, FEATURE_NAMES.sessionTrace, this.ee)
|
|
203
|
+
handle('errorAgg', jsErrorEvent, undefined, FEATURE_NAMES.sessionReplay, this.ee)
|
|
207
204
|
// still send EE events for other features such as above, but stop this one from aggregating internal data
|
|
208
205
|
if (this.blocked) return
|
|
209
|
-
var att = getInfo(this.agentIdentifier).jsAttributes
|
|
210
|
-
if (params._interactionId != null) {
|
|
211
|
-
// hold on to the error until the interaction finishes
|
|
212
|
-
this.errorCache[params._interactionId] = this.errorCache[params._interactionId] || []
|
|
213
|
-
this.errorCache[params._interactionId].push([type, bucketHash, params, newMetrics, att, customAttributes])
|
|
214
|
-
} else {
|
|
215
|
-
// store custom attributes
|
|
216
|
-
var customParams = {}
|
|
217
|
-
mapOwn(att, setCustom)
|
|
218
|
-
if (customAttributes) {
|
|
219
|
-
mapOwn(customAttributes, setCustom)
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
var jsAttributesHash = stringHashCode(stringify(customParams))
|
|
223
|
-
var aggregateHash = bucketHash + ':' + jsAttributesHash
|
|
224
|
-
this.aggregator.store(type, aggregateHash, params, newMetrics, customParams)
|
|
225
|
-
}
|
|
226
206
|
|
|
227
|
-
|
|
228
|
-
|
|
207
|
+
const softNavInUse = Boolean(getNREUMInitializedAgent(this.agentIdentifier)?.features[FEATURE_NAMES.softNav])
|
|
208
|
+
// Note: the following are subject to potential race cond wherein if the other feature aren't fully initialized, it'll be treated as there being no associated interaction.
|
|
209
|
+
// They each will also tack on their respective properties to the params object as part of the decision flow.
|
|
210
|
+
if (softNavInUse) handle('jserror', [params, time], undefined, FEATURE_NAMES.softNav, this.ee)
|
|
211
|
+
else handle('errorAgg', jsErrorEvent, undefined, FEATURE_NAMES.spa, this.ee)
|
|
212
|
+
|
|
213
|
+
if (params.browserInteractionId && !params._softNavFinished) { // hold onto the error until the in-progress interaction is done, eithered saved or discarded
|
|
214
|
+
this.bufferedErrorsUnderSpa[params.browserInteractionId] ??= []
|
|
215
|
+
this.bufferedErrorsUnderSpa[params.browserInteractionId].push(jsErrorEvent)
|
|
216
|
+
} else if (params._interactionId != null) { // same as above, except tailored for the way old spa does it
|
|
217
|
+
this.bufferedErrorsUnderSpa[params._interactionId] = this.bufferedErrorsUnderSpa[params._interactionId] || []
|
|
218
|
+
this.bufferedErrorsUnderSpa[params._interactionId].push(jsErrorEvent)
|
|
219
|
+
} else {
|
|
220
|
+
// Either there is no interaction (then all these params properties will be undefined) OR there's a related soft navigation that's already completed.
|
|
221
|
+
// The old spa does not look up completed interactions at all, so there's no need to consider it.
|
|
222
|
+
this.#storeJserrorForHarvest(jsErrorEvent, params.browserInteractionId !== undefined, params._softNavAttributes)
|
|
229
223
|
}
|
|
230
224
|
}
|
|
231
225
|
|
|
232
|
-
|
|
233
|
-
|
|
226
|
+
#storeJserrorForHarvest (errorInfoArr, softNavOccurredFinished, softNavCustomAttrs = {}) {
|
|
227
|
+
let [type, bucketHash, params, newMetrics, localAttrs] = errorInfoArr
|
|
228
|
+
const allCustomAttrs = {}
|
|
234
229
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
var localCustomParams = item[5]
|
|
230
|
+
if (softNavOccurredFinished) {
|
|
231
|
+
Object.entries(softNavCustomAttrs).forEach(([k, v]) => setCustom(k, v)) // when an ixn finishes, it'll include stuff in jsAttributes + attrs specific to the ixn
|
|
232
|
+
bucketHash += params.browserInteractionId
|
|
239
233
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (params._interactionNodeId) {
|
|
249
|
-
params.parentNodeId = params._interactionNodeId.toString()
|
|
250
|
-
delete params._interactionNodeId
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
var hash = item[1] + interaction.root.attrs.id
|
|
254
|
-
var jsAttributesHash = stringHashCode(stringify(customParams))
|
|
255
|
-
var aggregateHash = hash + ':' + jsAttributesHash
|
|
234
|
+
delete params._softNavAttributes // cleanup temp properties from synchronous evaluation; this is harmless when async from soft nav (properties DNE)
|
|
235
|
+
delete params._softNavFinished
|
|
236
|
+
} else { // interaction was cancelled -> error should not be associated OR there was no interaction
|
|
237
|
+
Object.entries(getInfo(this.agentIdentifier).jsAttributes).forEach(([k, v]) => setCustom(k, v))
|
|
238
|
+
delete params.browserInteractionId
|
|
239
|
+
}
|
|
240
|
+
if (localAttrs) Object.entries(localAttrs).forEach(([k, v]) => setCustom(k, v)) // local custom attrs are applied in either case with the highest precedence
|
|
256
241
|
|
|
257
|
-
|
|
242
|
+
const jsAttributesHash = stringHashCode(stringify(allCustomAttrs))
|
|
243
|
+
const aggregateHash = bucketHash + ':' + jsAttributesHash
|
|
244
|
+
this.aggregator.store(type, aggregateHash, params, newMetrics, allCustomAttrs)
|
|
258
245
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
})
|
|
263
|
-
delete this.errorCache[interaction.id]
|
|
246
|
+
function setCustom (key, val) {
|
|
247
|
+
allCustomAttrs[key] = (val && typeof val === 'object' ? stringify(val) : val)
|
|
248
|
+
}
|
|
264
249
|
}
|
|
265
250
|
|
|
266
|
-
|
|
267
|
-
|
|
251
|
+
// TO-DO: Remove this function when old spa is taken out. #storeJserrorForHarvest handles the work with the softnav feature.
|
|
252
|
+
onInteractionDone (interaction, wasSaved) {
|
|
253
|
+
if (!this.bufferedErrorsUnderSpa[interaction.id] || this.blocked) return
|
|
268
254
|
|
|
269
|
-
this.
|
|
270
|
-
var
|
|
271
|
-
|
|
272
|
-
var localCustomParams = item[5]
|
|
255
|
+
this.bufferedErrorsUnderSpa[interaction.id].forEach((item) => {
|
|
256
|
+
var allCustomAttrs = {}
|
|
257
|
+
const localCustomAttrs = item[4]
|
|
273
258
|
|
|
274
|
-
mapOwn(
|
|
275
|
-
mapOwn(
|
|
276
|
-
mapOwn(localCustomParams, setCustom)
|
|
259
|
+
mapOwn(interaction.root.attrs.custom, setCustom) // tack on custom attrs from the interaction
|
|
260
|
+
mapOwn(localCustomAttrs, setCustom)
|
|
277
261
|
|
|
278
262
|
var params = item[2]
|
|
263
|
+
if (wasSaved) {
|
|
264
|
+
params.browserInteractionId = interaction.root.attrs.id
|
|
265
|
+
if (params._interactionNodeId) params.parentNodeId = params._interactionNodeId.toString()
|
|
266
|
+
}
|
|
279
267
|
delete params._interactionId
|
|
280
268
|
delete params._interactionNodeId
|
|
281
269
|
|
|
282
|
-
var hash = item[1]
|
|
283
|
-
var jsAttributesHash = stringHashCode(stringify(
|
|
270
|
+
var hash = wasSaved ? item[1] + interaction.root.attrs.id : item[1]
|
|
271
|
+
var jsAttributesHash = stringHashCode(stringify(allCustomAttrs))
|
|
284
272
|
var aggregateHash = hash + ':' + jsAttributesHash
|
|
285
273
|
|
|
286
|
-
this.aggregator.store(item[0], aggregateHash,
|
|
274
|
+
this.aggregator.store(item[0], aggregateHash, params, item[3], allCustomAttrs)
|
|
287
275
|
|
|
288
276
|
function setCustom (key, val) {
|
|
289
|
-
|
|
277
|
+
allCustomAttrs[key] = (val && typeof val === 'object' ? stringify(val) : val)
|
|
290
278
|
}
|
|
291
279
|
})
|
|
292
|
-
delete this.
|
|
280
|
+
delete this.bufferedErrorsUnderSpa[interaction.id]
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
onSoftNavNotification (interactionId, wasFinished, softNavAttrs) {
|
|
284
|
+
if (this.blocked) return
|
|
285
|
+
|
|
286
|
+
this.bufferedErrorsUnderSpa[interactionId]?.forEach(jsErrorEvent =>
|
|
287
|
+
this.#storeJserrorForHarvest(jsErrorEvent, wasFinished, softNavAttrs) // this should not modify the re-used softNavAttrs contents
|
|
288
|
+
)
|
|
289
|
+
delete this.bufferedErrorsUnderSpa[interactionId] // wipe the list of jserrors so they aren't duplicated by another call to the same id
|
|
293
290
|
}
|
|
294
291
|
}
|