@newrelic/browser-agent 1.286.0 → 1.287.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 +7 -0
- package/dist/cjs/common/config/init-types.js +96 -0
- package/dist/cjs/common/config/init.js +9 -79
- package/dist/cjs/common/config/runtime.js +7 -6
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/harvest/harvester.js +2 -2
- package/dist/cjs/common/util/feature-flags.js +4 -5
- package/dist/cjs/common/util/target.js +34 -0
- package/dist/cjs/features/ajax/aggregate/index.js +2 -1
- package/dist/cjs/features/generic_events/aggregate/index.js +10 -6
- package/dist/cjs/features/jserrors/aggregate/index.js +44 -22
- package/dist/cjs/features/logging/aggregate/index.js +17 -11
- package/dist/cjs/features/logging/shared/utils.js +3 -2
- package/dist/cjs/features/metrics/aggregate/index.js +6 -4
- package/dist/cjs/features/page_view_event/aggregate/index.js +60 -11
- package/dist/cjs/features/page_view_event/instrument/index.js +4 -0
- package/dist/cjs/features/session_replay/aggregate/index.js +8 -6
- package/dist/cjs/features/session_replay/instrument/index.js +1 -1
- package/dist/cjs/features/session_replay/shared/recorder-events.js +4 -2
- package/dist/cjs/features/session_replay/shared/recorder.js +12 -11
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +1 -1
- package/dist/cjs/features/soft_navigations/aggregate/index.js +12 -2
- package/dist/cjs/features/spa/aggregate/index.js +3 -3
- package/dist/cjs/features/spa/aggregate/interaction.js +6 -9
- package/dist/cjs/features/utils/aggregate-base.js +49 -20
- package/dist/cjs/features/utils/entity-manager.js +47 -0
- package/dist/cjs/features/utils/event-store-manager.js +79 -54
- package/dist/cjs/interfaces/registered-entity.js +114 -0
- package/dist/cjs/loaders/api/api-methods.js +1 -1
- package/dist/cjs/loaders/api/api.js +50 -18
- package/dist/cjs/loaders/api/register-api-types.js +35 -0
- package/dist/cjs/loaders/api/register-api.js +165 -0
- package/dist/cjs/loaders/micro-agent-base.js +16 -0
- package/dist/cjs/loaders/micro-agent.js +1 -0
- package/dist/esm/common/config/init-types.js +92 -0
- package/dist/esm/common/config/init.js +9 -79
- package/dist/esm/common/config/runtime.js +7 -6
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/harvest/harvester.js +2 -2
- package/dist/esm/common/util/feature-flags.js +4 -5
- package/dist/esm/common/util/target.js +27 -0
- package/dist/esm/features/ajax/aggregate/index.js +2 -1
- package/dist/esm/features/generic_events/aggregate/index.js +10 -6
- package/dist/esm/features/jserrors/aggregate/index.js +44 -22
- package/dist/esm/features/logging/aggregate/index.js +17 -11
- package/dist/esm/features/logging/shared/utils.js +3 -2
- package/dist/esm/features/metrics/aggregate/index.js +6 -4
- package/dist/esm/features/page_view_event/aggregate/index.js +60 -11
- package/dist/esm/features/page_view_event/instrument/index.js +4 -0
- package/dist/esm/features/session_replay/aggregate/index.js +8 -6
- package/dist/esm/features/session_replay/instrument/index.js +1 -1
- package/dist/esm/features/session_replay/shared/recorder-events.js +4 -2
- package/dist/esm/features/session_replay/shared/recorder.js +12 -11
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +1 -1
- package/dist/esm/features/soft_navigations/aggregate/index.js +12 -2
- package/dist/esm/features/spa/aggregate/index.js +3 -3
- package/dist/esm/features/spa/aggregate/interaction.js +6 -9
- package/dist/esm/features/utils/aggregate-base.js +49 -20
- package/dist/esm/features/utils/entity-manager.js +40 -0
- package/dist/esm/features/utils/event-store-manager.js +79 -54
- package/dist/esm/interfaces/registered-entity.js +107 -0
- package/dist/esm/loaders/api/api-methods.js +1 -1
- package/dist/esm/loaders/api/api.js +50 -18
- package/dist/esm/loaders/api/register-api-types.js +33 -0
- package/dist/esm/loaders/api/register-api.js +159 -0
- package/dist/esm/loaders/micro-agent-base.js +16 -0
- package/dist/esm/loaders/micro-agent.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/config/init-types.d.ts +275 -0
- package/dist/types/common/config/init-types.d.ts.map +1 -0
- package/dist/types/common/config/init.d.ts +1 -262
- package/dist/types/common/config/init.d.ts.map +1 -1
- package/dist/types/common/config/runtime.d.ts.map +1 -1
- package/dist/types/common/util/feature-flags.d.ts +1 -1
- package/dist/types/common/util/feature-flags.d.ts.map +1 -1
- package/dist/types/common/util/target.d.ts +18 -0
- package/dist/types/common/util/target.d.ts.map +1 -0
- package/dist/types/features/ajax/aggregate/index.d.ts +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts +2 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +9 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts +3 -3
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/logging/shared/utils.d.ts +2 -1
- package/dist/types/features/logging/shared/utils.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts +1 -0
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +10 -2
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +2 -11
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder-events.d.ts +1 -0
- package/dist/types/features/session_replay/shared/recorder-events.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts +4 -4
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/interaction.d.ts +3 -4
- package/dist/types/features/spa/aggregate/interaction.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +22 -5
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/entity-manager.d.ts +15 -0
- package/dist/types/features/utils/entity-manager.d.ts.map +1 -0
- package/dist/types/features/utils/event-store-manager.d.ts +48 -24
- package/dist/types/features/utils/event-store-manager.d.ts.map +1 -1
- package/dist/types/interfaces/registered-entity.d.ts +72 -0
- package/dist/types/interfaces/registered-entity.d.ts.map +1 -0
- package/dist/types/loaders/agent.d.ts +1 -1
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/dist/types/loaders/api/register-api-types.d.ts +56 -0
- package/dist/types/loaders/api/register-api-types.d.ts.map +1 -0
- package/dist/types/loaders/api/register-api.d.ts +14 -0
- package/dist/types/loaders/api/register-api.d.ts.map +1 -0
- package/dist/types/loaders/micro-agent-base.d.ts +17 -0
- package/dist/types/loaders/micro-agent-base.d.ts.map +1 -1
- package/dist/types/loaders/micro-agent.d.ts +1 -0
- package/dist/types/loaders/micro-agent.d.ts.map +1 -1
- package/package.json +10 -1
- package/src/common/config/init-types.js +92 -0
- package/src/common/config/init.js +9 -79
- package/src/common/config/runtime.js +7 -6
- package/src/common/harvest/harvester.js +2 -2
- package/src/common/util/feature-flags.js +4 -5
- package/src/common/util/target.js +27 -0
- package/src/features/ajax/aggregate/index.js +2 -1
- package/src/features/generic_events/aggregate/index.js +8 -6
- package/src/features/jserrors/aggregate/index.js +42 -20
- package/src/features/logging/aggregate/index.js +14 -10
- package/src/features/logging/shared/utils.js +3 -2
- package/src/features/metrics/aggregate/index.js +7 -5
- package/src/features/page_view_event/aggregate/index.js +50 -8
- package/src/features/page_view_event/instrument/index.js +4 -0
- package/src/features/session_replay/aggregate/index.js +6 -3
- package/src/features/session_replay/instrument/index.js +1 -1
- package/src/features/session_replay/shared/recorder-events.js +5 -2
- package/src/features/session_replay/shared/recorder.js +12 -11
- package/src/features/session_trace/aggregate/trace/storage.js +1 -1
- package/src/features/soft_navigations/aggregate/index.js +11 -2
- package/src/features/spa/aggregate/index.js +3 -3
- package/src/features/spa/aggregate/interaction.js +6 -9
- package/src/features/utils/aggregate-base.js +54 -22
- package/src/features/utils/entity-manager.js +45 -0
- package/src/features/utils/event-store-manager.js +72 -49
- package/src/interfaces/registered-entity.js +107 -0
- package/src/loaders/api/api-methods.js +1 -1
- package/src/loaders/api/api.js +49 -13
- package/src/loaders/api/register-api-types.js +33 -0
- package/src/loaders/api/register-api.js +152 -0
- package/src/loaders/micro-agent-base.js +16 -0
- package/src/loaders/micro-agent.js +1 -0
|
@@ -20,10 +20,11 @@ var _constants2 = require("../constants");
|
|
|
20
20
|
* @param {string} message - the log message string
|
|
21
21
|
* @param {{[key: string]: *}} customAttributes - The log's custom attributes if any
|
|
22
22
|
* @param {enum} level - the log level enum
|
|
23
|
+
* @param {object=} targetEntityGuid - the optional target entity guid provided by an api call
|
|
23
24
|
*/
|
|
24
|
-
function bufferLog(ee, message, customAttributes = {}, level = _constants2.LOG_LEVELS.INFO) {
|
|
25
|
+
function bufferLog(ee, message, customAttributes = {}, level = _constants2.LOG_LEVELS.INFO, targetEntityGuid, timestamp = (0, _now.now)()) {
|
|
25
26
|
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ["API/logging/".concat(level.toLowerCase(), "/called")], undefined, _features.FEATURE_NAMES.metrics, ee);
|
|
26
|
-
(0, _handle.handle)(_constants2.LOGGING_EVENT_EMITTER_CHANNEL, [
|
|
27
|
+
(0, _handle.handle)(_constants2.LOGGING_EVENT_EMITTER_CHANNEL, [timestamp, message, customAttributes, level, targetEntityGuid], undefined, _features.FEATURE_NAMES.logging, ee);
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -28,8 +28,13 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
28
28
|
this.harvestOpts.aggregatorTypes = ['cm', 'sm']; // the types in EventAggregator this feature cares about
|
|
29
29
|
// This feature only harvests once per potential EoL of the page, which is handled by the central harvester.
|
|
30
30
|
|
|
31
|
+
// this must be read/stored synchronously, as the currentScript is removed from the DOM after this script is executed and this lookup will be void
|
|
32
|
+
// its used to report a SM later in the lifecycle
|
|
33
|
+
this.agentNonce = _runtime.isBrowserScope && document.currentScript?.nonce;
|
|
31
34
|
this.waitForFlags(['err']).then(([errFlag]) => {
|
|
32
35
|
if (errFlag) {
|
|
36
|
+
this.singleChecks(); // checks that are run only one time, at script load
|
|
37
|
+
this.eachSessionChecks(); // the start of every time user engages with page
|
|
33
38
|
this.drain();
|
|
34
39
|
} else {
|
|
35
40
|
this.blocked = true; // if rum response determines that customer lacks entitlements for spa endpoint, this feature shouldn't harvest
|
|
@@ -40,8 +45,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
40
45
|
// Allow features external to the metrics feature to capture SMs and CMs through the event emitter
|
|
41
46
|
(0, _registerHandler.registerHandler)(_constants.SUPPORTABILITY_METRIC_CHANNEL, this.storeSupportabilityMetrics.bind(this), this.featureName, this.ee);
|
|
42
47
|
(0, _registerHandler.registerHandler)(_constants.CUSTOM_METRIC_CHANNEL, this.storeEventMetrics.bind(this), this.featureName, this.ee);
|
|
43
|
-
this.singleChecks(); // checks that are run only one time, at script load
|
|
44
|
-
this.eachSessionChecks(); // the start of every time user engages with page
|
|
45
48
|
}
|
|
46
49
|
preHarvestChecks(opts) {
|
|
47
50
|
return this.drained && opts.isFinalHarvest;
|
|
@@ -77,8 +80,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
77
80
|
if (distMethod) this.storeSupportabilityMetrics("Generic/DistMethod/".concat(distMethod, "/Detected"));
|
|
78
81
|
if (_runtime.isBrowserScope) {
|
|
79
82
|
this.storeSupportabilityMetrics('Generic/Runtime/Browser/Detected');
|
|
80
|
-
|
|
81
|
-
if (nonce && nonce !== '') {
|
|
83
|
+
if (this.agentNonce && this.agentNonce !== '') {
|
|
82
84
|
this.storeSupportabilityMetrics('Generic/Runtime/Nonce/Detected');
|
|
83
85
|
}
|
|
84
86
|
|
|
@@ -19,6 +19,8 @@ var _timeToFirstByte = require("../../../common/vitals/time-to-first-byte");
|
|
|
19
19
|
var _now = require("../../../common/timing/now");
|
|
20
20
|
var _timeKeeper = require("../../../common/timing/time-keeper");
|
|
21
21
|
var _traverse = require("../../../common/util/traverse");
|
|
22
|
+
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
23
|
+
var _target = require("../../../common/util/target");
|
|
22
24
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
23
25
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
24
26
|
/**
|
|
@@ -34,6 +36,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
34
36
|
this.firstByteToWindowLoad = 0; // our "frontend" duration
|
|
35
37
|
this.firstByteToDomContent = 0; // our "dom processing" duration
|
|
36
38
|
|
|
39
|
+
(0, _registerHandler.registerHandler)('send-rum', (customAttibutes, target) => {
|
|
40
|
+
this.sendRum(customAttibutes, target);
|
|
41
|
+
}, this.featureName, this.ee);
|
|
37
42
|
if (!(0, _info.isValid)(agentRef.agentIdentifier)) {
|
|
38
43
|
this.ee.abort();
|
|
39
44
|
return (0, _console.warn)(43);
|
|
@@ -56,7 +61,17 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
56
61
|
this.sendRum();
|
|
57
62
|
}
|
|
58
63
|
}
|
|
59
|
-
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
*
|
|
67
|
+
* @param {Function} cb A function to run once the RUM call has finished - Defaults to activateFeatures
|
|
68
|
+
* @param {*} customAttributes custom attributes to attach to the RUM call - Defaults to info.js
|
|
69
|
+
* @param {*} target The target to harvest to - Since we will not know the entityGuid before harvesting, this must be an object directly supplied from the info object or API, not an entityGuid string for lookup with the entityManager - Defaults to { licenseKey: this.agentRef.info.licenseKey, applicationID: this.agentRef.info.applicationID }
|
|
70
|
+
*/
|
|
71
|
+
sendRum(customAttributes = this.agentRef.info.jsAttributes, target = {
|
|
72
|
+
licenseKey: this.agentRef.info.licenseKey,
|
|
73
|
+
applicationID: this.agentRef.info.applicationID
|
|
74
|
+
}) {
|
|
60
75
|
const info = this.agentRef.info;
|
|
61
76
|
const measures = {};
|
|
62
77
|
if (info.queueTime) measures.qt = info.queueTime;
|
|
@@ -82,9 +97,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
82
97
|
if (this.agentRef.runtime.session) queryParameters.fsh = Number(this.agentRef.runtime.session.isNew); // "first session harvest" aka RUM request or PageView event of a session
|
|
83
98
|
|
|
84
99
|
let body;
|
|
85
|
-
if (typeof
|
|
100
|
+
if (typeof customAttributes === 'object' && Object.keys(customAttributes).length > 0) {
|
|
86
101
|
body = (0, _traverse.applyFnToProps)({
|
|
87
|
-
ja:
|
|
102
|
+
ja: customAttributes
|
|
88
103
|
}, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string');
|
|
89
104
|
}
|
|
90
105
|
if (_runtime.globalScope.performance) {
|
|
@@ -114,7 +129,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
114
129
|
this.rumStartTime = (0, _now.now)();
|
|
115
130
|
this.agentRef.runtime.harvester.triggerHarvestFor(this, {
|
|
116
131
|
directSend: {
|
|
117
|
-
targetApp:
|
|
132
|
+
targetApp: target,
|
|
118
133
|
payload: {
|
|
119
134
|
qs: queryParameters,
|
|
120
135
|
body
|
|
@@ -127,20 +142,32 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
127
142
|
postHarvestCleanup({
|
|
128
143
|
status,
|
|
129
144
|
responseText,
|
|
130
|
-
xhr
|
|
145
|
+
xhr,
|
|
146
|
+
targetApp
|
|
131
147
|
}) {
|
|
132
148
|
const rumEndTime = (0, _now.now)();
|
|
149
|
+
let app, flags;
|
|
150
|
+
try {
|
|
151
|
+
({
|
|
152
|
+
app,
|
|
153
|
+
...flags
|
|
154
|
+
} = JSON.parse(responseText));
|
|
155
|
+
this.processEntities(app.agents, targetApp);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
// wont set entity stuff here, if main agent will later abort, if registered agent, nothing will happen
|
|
158
|
+
(0, _console.warn)(53, error);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Only run agent-wide side-effects if the harvest was for the main agent */
|
|
162
|
+
if (!(0, _target.isContainerAgentTarget)(targetApp, this.agentRef)) return;
|
|
133
163
|
if (status >= 400 || status === 0) {
|
|
134
164
|
(0, _console.warn)(18, status);
|
|
135
165
|
// Adding retry logic for the rum call will be a separate change; this.blocked will need to be changed since that prevents another triggerHarvestFor()
|
|
136
166
|
this.ee.abort();
|
|
137
167
|
return;
|
|
138
168
|
}
|
|
139
|
-
const {
|
|
140
|
-
app,
|
|
141
|
-
...flags
|
|
142
|
-
} = JSON.parse(responseText);
|
|
143
169
|
try {
|
|
170
|
+
// will do nothing if already done
|
|
144
171
|
this.agentRef.runtime.timeKeeper.processRumRequest(xhr, this.rumStartTime, rumEndTime, app.nrServerTime);
|
|
145
172
|
if (!this.agentRef.runtime.timeKeeper.ready) throw new Error('TimeKeeper not ready');
|
|
146
173
|
} catch (error) {
|
|
@@ -148,10 +175,32 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
148
175
|
(0, _console.warn)(17, error);
|
|
149
176
|
return;
|
|
150
177
|
}
|
|
151
|
-
|
|
152
|
-
|
|
178
|
+
|
|
179
|
+
// set the agent runtime objects that require the rum response or entity guid
|
|
180
|
+
if (!Object.keys(this.agentRef.runtime.appMetadata).length) this.agentRef.runtime.appMetadata = app;
|
|
153
181
|
this.drain();
|
|
154
182
|
this.agentRef.runtime.harvester.startTimer();
|
|
183
|
+
(0, _featureFlags.activateFeatures)(flags, this.agentRef);
|
|
184
|
+
}
|
|
185
|
+
processEntities(entities, targetApp) {
|
|
186
|
+
if (!entities || !targetApp) return;
|
|
187
|
+
entities.forEach(agent => {
|
|
188
|
+
const entityManager = this.agentRef.runtime.entityManager;
|
|
189
|
+
const entityGuid = agent.entityGuid;
|
|
190
|
+
const entity = entityManager.get(entityGuid);
|
|
191
|
+
if (entity) return; // already processed
|
|
192
|
+
|
|
193
|
+
if ((0, _target.isContainerAgentTarget)(targetApp, this.agentRef)) {
|
|
194
|
+
entityManager.setDefaultEntity({
|
|
195
|
+
...targetApp,
|
|
196
|
+
entityGuid
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
entityManager.set(agent.entityGuid, {
|
|
200
|
+
...targetApp,
|
|
201
|
+
entityGuid
|
|
202
|
+
});
|
|
203
|
+
});
|
|
155
204
|
}
|
|
156
205
|
}
|
|
157
206
|
exports.Aggregate = Aggregate;
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.PageViewEvent = exports.Instrument = void 0;
|
|
7
|
+
var _handle = require("../../../common/event-emitter/handle");
|
|
7
8
|
var _instrumentBase = require("../../utils/instrument-base");
|
|
8
9
|
var CONSTANTS = _interopRequireWildcard(require("../constants"));
|
|
9
10
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
@@ -17,6 +18,9 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
17
18
|
static featureName = CONSTANTS.FEATURE_NAME;
|
|
18
19
|
constructor(agentRef, auto = true) {
|
|
19
20
|
super(agentRef, CONSTANTS.FEATURE_NAME, auto);
|
|
21
|
+
|
|
22
|
+
/** messages from the register API that can trigger a new RUM call */
|
|
23
|
+
this.ee.on('api-send-rum', (attrs, target) => (0, _handle.handle)('send-rum', [attrs, target], undefined, this.featureName, this.ee));
|
|
20
24
|
this.importAggregator(agentRef);
|
|
21
25
|
}
|
|
22
26
|
}
|
|
@@ -223,6 +223,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
makeHarvestPayload(shouldRetryOnFail) {
|
|
226
|
+
const payloadOutput = {
|
|
227
|
+
targetApp: undefined,
|
|
228
|
+
payload: undefined
|
|
229
|
+
};
|
|
226
230
|
if (this.mode !== _constants2.MODE.FULL || this.blocked) return;
|
|
227
231
|
if (!this.recorder || !this.timeKeeper?.ready || !this.recorder.hasSeenSnapshot) return;
|
|
228
232
|
const recorderEvents = this.recorder.getEvents();
|
|
@@ -231,7 +235,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
231
235
|
const payload = this.getHarvestContents(recorderEvents);
|
|
232
236
|
if (!payload.body.length) {
|
|
233
237
|
this.recorder.clearBuffer();
|
|
234
|
-
return;
|
|
238
|
+
return [payloadOutput];
|
|
235
239
|
}
|
|
236
240
|
this.reportSupportabilityMetric('SessionReplay/Harvest/Attempts');
|
|
237
241
|
let len = 0;
|
|
@@ -268,7 +272,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
268
272
|
}
|
|
269
273
|
if (len > _agentConstants.MAX_PAYLOAD_SIZE) {
|
|
270
274
|
this.abort(_constants.ABORT_REASONS.TOO_BIG, len);
|
|
271
|
-
return;
|
|
275
|
+
return [payloadOutput];
|
|
272
276
|
}
|
|
273
277
|
// TODO -- Gracefully handle the buffer for retries.
|
|
274
278
|
if (!this.agentRef.runtime.session.state.sessionReplaySentFirstChunk) this.syncWithSessionManager({
|
|
@@ -276,10 +280,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
276
280
|
});
|
|
277
281
|
this.recorder.clearBuffer();
|
|
278
282
|
if (recorderEvents.type === 'preloaded') this.agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
payload
|
|
282
|
-
}]; // SR doesn't need a targetApp as it only works for the main, but format needs to make AggregateBase
|
|
283
|
+
payloadOutput.payload = payload;
|
|
284
|
+
return [payloadOutput];
|
|
283
285
|
}
|
|
284
286
|
getCorrectedTimestamp(node) {
|
|
285
287
|
if (!node?.timestamp) return;
|
|
@@ -89,7 +89,7 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
89
89
|
});
|
|
90
90
|
this.recorder.startRecording();
|
|
91
91
|
this.abortHandler = this.recorder.stopRecording;
|
|
92
|
-
} catch (e) {}
|
|
92
|
+
} catch (e) {} // TODO add internal error handling
|
|
93
93
|
this.importAggregator(this.#agentRef, {
|
|
94
94
|
recorder: this.recorder,
|
|
95
95
|
errorNoticed: this.errorNoticed
|
|
@@ -26,8 +26,10 @@ class RecorderEvents {
|
|
|
26
26
|
hasMeta = false;
|
|
27
27
|
/** Payload metadata -- Should indicate that the payload being sent contains an error. Used for query/filter purposes in UI */
|
|
28
28
|
hasError = false;
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
constructor(shouldInlineStylesheets = true) {
|
|
30
|
+
/** Payload metadata -- Denotes whether all stylesheet elements were able to be inlined */
|
|
31
|
+
this.inlinedAllStylesheets = shouldInlineStylesheets;
|
|
32
|
+
}
|
|
31
33
|
add(event) {
|
|
32
34
|
this.#events.add(event);
|
|
33
35
|
}
|
|
@@ -35,9 +35,14 @@ class Recorder {
|
|
|
35
35
|
#warnCSSOnce = (0, _invoke.single)(() => (0, _console.warn)(47)); // notifies user of potential replayer issue if fix_stylesheets is off
|
|
36
36
|
|
|
37
37
|
constructor(parent) {
|
|
38
|
-
|
|
39
|
-
this
|
|
40
|
-
|
|
38
|
+
/** The parent class that instantiated the recorder */
|
|
39
|
+
this.parent = parent;
|
|
40
|
+
/** A flag that can be set to false by failing conversions to stop the fetching process */
|
|
41
|
+
this.shouldFix = this.parent.agentRef.init.session_replay.fix_stylesheets;
|
|
42
|
+
/** Event Buffers */
|
|
43
|
+
this.#events = new _recorderEvents.RecorderEvents(this.shouldFix);
|
|
44
|
+
this.#backloggedEvents = new _recorderEvents.RecorderEvents(this.shouldFix);
|
|
45
|
+
this.#preloaded = [new _recorderEvents.RecorderEvents(this.shouldFix)];
|
|
41
46
|
/** True when actively recording, false when paused or stopped */
|
|
42
47
|
this.recording = false;
|
|
43
48
|
/** The pointer to the current bucket holding rrweb events */
|
|
@@ -46,10 +51,6 @@ class Recorder {
|
|
|
46
51
|
this.hasSeenSnapshot = false;
|
|
47
52
|
/** Hold on to the last meta node, so that it can be re-inserted if the meta and snapshot nodes are broken up due to harvesting */
|
|
48
53
|
this.lastMeta = false;
|
|
49
|
-
/** The parent class that instantiated the recorder */
|
|
50
|
-
this.parent = parent;
|
|
51
|
-
/** A flag that can be set to false by failing conversions to stop the fetching process */
|
|
52
|
-
this.shouldFix = this.parent.agentRef.init.session_replay.fix_stylesheets;
|
|
53
54
|
/** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
|
|
54
55
|
this.stopRecording = () => {/* no-op until set by rrweb initializer */};
|
|
55
56
|
}
|
|
@@ -76,8 +77,8 @@ class Recorder {
|
|
|
76
77
|
|
|
77
78
|
/** Clears the buffer (this.#events), and resets all payload metadata properties */
|
|
78
79
|
clearBuffer() {
|
|
79
|
-
if (this.#preloaded[0]?.events.length) this.#preloaded.shift();else if (this.parent.mode === _constants2.MODE.ERROR) this.#backloggedEvents = this.#events;else this.#backloggedEvents = new _recorderEvents.RecorderEvents();
|
|
80
|
-
this.#events = new _recorderEvents.RecorderEvents();
|
|
80
|
+
if (this.#preloaded[0]?.events.length) this.#preloaded.shift();else if (this.parent.mode === _constants2.MODE.ERROR) this.#backloggedEvents = this.#events;else this.#backloggedEvents = new _recorderEvents.RecorderEvents(this.shouldFix);
|
|
81
|
+
this.#events = new _recorderEvents.RecorderEvents(this.shouldFix);
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
/** Begin recording using configured recording lib */
|
|
@@ -129,7 +130,7 @@ class Recorder {
|
|
|
129
130
|
*/
|
|
130
131
|
audit(event, isCheckout) {
|
|
131
132
|
/** An count of stylesheet objects that were blocked from accessing contents via JS */
|
|
132
|
-
const incompletes = _stylesheetEvaluator.stylesheetEvaluator.evaluate();
|
|
133
|
+
const incompletes = this.parent.agentRef.init.session_replay.fix_stylesheets ? _stylesheetEvaluator.stylesheetEvaluator.evaluate() : 0;
|
|
133
134
|
const missingInlineSMTag = 'SessionReplay/Payload/Missing-Inline-Css/';
|
|
134
135
|
/** only run the full fixing behavior (more costly) if fix_stylesheets is configured as on (default behavior) */
|
|
135
136
|
if (!this.shouldFix) {
|
|
@@ -205,7 +206,7 @@ class Recorder {
|
|
|
205
206
|
this.parent.agentRef.runtime.harvester.triggerHarvestFor(this.parent);
|
|
206
207
|
} else {
|
|
207
208
|
// we are still in "preload" and it triggered a "stop point". Make a new set, which will get pointed at on next cycle
|
|
208
|
-
this.#preloaded.push(new _recorderEvents.RecorderEvents());
|
|
209
|
+
this.#preloaded.push(new _recorderEvents.RecorderEvents(this.shouldFix));
|
|
209
210
|
}
|
|
210
211
|
}
|
|
211
212
|
}
|
|
@@ -31,7 +31,15 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
31
31
|
this.initialPageLoadInteraction.onDone.push(() => {
|
|
32
32
|
// this ensures the .end() method also works with iPL
|
|
33
33
|
this.initialPageLoadInteraction.forceSave = true; // unless forcibly ignored, iPL always finish by default
|
|
34
|
-
this.
|
|
34
|
+
const ixn = this.initialPageLoadInteraction;
|
|
35
|
+
/** this.events (ixns to harvest) has already been set up, use it immediately */
|
|
36
|
+
if (this.interactionsToHarvest) this.interactionsToHarvest.add(ixn);else {
|
|
37
|
+
/** this.events (ixns to harvest) hasnt been initialized yet... wait for it */
|
|
38
|
+
this.ee.on('entity-added', () => {
|
|
39
|
+
this.interactionsToHarvest = this.events;
|
|
40
|
+
this.interactionsToHarvest.add(ixn);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
35
43
|
this.initialPageLoadInteraction = null;
|
|
36
44
|
});
|
|
37
45
|
_timeToFirstByte.timeToFirstByte.subscribe(({
|
|
@@ -132,7 +140,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
132
140
|
*/
|
|
133
141
|
if (this.interactionInProgress?.isActiveDuring(timestamp)) return this.interactionInProgress;
|
|
134
142
|
let saveIxn;
|
|
135
|
-
const
|
|
143
|
+
const [{
|
|
144
|
+
data: interactionsBuffer
|
|
145
|
+
}] = this.interactionsToHarvest.get();
|
|
136
146
|
for (let idx = interactionsBuffer.length - 1; idx >= 0; idx--) {
|
|
137
147
|
// reverse search for the latest completed interaction for efficiency
|
|
138
148
|
const finishedInteraction = interactionsBuffer[idx];
|
|
@@ -125,7 +125,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
125
125
|
}
|
|
126
126
|
});
|
|
127
127
|
if (agentRef.init.spa.enabled !== true) return;
|
|
128
|
-
state.initialPageLoad = new _interaction.Interaction('initialPageLoad', 0, state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef
|
|
128
|
+
state.initialPageLoad = new _interaction.Interaction('initialPageLoad', 0, state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef);
|
|
129
129
|
state.initialPageLoad.save = true;
|
|
130
130
|
state.prevInteraction = state.initialPageLoad;
|
|
131
131
|
state.currentNode = state.initialPageLoad.root; // hint
|
|
@@ -206,7 +206,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
206
206
|
// Otherwise, if no interaction is currently active, create a new node ID,
|
|
207
207
|
// and let the aggregator know that we entered a new event handler callback
|
|
208
208
|
// so that it has a chance to possibly start an interaction.
|
|
209
|
-
var ixn = new _interaction.Interaction(evName, this[FN_START], state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef
|
|
209
|
+
var ixn = new _interaction.Interaction(evName, this[FN_START], state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef);
|
|
210
210
|
|
|
211
211
|
// Store the interaction as prevInteraction in case it is prematurely discarded
|
|
212
212
|
state.prevInteraction = ixn;
|
|
@@ -504,7 +504,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
504
504
|
}, this.featureName, promiseEE);
|
|
505
505
|
(0, _registerHandler.registerHandler)(INTERACTION_API + 'get', function (t) {
|
|
506
506
|
var interaction;
|
|
507
|
-
if (state?.currentNode?.[INTERACTION]) interaction = this.ixn = state.currentNode[INTERACTION];else if (state?.prevNode?.end === null && state?.prevNode?.[INTERACTION]?.root?.[INTERACTION]?.eventName !== 'initialPageLoad') interaction = this.ixn = state.prevNode[INTERACTION];else interaction = this.ixn = new _interaction.Interaction('api', t, state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef
|
|
507
|
+
if (state?.currentNode?.[INTERACTION]) interaction = this.ixn = state.currentNode[INTERACTION];else if (state?.prevNode?.end === null && state?.prevNode?.[INTERACTION]?.root?.[INTERACTION]?.eventName !== 'initialPageLoad') interaction = this.ixn = state.prevNode[INTERACTION];else interaction = this.ixn = new _interaction.Interaction('api', t, state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef);
|
|
508
508
|
if (!state.currentNode) {
|
|
509
509
|
interaction.checkFinish();
|
|
510
510
|
if (state.depth) setCurrentNode(interaction.root);
|
|
@@ -4,10 +4,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.Interaction = Interaction;
|
|
7
|
-
var _info = require("../../../common/config/info");
|
|
8
7
|
var _runtime = require("../../../common/constants/runtime");
|
|
9
8
|
var _nreum = require("../../../common/window/nreum");
|
|
10
|
-
var _contextualEe = require("../../../common/event-emitter/contextual-ee");
|
|
11
9
|
var _interactionNode = require("./interaction-node");
|
|
12
10
|
/**
|
|
13
11
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
@@ -17,11 +15,10 @@ var _interactionNode = require("./interaction-node");
|
|
|
17
15
|
var originalSetTimeout = (0, _nreum.gosNREUMOriginals)().o.ST;
|
|
18
16
|
var originalClearTimeout = (0, _nreum.gosNREUMOriginals)().o.CT;
|
|
19
17
|
var lastId = {};
|
|
20
|
-
function Interaction(eventName, timestamp, url, routeName, onFinished,
|
|
21
|
-
this.
|
|
22
|
-
|
|
23
|
-
lastId[agentIdentifier]
|
|
24
|
-
this.id = ++lastId[agentIdentifier];
|
|
18
|
+
function Interaction(eventName, timestamp, url, routeName, onFinished, agentRef) {
|
|
19
|
+
this.agentRef = agentRef;
|
|
20
|
+
lastId[agentRef.agentIdentifier] = 0;
|
|
21
|
+
this.id = ++lastId[agentRef.agentIdentifier];
|
|
25
22
|
this.eventName = eventName;
|
|
26
23
|
this.nodes = 0;
|
|
27
24
|
this.remaining = 0;
|
|
@@ -89,9 +86,9 @@ InteractionPrototype.finish = function finishInteraction() {
|
|
|
89
86
|
if (this.onFinished) {
|
|
90
87
|
this.onFinished(this);
|
|
91
88
|
}
|
|
92
|
-
Object.entries(
|
|
89
|
+
Object.entries(interaction.agentRef.info?.jsAttributes || {}).forEach(([attr, value]) => {
|
|
93
90
|
if (!(attr in customAttrs)) customAttrs[attr] = value;
|
|
94
91
|
});
|
|
95
92
|
root.end = endTimestamp;
|
|
96
|
-
interaction.ee.emit('interaction', [this]);
|
|
93
|
+
interaction.agentRef.ee.emit('interaction', [this]);
|
|
97
94
|
};
|
|
@@ -14,21 +14,47 @@ var _obfuscate = require("../../common/util/obfuscate");
|
|
|
14
14
|
var _features = require("../../loaders/features/features");
|
|
15
15
|
var _eventStoreManager = require("./event-store-manager");
|
|
16
16
|
var _harvester = require("../../common/harvest/harvester");
|
|
17
|
+
var _console = require("../../common/util/console");
|
|
18
|
+
var _entityManager = require("./entity-manager");
|
|
19
|
+
var _eventBuffer = require("./event-buffer");
|
|
17
20
|
var _handle = require("../../common/event-emitter/handle");
|
|
18
21
|
var _constants = require("../metrics/constants");
|
|
22
|
+
var _eventAggregator = require("../../common/aggregate/event-aggregator");
|
|
19
23
|
/**
|
|
20
24
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
21
25
|
* SPDX-License-Identifier: Apache-2.0
|
|
22
26
|
*/
|
|
23
27
|
|
|
24
28
|
class AggregateBase extends _featureBase.FeatureBase {
|
|
29
|
+
/**
|
|
30
|
+
* Create an AggregateBase instance.
|
|
31
|
+
* @param {Object} agentRef The reference to the agent instance.
|
|
32
|
+
* @param {string} featureName The name of the feature creating the instance.
|
|
33
|
+
*/
|
|
25
34
|
constructor(agentRef, featureName) {
|
|
26
35
|
super(agentRef.agentIdentifier, featureName);
|
|
27
36
|
this.agentRef = agentRef;
|
|
28
37
|
this.checkConfiguration(agentRef);
|
|
29
38
|
this.doOnceForAllAggregate(agentRef);
|
|
39
|
+
this.harvestOpts = {}; // features aggregate classes can define custom opts for when their harvest is called
|
|
40
|
+
|
|
41
|
+
const agentEntityGuid = this.agentRef?.runtime?.appMetadata?.agents?.[0]?.entityGuid;
|
|
42
|
+
if (agentEntityGuid) {
|
|
43
|
+
this.#setupEventStore(agentEntityGuid); // if there's no entity guid, wont dont anything, and will wait for rum flags
|
|
44
|
+
} else {
|
|
45
|
+
this.ee.on('entity-added', entity => {
|
|
46
|
+
this.#setupEventStore(entity.entityGuid);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
30
50
|
|
|
31
|
-
|
|
51
|
+
/**
|
|
52
|
+
* sets up the event store for the feature. It must wait for the entity guid to be available before setting up the event store. This is called once the rum response is received with an entityGuid.
|
|
53
|
+
* @param {string} entityGuid
|
|
54
|
+
* @returns {void}
|
|
55
|
+
*/
|
|
56
|
+
#setupEventStore(entityGuid) {
|
|
57
|
+
if (this.events || !entityGuid) return;
|
|
32
58
|
switch (this.featureName) {
|
|
33
59
|
// SessionTrace + Replay have their own storage mechanisms.
|
|
34
60
|
case _features.FEATURE_NAMES.sessionTrace:
|
|
@@ -37,16 +63,15 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
37
63
|
// Jserror and Metric features uses a singleton EventAggregator instead of a regular EventBuffer.
|
|
38
64
|
case _features.FEATURE_NAMES.jserrors:
|
|
39
65
|
case _features.FEATURE_NAMES.metrics:
|
|
40
|
-
this.events = agentRef.sharedAggregator;
|
|
66
|
+
this.events = this.agentRef.sharedAggregator ??= new _eventStoreManager.EventStoreManager(this.agentRef, _eventAggregator.EventAggregator, entityGuid, 'shared_aggregator');
|
|
41
67
|
break;
|
|
42
68
|
/** All other features get EventBuffer in the ESM by default. Note: PVE is included here, but event buffer will always be empty so future harvests will still not happen by interval or EOL.
|
|
43
69
|
This was necessary to prevent race cond. issues where the event buffer was checked before the feature could "block" itself.
|
|
44
70
|
Its easier to just keep an empty event buffer in place. */
|
|
45
71
|
default:
|
|
46
|
-
this.events = new _eventStoreManager.EventStoreManager(agentRef
|
|
72
|
+
this.events = new _eventStoreManager.EventStoreManager(this.agentRef, _eventBuffer.EventBuffer, entityGuid, this.featureName);
|
|
47
73
|
break;
|
|
48
74
|
}
|
|
49
|
-
this.harvestOpts = {}; // features aggregate classes can define custom opts for when their harvest is called
|
|
50
75
|
}
|
|
51
76
|
|
|
52
77
|
/**
|
|
@@ -76,6 +101,10 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
76
101
|
this.deregisterDrain();
|
|
77
102
|
});
|
|
78
103
|
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Stages the feature to be drained
|
|
107
|
+
*/
|
|
79
108
|
drain() {
|
|
80
109
|
(0, _drain.drain)(this.agentIdentifier, this.featureName);
|
|
81
110
|
this.drained = true;
|
|
@@ -87,28 +116,29 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
87
116
|
/**
|
|
88
117
|
* Return harvest payload. A "serializer" function can be defined on a derived class to format the payload.
|
|
89
118
|
* @param {Boolean} shouldRetryOnFail - harvester flag to backup payload for retry later if harvest request fails; this should be moved to harvester logic
|
|
90
|
-
* @param {object|undefined} opts
|
|
119
|
+
* @param {object|undefined} opts - opts passed from the harvester to help form the payload
|
|
120
|
+
* @param {string} opts.targetEntityGuid - the entity guid of the target app
|
|
91
121
|
* @returns {Array} Final payload tagged with their targeting browser app. The value of `payload` can be undefined if there are no pending events for an app. This should be a minimum length of 1.
|
|
92
122
|
*/
|
|
93
123
|
makeHarvestPayload(shouldRetryOnFail = false, opts = {}) {
|
|
94
|
-
if (this.events.isEmpty(this.harvestOpts, opts.
|
|
124
|
+
if (!this.events || this.events.isEmpty(this.harvestOpts, opts.targetEntityGuid)) return;
|
|
95
125
|
// Other conditions and things to do when preparing harvest that is required.
|
|
96
126
|
if (this.preHarvestChecks && !this.preHarvestChecks(opts)) return;
|
|
97
|
-
if (shouldRetryOnFail) this.events.save(this.harvestOpts, opts.
|
|
98
|
-
const returnedDataArr = this.events.get(this.harvestOpts, opts.
|
|
99
|
-
if (!returnedDataArr.length)
|
|
100
|
-
this.events.clear(this.harvestOpts, opts.
|
|
127
|
+
if (shouldRetryOnFail) this.events.save(this.harvestOpts, opts.targetEntityGuid);
|
|
128
|
+
const returnedDataArr = this.events.get(this.harvestOpts, opts.targetEntityGuid);
|
|
129
|
+
if (!returnedDataArr.length) return (0, _console.warn)(52);
|
|
130
|
+
this.events.clear(this.harvestOpts, opts.targetEntityGuid);
|
|
101
131
|
return returnedDataArr.map(({
|
|
102
132
|
targetApp,
|
|
103
133
|
data
|
|
104
134
|
}) => {
|
|
105
135
|
// A serializer or formatter assists in creating the payload `body` from stored events on harvest when defined by derived feature class.
|
|
106
|
-
const body = this.serializer ? this.serializer(data) : data;
|
|
136
|
+
const body = this.serializer ? this.serializer(data, targetApp?.entityGuid) : data;
|
|
107
137
|
const payload = {
|
|
108
138
|
body
|
|
109
139
|
};
|
|
110
140
|
// Constructs the payload `qs` for relevant features on harvest.
|
|
111
|
-
if (this.queryStringsBuilder) payload.qs = this.queryStringsBuilder(data);
|
|
141
|
+
if (this.queryStringsBuilder) payload.qs = this.queryStringsBuilder(data, targetApp?.entityGuid);
|
|
112
142
|
return {
|
|
113
143
|
targetApp,
|
|
114
144
|
payload
|
|
@@ -119,11 +149,15 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
119
149
|
/**
|
|
120
150
|
* Cleanup task after a harvest.
|
|
121
151
|
* @param {object} result - the cbResult object from the harvester's send method
|
|
152
|
+
* @param {object=} result.targetApp - the target app object that was used to point the harvest to the correct app
|
|
153
|
+
* @param {string=} result.targetApp.entityGuid - the entity guid of the target app
|
|
154
|
+
* @param {boolean=} result.sent - whether the harvest was sent successfully
|
|
155
|
+
* @param {boolean=} result.retry - whether the harvest should be retried
|
|
122
156
|
*/
|
|
123
157
|
postHarvestCleanup(result = {}) {
|
|
124
158
|
const harvestFailed = result.sent && result.retry;
|
|
125
|
-
if (harvestFailed) this.events.reloadSave(this.harvestOpts, result.targetApp);
|
|
126
|
-
this.events.clearSave(this.harvestOpts, result.targetApp);
|
|
159
|
+
if (harvestFailed) this.events.reloadSave(this.harvestOpts, result.targetApp?.entityGuid);
|
|
160
|
+
this.events.clearSave(this.harvestOpts, result.targetApp?.entityGuid);
|
|
127
161
|
}
|
|
128
162
|
|
|
129
163
|
/**
|
|
@@ -163,12 +197,7 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
163
197
|
doOnceForAllAggregate(agentRef) {
|
|
164
198
|
if (!agentRef.runtime.obfuscator) agentRef.runtime.obfuscator = new _obfuscate.Obfuscator(agentRef);
|
|
165
199
|
this.obfuscator = agentRef.runtime.obfuscator;
|
|
166
|
-
if (!agentRef.
|
|
167
|
-
licenseKey: agentRef.info.licenseKey,
|
|
168
|
-
appId: agentRef.info.applicationID
|
|
169
|
-
};
|
|
170
|
-
// Create a single Aggregator for this agent if DNE yet; to be used by jserror endpoint features.
|
|
171
|
-
if (!agentRef.sharedAggregator) agentRef.sharedAggregator = new _eventStoreManager.EventStoreManager(agentRef.mainAppKey, 2, agentRef.agentIdentifier, 'shared_aggregator');
|
|
200
|
+
if (!agentRef.runtime.entityManager) agentRef.runtime.entityManager = new _entityManager.EntityManager(this.agentRef);
|
|
172
201
|
if (!agentRef.runtime.harvester) agentRef.runtime.harvester = new _harvester.Harvester(agentRef);
|
|
173
202
|
}
|
|
174
203
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.EntityManager = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
9
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
class EntityManager {
|
|
13
|
+
#entities = new Map();
|
|
14
|
+
#entityGuidLookup = {};
|
|
15
|
+
#defaultEntity = null;
|
|
16
|
+
constructor(agentRef) {
|
|
17
|
+
this.agentRef = agentRef;
|
|
18
|
+
this.#defaultEntity = {
|
|
19
|
+
licenseKey: agentRef.info.licenseKey,
|
|
20
|
+
applicationID: agentRef.info.applicationID
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
get(entityGuid) {
|
|
24
|
+
if (!entityGuid) return this.#defaultEntity;
|
|
25
|
+
return this.#entities.get(entityGuid);
|
|
26
|
+
}
|
|
27
|
+
getEntityGuidFor(licenseKey, applicationID) {
|
|
28
|
+
if (!this.#entityGuidLookup[licenseKey] || !this.#entityGuidLookup[applicationID]) return;
|
|
29
|
+
return this.#entityGuidLookup[licenseKey].filter(x => this.#entityGuidLookup[applicationID].includes(x))[0];
|
|
30
|
+
}
|
|
31
|
+
set(entityGuid, entity) {
|
|
32
|
+
if (this.#entities.has(entityGuid)) return;
|
|
33
|
+
this.#entities.set(entityGuid, entity);
|
|
34
|
+
this.#entityGuidLookup[entity.licenseKey] ??= [];
|
|
35
|
+
this.#entityGuidLookup[entity.licenseKey].push(entityGuid);
|
|
36
|
+
this.#entityGuidLookup[entity.applicationID] ??= [];
|
|
37
|
+
this.#entityGuidLookup[entity.applicationID].push(entityGuid);
|
|
38
|
+
this.agentRef.ee.emit('entity-added', [entity]);
|
|
39
|
+
}
|
|
40
|
+
clear() {
|
|
41
|
+
this.#entities.clear();
|
|
42
|
+
}
|
|
43
|
+
setDefaultEntity(entity) {
|
|
44
|
+
this.#defaultEntity = entity;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.EntityManager = EntityManager;
|