@newrelic/browser-agent 1.301.0 → 1.302.0-alpha.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 +13 -0
- package/dist/cjs/common/config/init-types.js +1 -1
- package/dist/cjs/common/config/init.js +7 -1
- package/dist/cjs/common/config/runtime.js +1 -1
- package/dist/cjs/common/constants/agent-constants.js +11 -2
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/drain/drain.js +1 -1
- package/dist/cjs/common/harvest/harvester.js +30 -39
- package/dist/cjs/common/util/mfe.js +45 -0
- package/dist/cjs/features/ajax/aggregate/index.js +5 -1
- package/dist/cjs/features/generic_events/aggregate/index.js +9 -8
- package/dist/cjs/features/generic_events/constants.js +3 -1
- package/dist/cjs/features/generic_events/instrument/index.js +38 -32
- package/dist/cjs/features/jserrors/aggregate/index.js +18 -17
- package/dist/cjs/features/logging/aggregate/index.js +19 -15
- package/dist/cjs/features/logging/shared/utils.js +3 -3
- package/dist/cjs/features/page_view_event/aggregate/index.js +3 -33
- package/dist/cjs/features/session_replay/aggregate/index.js +13 -13
- package/dist/cjs/features/session_replay/shared/recorder.js +3 -2
- package/dist/cjs/features/session_trace/aggregate/index.js +0 -2
- package/dist/cjs/features/soft_navigations/aggregate/index.js +1 -2
- package/dist/cjs/features/utils/aggregate-base.js +45 -47
- package/dist/cjs/loaders/api/addPageAction.js +2 -2
- package/dist/cjs/loaders/api/log.js +2 -2
- package/dist/cjs/loaders/api/noticeError.js +2 -2
- package/dist/cjs/loaders/api/register-api-types.js +5 -5
- package/dist/cjs/loaders/api/register.js +80 -97
- package/dist/esm/common/config/init-types.js +1 -1
- package/dist/esm/common/config/init.js +7 -1
- package/dist/esm/common/config/runtime.js +1 -1
- package/dist/esm/common/constants/agent-constants.js +9 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/drain/drain.js +1 -1
- package/dist/esm/common/harvest/harvester.js +30 -39
- package/dist/esm/common/util/mfe.js +38 -0
- package/dist/esm/features/ajax/aggregate/index.js +5 -1
- package/dist/esm/features/generic_events/aggregate/index.js +9 -8
- package/dist/esm/features/generic_events/constants.js +3 -1
- package/dist/esm/features/generic_events/instrument/index.js +38 -32
- package/dist/esm/features/jserrors/aggregate/index.js +18 -17
- package/dist/esm/features/logging/aggregate/index.js +19 -15
- package/dist/esm/features/logging/shared/utils.js +3 -3
- package/dist/esm/features/page_view_event/aggregate/index.js +3 -33
- package/dist/esm/features/session_replay/aggregate/index.js +13 -13
- package/dist/esm/features/session_replay/shared/recorder.js +3 -2
- package/dist/esm/features/session_trace/aggregate/index.js +0 -2
- package/dist/esm/features/soft_navigations/aggregate/index.js +1 -2
- package/dist/esm/features/utils/aggregate-base.js +46 -48
- package/dist/esm/loaders/api/addPageAction.js +2 -2
- package/dist/esm/loaders/api/log.js +2 -2
- package/dist/esm/loaders/api/noticeError.js +2 -2
- package/dist/esm/loaders/api/register-api-types.js +5 -5
- package/dist/esm/loaders/api/register.js +80 -97
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/config/init-types.d.ts +4 -1
- package/dist/types/common/config/init-types.d.ts.map +1 -1
- package/dist/types/common/config/init.d.ts.map +1 -1
- package/dist/types/common/constants/agent-constants.d.ts +7 -4
- package/dist/types/common/constants/agent-constants.d.ts.map +1 -1
- package/dist/types/common/harvest/harvester.d.ts +2 -2
- package/dist/types/common/harvest/harvester.d.ts.map +1 -1
- package/dist/types/common/util/mfe.d.ts +20 -0
- package/dist/types/common/util/mfe.d.ts.map +1 -0
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts +2 -2
- package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/constants.d.ts +1 -0
- package/dist/types/features/generic_events/instrument/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +3 -3
- 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 -2
- package/dist/types/features/logging/shared/utils.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -4
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +13 -4
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts +1 -0
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +13 -5
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/loaders/api/addPageAction.d.ts +1 -1
- package/dist/types/loaders/api/addPageAction.d.ts.map +1 -1
- package/dist/types/loaders/api/log.d.ts +1 -1
- package/dist/types/loaders/api/log.d.ts.map +1 -1
- package/dist/types/loaders/api/noticeError.d.ts +1 -1
- package/dist/types/loaders/api/noticeError.d.ts.map +1 -1
- package/dist/types/loaders/api/register-api-types.d.ts +4 -4
- package/dist/types/loaders/api/register-api-types.d.ts.map +1 -1
- package/dist/types/loaders/api/register.d.ts +8 -1
- package/dist/types/loaders/api/register.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/common/config/init-types.js +1 -1
- package/src/common/config/init.js +3 -1
- package/src/common/config/runtime.js +1 -1
- package/src/common/constants/agent-constants.js +10 -0
- package/src/common/drain/drain.js +1 -1
- package/src/common/harvest/harvester.js +27 -32
- package/src/common/util/mfe.js +35 -0
- package/src/features/ajax/aggregate/index.js +7 -1
- package/src/features/generic_events/aggregate/index.js +9 -8
- package/src/features/generic_events/constants.js +3 -1
- package/src/features/generic_events/instrument/index.js +44 -35
- package/src/features/jserrors/aggregate/index.js +17 -17
- package/src/features/logging/aggregate/index.js +20 -13
- package/src/features/logging/shared/utils.js +3 -3
- package/src/features/page_view_event/aggregate/index.js +3 -28
- package/src/features/session_replay/aggregate/index.js +12 -10
- package/src/features/session_replay/shared/recorder.js +3 -2
- package/src/features/session_trace/aggregate/index.js +0 -2
- package/src/features/soft_navigations/aggregate/index.js +1 -2
- package/src/features/utils/aggregate-base.js +47 -42
- package/src/loaders/api/addPageAction.js +2 -2
- package/src/loaders/api/log.js +2 -2
- package/src/loaders/api/noticeError.js +2 -2
- package/src/loaders/api/register-api-types.js +5 -5
- package/src/loaders/api/register.js +62 -89
- package/dist/cjs/common/util/target.js +0 -34
- package/dist/cjs/features/utils/entity-manager.js +0 -46
- package/dist/cjs/features/utils/event-store-manager.js +0 -174
- package/dist/cjs/loaders/api/register-api.js +0 -165
- package/dist/esm/common/util/target.js +0 -27
- package/dist/esm/features/utils/entity-manager.js +0 -39
- package/dist/esm/features/utils/event-store-manager.js +0 -166
- package/dist/esm/loaders/api/register-api.js +0 -159
- package/dist/types/common/util/target.d.ts +0 -18
- package/dist/types/common/util/target.d.ts.map +0 -1
- package/dist/types/features/utils/entity-manager.d.ts +0 -11
- package/dist/types/features/utils/entity-manager.d.ts.map +0 -1
- package/dist/types/features/utils/event-store-manager.d.ts +0 -85
- package/dist/types/features/utils/event-store-manager.d.ts.map +0 -1
- package/dist/types/loaders/api/register-api.d.ts +0 -14
- package/dist/types/loaders/api/register-api.d.ts.map +0 -1
- package/src/common/util/target.js +0 -27
- package/src/features/utils/entity-manager.js +0 -45
- package/src/features/utils/event-store-manager.js +0 -165
- package/src/loaders/api/register-api.js +0 -152
|
@@ -7,7 +7,7 @@ exports.buildRegisterApi = buildRegisterApi;
|
|
|
7
7
|
exports.setupRegisterAPI = setupRegisterAPI;
|
|
8
8
|
var _handle = require("../../common/event-emitter/handle");
|
|
9
9
|
var _console = require("../../common/util/console");
|
|
10
|
-
var
|
|
10
|
+
var _mfe = require("../../common/util/mfe");
|
|
11
11
|
var _features = require("../features/features");
|
|
12
12
|
var _now = require("../../common/timing/now");
|
|
13
13
|
var _constants = require("../../features/metrics/constants");
|
|
@@ -16,6 +16,7 @@ var _constants2 = require("./constants");
|
|
|
16
16
|
var _log = require("./log");
|
|
17
17
|
var _addPageAction = require("./addPageAction");
|
|
18
18
|
var _noticeError = require("./noticeError");
|
|
19
|
+
var _invoke = require("../../common/util/invoke");
|
|
19
20
|
/**
|
|
20
21
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
21
22
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -42,138 +43,120 @@ function setupRegisterAPI(agent) {
|
|
|
42
43
|
* @param {Object} agentRef the reference to the base agent instance
|
|
43
44
|
* @param {Object} handlers the shared handlers to be used by both the base agent's API and the external target's API
|
|
44
45
|
* @param {Object} target the target information to be used by the external target's API to send data to the correct location
|
|
46
|
+
* @param {string} [target.licenseKey] the license key of the target to report data to
|
|
47
|
+
* @param {string} target.id the entity ID of the target to report data to
|
|
48
|
+
* @param {string} target.name the entity name of the target to report data to
|
|
45
49
|
* @returns {RegisterAPI} the api object to be returned from the register api method
|
|
46
50
|
*/
|
|
47
51
|
function buildRegisterApi(agentRef, target) {
|
|
48
52
|
const attrs = {};
|
|
49
53
|
(0, _console.warn)(54, 'newrelic.register');
|
|
54
|
+
target ||= {};
|
|
55
|
+
target.licenseKey ||= agentRef.info.licenseKey; // will inherit the license key from the container agent if not provided for brevity. A future state may dictate that we need different license keys to do different things.
|
|
56
|
+
target.blocked = false;
|
|
50
57
|
|
|
51
|
-
/** @type {Function
|
|
52
|
-
let invalidApiResponse;
|
|
58
|
+
/** @type {Function} a function that is set and reports when APIs are triggered -- warns the customer of the invalid state */
|
|
59
|
+
let invalidApiResponse = () => {};
|
|
60
|
+
/** @type {Array} the array of registered target APIs */
|
|
61
|
+
const registeredEntities = agentRef.runtime.registeredEntities;
|
|
62
|
+
|
|
63
|
+
/** if we have already registered this target, go ahead and re-use it */
|
|
64
|
+
const preregisteredEntity = registeredEntities.find(({
|
|
65
|
+
metadata: {
|
|
66
|
+
target: {
|
|
67
|
+
id,
|
|
68
|
+
name
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}) => id === target.id);
|
|
72
|
+
if (preregisteredEntity) {
|
|
73
|
+
if (preregisteredEntity.metadata.target.name !== target.name) preregisteredEntity.metadata.target.name = target.name;
|
|
74
|
+
return preregisteredEntity;
|
|
75
|
+
}
|
|
53
76
|
|
|
54
77
|
/**
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
78
|
+
* Block the API, and supply a warning function to display a message to end users
|
|
79
|
+
* @param {Function} warning
|
|
80
|
+
*/
|
|
81
|
+
const block = warning => {
|
|
82
|
+
target.blocked = true;
|
|
83
|
+
invalidApiResponse = warning;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/** primary cases that can block the register API from working at init time */
|
|
87
|
+
if (!agentRef.init.api.allow_registered_children) block((0, _invoke.single)(() => (0, _console.warn)(55)));
|
|
88
|
+
if (!(0, _mfe.isValidMFETarget)(target)) block((0, _invoke.single)(() => (0, _console.warn)(48, target)));
|
|
63
89
|
|
|
64
90
|
/** @type {RegisterAPI} */
|
|
65
91
|
const api = {
|
|
66
|
-
addPageAction: (name, attributes = {}) => {
|
|
67
|
-
|
|
92
|
+
addPageAction: (name, attributes = {}) => report(_addPageAction.addPageAction, [name, {
|
|
93
|
+
...attrs,
|
|
94
|
+
...attributes
|
|
95
|
+
}, agentRef], target),
|
|
96
|
+
log: (message, options = {}) => report(_log.log, [message, {
|
|
97
|
+
...options,
|
|
98
|
+
customAttributes: {
|
|
68
99
|
...attrs,
|
|
69
|
-
...
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}, agentRef], target);
|
|
80
|
-
},
|
|
81
|
-
noticeError: (error, attributes = {}) => {
|
|
82
|
-
report(_noticeError.noticeError, [error, {
|
|
83
|
-
...attrs,
|
|
84
|
-
...attributes
|
|
85
|
-
}, agentRef], target);
|
|
86
|
-
},
|
|
87
|
-
setApplicationVersion: value => {
|
|
88
|
-
attrs['application.version'] = value;
|
|
89
|
-
},
|
|
90
|
-
setCustomAttribute: (key, value) => {
|
|
91
|
-
attrs[key] = value;
|
|
92
|
-
},
|
|
93
|
-
setUserId: value => {
|
|
94
|
-
attrs['enduser.id'] = value;
|
|
95
|
-
},
|
|
100
|
+
...(options.customAttributes || {})
|
|
101
|
+
}
|
|
102
|
+
}, agentRef], target),
|
|
103
|
+
noticeError: (error, attributes = {}) => report(_noticeError.noticeError, [error, {
|
|
104
|
+
...attrs,
|
|
105
|
+
...attributes
|
|
106
|
+
}, agentRef], target),
|
|
107
|
+
setApplicationVersion: value => setLocalValue('application.version', value),
|
|
108
|
+
setCustomAttribute: (key, value) => setLocalValue(key, value),
|
|
109
|
+
setUserId: value => setLocalValue('enduser.id', value),
|
|
96
110
|
/** metadata */
|
|
97
111
|
metadata: {
|
|
98
112
|
customAttributes: attrs,
|
|
99
|
-
target
|
|
100
|
-
/** set in a getter so that later access of the Promise is not polluted before customer is allowed to set a catch block */
|
|
101
|
-
get connected() {
|
|
102
|
-
return _connected || Promise.reject(new Error('Failed to connect'));
|
|
103
|
-
}
|
|
113
|
+
target
|
|
104
114
|
}
|
|
105
115
|
};
|
|
106
|
-
if (invalidApiResponse) {
|
|
107
|
-
invalidApiResponse();
|
|
108
|
-
} else {
|
|
109
|
-
_connected = new Promise((resolve, reject) => {
|
|
110
|
-
try {
|
|
111
|
-
const entityManager = agentRef.runtime?.entityManager;
|
|
112
|
-
/** check if main agent already has main agent entity guid */
|
|
113
|
-
let mainAgentReady = !!entityManager?.get().entityGuid;
|
|
114
|
-
/** check if registered target already has entity guid */
|
|
115
|
-
let registeredEntityGuid = entityManager?.getEntityGuidFor(target.licenseKey, target.applicationID);
|
|
116
|
-
let registrationReady = !!registeredEntityGuid;
|
|
117
|
-
|
|
118
|
-
/** check if we can just resolve immediately without making another connect call */
|
|
119
|
-
if (mainAgentReady && registrationReady) {
|
|
120
|
-
target.entityGuid = registeredEntityGuid;
|
|
121
|
-
resolve(api);
|
|
122
|
-
} else {
|
|
123
|
-
/** we need to make a new connection call since we dont already have a registered entity for this call */
|
|
124
116
|
|
|
125
|
-
|
|
126
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Check if the API is blocked and emit a warning message describing the blockage
|
|
119
|
+
* @returns {boolean}
|
|
120
|
+
*/
|
|
121
|
+
const isBlocked = () => {
|
|
122
|
+
if (target.blocked) invalidApiResponse();
|
|
123
|
+
return target.blocked;
|
|
124
|
+
};
|
|
127
125
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
agentRef.ee.emit('api-send-rum', [attrs, target]);
|
|
126
|
+
/** only allow registered APIs to be tracked in the agent runtime */
|
|
127
|
+
if (!isBlocked()) registeredEntities.push(api);
|
|
131
128
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
clearTimeout(timeout);
|
|
143
|
-
// unsubscribe from the event emitter
|
|
144
|
-
agentRef.ee.removeEventListener('entity-added', entityEventHandler);
|
|
145
|
-
resolve(api);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
} catch (err) {
|
|
150
|
-
reject(err);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
}
|
|
129
|
+
/**
|
|
130
|
+
* Sets a value local to the registered API attrs. Will do nothing if APIs are deregistered.
|
|
131
|
+
* @param {string} key The attribute key
|
|
132
|
+
* @param {*} value the attribute value
|
|
133
|
+
* @returns {void}
|
|
134
|
+
*/
|
|
135
|
+
const setLocalValue = (key, value) => {
|
|
136
|
+
if (isBlocked()) return;
|
|
137
|
+
attrs[key] = value;
|
|
138
|
+
};
|
|
154
139
|
|
|
155
140
|
/**
|
|
156
141
|
* The reporter method that will be used to report the data to the container agent's API method. If invalid, will log a warning and not execute.
|
|
157
142
|
* If the api.duplicate_registered_data configuration value is set to true, the data will be reported to BOTH the container and the external target
|
|
158
143
|
* @param {*} methodToCall the container agent's API method to call
|
|
159
144
|
* @param {*} args the arguments to supply to the container agent's API method
|
|
160
|
-
* @param {string}
|
|
145
|
+
* @param {string} target the target to report the data to. If undefined, will report to the container agent's target.
|
|
161
146
|
* @returns
|
|
162
147
|
*/
|
|
163
|
-
const report =
|
|
164
|
-
if (
|
|
148
|
+
const report = (methodToCall, args, target) => {
|
|
149
|
+
if (isBlocked()) return;
|
|
165
150
|
/** set the timestamp before the async part of waiting for the rum response for better accuracy */
|
|
166
151
|
const timestamp = (0, _now.now)();
|
|
167
152
|
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ["API/register/".concat(methodToCall.name, "/called")], undefined, _features.FEATURE_NAMES.metrics, agentRef.ee);
|
|
168
153
|
try {
|
|
169
|
-
await _connected;
|
|
170
|
-
// target should be decorated with entityGuid by the rum resp at this point
|
|
171
154
|
const shouldDuplicate = agentRef.init.api.duplicate_registered_data;
|
|
172
|
-
if (shouldDuplicate === true || Array.isArray(shouldDuplicate)
|
|
155
|
+
if (shouldDuplicate === true || Array.isArray(shouldDuplicate)) {
|
|
173
156
|
// also report to container by providing undefined target
|
|
174
157
|
methodToCall(...args, undefined, timestamp);
|
|
175
158
|
}
|
|
176
|
-
methodToCall(...args, target
|
|
159
|
+
return methodToCall(...args, target, timestamp); // always report to target
|
|
177
160
|
} catch (err) {
|
|
178
161
|
(0, _console.warn)(50, err);
|
|
179
162
|
}
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* @property {Object} [metrics]
|
|
36
36
|
* @property {boolean} [metrics.enabled] - Turn on/off the metrics feature (on by default).
|
|
37
37
|
* @property {boolean} [metrics.autoStart] - If true, the agent will automatically start the metrics feature. Otherwise, it will be in a deferred state until the `start` API method is called.
|
|
38
|
-
* @property {
|
|
38
|
+
* @property {{regex: RegExp | string, replacement: string}[]} [obfuscate] - Array of regexp and corresponding replacement patterns for obfuscating data.
|
|
39
39
|
* @property {Object} [page_action]
|
|
40
40
|
* @property {boolean} [page_action.enabled] - Must be true to allow PageAction events to be captured.
|
|
41
41
|
* @property {Object} [page_view_event]
|
|
@@ -21,6 +21,7 @@ const InitModelFn = () => {
|
|
|
21
21
|
const hiddenState = {
|
|
22
22
|
feature_flags: [],
|
|
23
23
|
experimental: {
|
|
24
|
+
allow_registered_children: false,
|
|
24
25
|
resources: false
|
|
25
26
|
},
|
|
26
27
|
mask_selector: '*',
|
|
@@ -53,7 +54,12 @@ const InitModelFn = () => {
|
|
|
53
54
|
autoStart: true
|
|
54
55
|
},
|
|
55
56
|
api: {
|
|
56
|
-
allow_registered_children
|
|
57
|
+
get allow_registered_children() {
|
|
58
|
+
return hiddenState.feature_flags.includes(FEATURE_FLAGS.REGISTER) || hiddenState.experimental.allow_registered_children;
|
|
59
|
+
},
|
|
60
|
+
set allow_registered_children(val) {
|
|
61
|
+
hiddenState.experimental.allow_registered_children = val;
|
|
62
|
+
},
|
|
57
63
|
duplicate_registered_data: false
|
|
58
64
|
},
|
|
59
65
|
distributed_tracing: {
|
|
@@ -23,7 +23,6 @@ const RuntimeModel = {
|
|
|
23
23
|
customTransaction: undefined,
|
|
24
24
|
denyList: undefined,
|
|
25
25
|
disabled: false,
|
|
26
|
-
entityManager: undefined,
|
|
27
26
|
harvester: undefined,
|
|
28
27
|
isolatedBacklog: false,
|
|
29
28
|
isRecording: false,
|
|
@@ -36,6 +35,7 @@ const RuntimeModel = {
|
|
|
36
35
|
releaseIds: {},
|
|
37
36
|
session: undefined,
|
|
38
37
|
timeKeeper: undefined,
|
|
38
|
+
registeredEntities: [],
|
|
39
39
|
/** a proxy is set in agent-session to track jsAttributes changes for harvesting mechanics */
|
|
40
40
|
jsAttributesMetadata: {
|
|
41
41
|
bytes: 0
|
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
+
import { FEATURE_NAMES } from '../../loaders/features/features';
|
|
5
6
|
export const IDEAL_PAYLOAD_SIZE = 16000;
|
|
6
7
|
export const MAX_PAYLOAD_SIZE = 1000000;
|
|
7
8
|
export const DEFAULT_KEY = 'NR_CONTAINER_AGENT';
|
|
8
|
-
export const SESSION_ERROR = 'SESSION_ERROR';
|
|
9
|
+
export const SESSION_ERROR = 'SESSION_ERROR';
|
|
10
|
+
export const SUPPORTS_REGISTERED_ENTITIES = {
|
|
11
|
+
[FEATURE_NAMES.logging]: true,
|
|
12
|
+
// flip other features here when they are supported by DEM consumers
|
|
13
|
+
[FEATURE_NAMES.genericEvents]: false,
|
|
14
|
+
[FEATURE_NAMES.jserrors]: false,
|
|
15
|
+
[FEATURE_NAMES.ajax]: false
|
|
16
|
+
};
|
|
@@ -122,7 +122,7 @@ function drainGroup(agentIdentifier, group, activateGroup = true) {
|
|
|
122
122
|
}
|
|
123
123
|
if (!baseEE.isolatedBacklog) delete handlers[group];
|
|
124
124
|
baseEE.backlog[group] = null;
|
|
125
|
-
baseEE.emit('drain-' + group, []); //
|
|
125
|
+
baseEE.emit('drain-' + group, []); // Informs the feature that it has drained its backlog of events, this kicks off an immediate harvest to capture any load-driven events that were buffered.
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
/**
|
|
@@ -53,35 +53,30 @@ export class Harvester {
|
|
|
53
53
|
* @returns {boolean} True if 1+ network call was made. Note that this does not mean or guarantee that it was successful (or that all were in the case of more than 1).
|
|
54
54
|
*/
|
|
55
55
|
triggerHarvestFor(aggregateInst, localOpts = {}) {
|
|
56
|
-
|
|
56
|
+
const output = {
|
|
57
|
+
ranSend: false,
|
|
58
|
+
payload: undefined,
|
|
59
|
+
endpointVersion: aggregateInst.harvestEndpointVersion || 1
|
|
60
|
+
};
|
|
61
|
+
if (aggregateInst.blocked) return output;
|
|
57
62
|
const submitMethod = getSubmitMethod(localOpts);
|
|
58
|
-
if (!submitMethod) return
|
|
63
|
+
if (!submitMethod) return output;
|
|
59
64
|
const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === xhrMethod; // always retry all features harvests except for final
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (!
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
send(this.agentRef, {
|
|
73
|
-
endpoint: FEATURE_TO_ENDPOINT[aggregateInst.featureName],
|
|
74
|
-
targetApp,
|
|
75
|
-
payload,
|
|
76
|
-
localOpts,
|
|
77
|
-
submitMethod,
|
|
78
|
-
cbFinished,
|
|
79
|
-
raw: aggregateInst.harvestOpts.raw,
|
|
80
|
-
featureName: aggregateInst.featureName
|
|
81
|
-
});
|
|
82
|
-
ranSend = true;
|
|
65
|
+
output.payload = !localOpts.directSend ? aggregateInst.makeHarvestPayload(shouldRetryOnFail, localOpts) : localOpts.directSend?.payload; // features like PVE can define the payload directly, bypassing the makeHarvestPayload logic
|
|
66
|
+
|
|
67
|
+
if (!output.payload) return output;
|
|
68
|
+
send(this.agentRef, {
|
|
69
|
+
endpoint: FEATURE_TO_ENDPOINT[aggregateInst.featureName],
|
|
70
|
+
payload: output.payload,
|
|
71
|
+
localOpts,
|
|
72
|
+
submitMethod,
|
|
73
|
+
cbFinished,
|
|
74
|
+
raw: aggregateInst.harvestOpts.raw,
|
|
75
|
+
featureName: aggregateInst.featureName,
|
|
76
|
+
endpointVersion: output.endpointVersion
|
|
83
77
|
});
|
|
84
|
-
|
|
78
|
+
output.ranSend = true;
|
|
79
|
+
return output;
|
|
85
80
|
|
|
86
81
|
/**
|
|
87
82
|
* This is executed immediately after harvest sends the data via XHR, or if there's nothing to send. Note that this excludes on unloading / sendBeacon.
|
|
@@ -114,13 +109,13 @@ const warnings = {};
|
|
|
114
109
|
*/
|
|
115
110
|
export function send(agentRef, {
|
|
116
111
|
endpoint,
|
|
117
|
-
targetApp,
|
|
118
112
|
payload,
|
|
119
113
|
localOpts = {},
|
|
120
114
|
submitMethod,
|
|
121
115
|
cbFinished,
|
|
122
116
|
raw,
|
|
123
|
-
featureName
|
|
117
|
+
featureName,
|
|
118
|
+
endpointVersion = 1
|
|
124
119
|
}) {
|
|
125
120
|
if (!agentRef.info.errorBeacon) return false;
|
|
126
121
|
let {
|
|
@@ -130,15 +125,14 @@ export function send(agentRef, {
|
|
|
130
125
|
if (Object.keys(body).length === 0 && !localOpts.sendEmptyBody) {
|
|
131
126
|
// if there's no body to send, just run onfinish stuff and return
|
|
132
127
|
if (cbFinished) cbFinished({
|
|
133
|
-
sent: false
|
|
134
|
-
targetApp
|
|
128
|
+
sent: false
|
|
135
129
|
});
|
|
136
130
|
return false;
|
|
137
131
|
}
|
|
138
132
|
const protocol = agentRef.init.ssl === false ? 'http' : 'https';
|
|
139
133
|
const perceivedBeacon = agentRef.init.proxy.beacon || agentRef.info.errorBeacon;
|
|
140
|
-
const url = raw ? "".concat(protocol, "://").concat(perceivedBeacon, "/").concat(endpoint) : "".concat(protocol, "://").concat(perceivedBeacon).concat(endpoint !== RUM ? '/' + endpoint : '', "/
|
|
141
|
-
const baseParams = !raw ? baseQueryString(agentRef, qs, endpoint
|
|
134
|
+
const url = raw ? "".concat(protocol, "://").concat(perceivedBeacon, "/").concat(endpoint) : "".concat(protocol, "://").concat(perceivedBeacon).concat(endpoint !== RUM ? '/' + endpoint : '', "/").concat(endpointVersion, "/").concat(agentRef.info.licenseKey);
|
|
135
|
+
const baseParams = !raw ? baseQueryString(agentRef, qs, endpoint) : '';
|
|
142
136
|
let payloadParams = obj(qs, agentRef.runtime.maxBytes);
|
|
143
137
|
if (baseParams === '' && payloadParams.startsWith('&')) {
|
|
144
138
|
payloadParams = payloadParams.substring(1);
|
|
@@ -181,8 +175,7 @@ export function send(agentRef, {
|
|
|
181
175
|
status: this.status,
|
|
182
176
|
retry: shouldRetry(this.status),
|
|
183
177
|
fullUrl,
|
|
184
|
-
xhr: this
|
|
185
|
-
targetApp
|
|
178
|
+
xhr: this
|
|
186
179
|
};
|
|
187
180
|
if (localOpts.needResponse) cbResult.responseText = this.responseText;
|
|
188
181
|
cbFinished(cbResult);
|
|
@@ -198,8 +191,7 @@ export function send(agentRef, {
|
|
|
198
191
|
status,
|
|
199
192
|
retry: shouldRetry(status),
|
|
200
193
|
fullUrl,
|
|
201
|
-
fetchResponse: response
|
|
202
|
-
targetApp
|
|
194
|
+
fetchResponse: response
|
|
203
195
|
};
|
|
204
196
|
if (localOpts.needResponse) cbResult.responseText = await response.text();
|
|
205
197
|
cbFinished(cbResult);
|
|
@@ -240,7 +232,6 @@ export function send(agentRef, {
|
|
|
240
232
|
data: {
|
|
241
233
|
endpoint,
|
|
242
234
|
headers,
|
|
243
|
-
targetApp,
|
|
244
235
|
payload,
|
|
245
236
|
submitMethod: getSubmitMethodName(),
|
|
246
237
|
raw,
|
|
@@ -290,12 +281,12 @@ function cleanPayload(payload = {}) {
|
|
|
290
281
|
}
|
|
291
282
|
|
|
292
283
|
// The stuff that gets sent every time.
|
|
293
|
-
function baseQueryString(agentRef, qs, endpoint
|
|
284
|
+
function baseQueryString(agentRef, qs, endpoint) {
|
|
294
285
|
const ref = agentRef.runtime.obfuscator.obfuscateString(cleanURL('' + globalScope.location));
|
|
295
286
|
const session = agentRef.runtime.session;
|
|
296
287
|
const hr = !!session?.state.sessionReplaySentFirstChunk && session?.state.sessionReplayMode === 1 && endpoint !== JSERRORS;
|
|
297
288
|
const ht = !!session?.state.traceHarvestStarted && session?.state.sessionTraceMode === 1 && ![LOGS, BLOBS].includes(endpoint);
|
|
298
|
-
const qps = ['a=' + applicationID, param('sa', agentRef.info.sa ? '' + agentRef.info.sa : ''), param('v', VERSION), transactionNameParam(), param('ct', agentRef.runtime.customTransaction), '&rst=' + now(), '&ck=0',
|
|
289
|
+
const qps = ['a=' + agentRef.info.applicationID, param('sa', agentRef.info.sa ? '' + agentRef.info.sa : ''), param('v', VERSION), transactionNameParam(), param('ct', agentRef.runtime.customTransaction), '&rst=' + now(), '&ck=0',
|
|
299
290
|
// ck param DEPRECATED - still expected by backend
|
|
300
291
|
'&s=' + (session?.state.value || '0'),
|
|
301
292
|
// the 0 id encaps all untrackable and default traffic
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {Object} [target] - the target to be validated
|
|
8
|
+
* @returns {boolean}
|
|
9
|
+
*/
|
|
10
|
+
export function isValidMFETarget(target = {}) {
|
|
11
|
+
return !!(target.id && target.name);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* When given a valid target, returns an object with the MFE payload attributes. Returns an empty object otherwise.
|
|
16
|
+
* @param {Object} [target] the registered target
|
|
17
|
+
* @param {AggregateInstance} [aggregateInstance] the aggregate instance calling the method
|
|
18
|
+
* @returns {{'mfe.id': *, 'mfe.name': String}|{}} returns an empty object if args are not supplied or the aggregate instance is not supporting version 2
|
|
19
|
+
*/
|
|
20
|
+
export function getVersion2Attributes(target, aggregateInstance) {
|
|
21
|
+
if (aggregateInstance?.harvestEndpointVersion !== 2) return {};
|
|
22
|
+
const containerAgentEntityGuid = aggregateInstance.agentRef.runtime.appMetadata.agents[0].entityGuid;
|
|
23
|
+
if (!isValidMFETarget(target)) {
|
|
24
|
+
return {
|
|
25
|
+
'entity.guid': containerAgentEntityGuid,
|
|
26
|
+
appId: aggregateInstance.agentRef.info.applicationID
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
'mfe.id': target.id,
|
|
31
|
+
// these field names may change as the schema is finalized
|
|
32
|
+
'mfe.name': target.name,
|
|
33
|
+
// these field names may change as the schema is finalized
|
|
34
|
+
eventSource: 'MicroFrontendBrowserAgent',
|
|
35
|
+
// these field names may change as the schema is finalized
|
|
36
|
+
'parent.id': containerAgentEntityGuid
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -124,9 +124,13 @@ export class Aggregate extends AggregateBase {
|
|
|
124
124
|
if (!eventBuffer.length) return;
|
|
125
125
|
const addString = getAddStringContext(this.agentRef.runtime.obfuscator);
|
|
126
126
|
let payload = 'bel.7;';
|
|
127
|
+
let firstTimestamp = 0;
|
|
127
128
|
for (let i = 0; i < eventBuffer.length; i++) {
|
|
128
129
|
const event = eventBuffer[i];
|
|
129
|
-
|
|
130
|
+
// ajax nodes are relative to the first node (or page origin if no previous node), so we need to calculate the relative start time
|
|
131
|
+
const relativeStartTime = event.startTime - firstTimestamp;
|
|
132
|
+
if (i === 0) firstTimestamp = event.startTime;
|
|
133
|
+
const fields = [numeric(relativeStartTime), numeric(event.endTime - event.startTime), numeric(0),
|
|
130
134
|
// callbackEnd
|
|
131
135
|
numeric(0),
|
|
132
136
|
// no callbackDuration for non-SPA events
|
|
@@ -14,6 +14,7 @@ import { applyFnToProps } from '../../../common/util/traverse';
|
|
|
14
14
|
import { UserActionsAggregator } from './user-actions/user-actions-aggregator';
|
|
15
15
|
import { isIFrameWindow } from '../../../common/dom/iframe';
|
|
16
16
|
import { isPureObject } from '../../../common/util/type-check';
|
|
17
|
+
import { getVersion2Attributes } from '../../../common/util/mfe';
|
|
17
18
|
export class Aggregate extends AggregateBase {
|
|
18
19
|
static featureName = FEATURE_NAME;
|
|
19
20
|
#userActionAggregator;
|
|
@@ -36,8 +37,7 @@ export class Aggregate extends AggregateBase {
|
|
|
36
37
|
});
|
|
37
38
|
}, this.featureName, this.ee);
|
|
38
39
|
if (agentRef.init.page_action.enabled) {
|
|
39
|
-
registerHandler('api-addPageAction', (timestamp, name, attributes,
|
|
40
|
-
if (!this.agentRef.runtime.entityManager.get(targetEntityGuid)) return warn(56, this.featureName);
|
|
40
|
+
registerHandler('api-addPageAction', (timestamp, name, attributes, target) => {
|
|
41
41
|
this.addEvent({
|
|
42
42
|
...attributes,
|
|
43
43
|
eventType: 'PageAction',
|
|
@@ -49,7 +49,7 @@ export class Aggregate extends AggregateBase {
|
|
|
49
49
|
browserWidth: window.document.documentElement?.clientWidth,
|
|
50
50
|
browserHeight: window.document.documentElement?.clientHeight
|
|
51
51
|
})
|
|
52
|
-
},
|
|
52
|
+
}, target);
|
|
53
53
|
}, this.featureName, this.ee);
|
|
54
54
|
}
|
|
55
55
|
let addUserAction = () => {/** no-op */};
|
|
@@ -247,7 +247,6 @@ export class Aggregate extends AggregateBase {
|
|
|
247
247
|
};
|
|
248
248
|
this.addEvent(event);
|
|
249
249
|
}, this.featureName, this.ee);
|
|
250
|
-
agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
251
250
|
this.drain();
|
|
252
251
|
});
|
|
253
252
|
}
|
|
@@ -263,10 +262,10 @@ export class Aggregate extends AggregateBase {
|
|
|
263
262
|
* * sessionTraceId: set by the `ptid=` query param
|
|
264
263
|
* * userAgent*: set by the userAgent header
|
|
265
264
|
* @param {object=} obj the event object for storing in the event buffer
|
|
266
|
-
* @param {string=}
|
|
265
|
+
* @param {string=} target the target metadata for the event to scope buffering and harvesting. Defaults to container agent config if undefined
|
|
267
266
|
* @returns void
|
|
268
267
|
*/
|
|
269
|
-
addEvent(obj = {},
|
|
268
|
+
addEvent(obj = {}, target) {
|
|
270
269
|
if (!obj || !Object.keys(obj).length) return;
|
|
271
270
|
if (!obj.eventType) {
|
|
272
271
|
warn(44);
|
|
@@ -281,7 +280,9 @@ export class Aggregate extends AggregateBase {
|
|
|
281
280
|
timestamp: Math.floor(this.agentRef.runtime.timeKeeper.correctRelativeTimestamp(now())),
|
|
282
281
|
/** all generic events require pageUrl(s) */
|
|
283
282
|
pageUrl: cleanURL('' + initialLocation),
|
|
284
|
-
currentUrl: cleanURL('' + location)
|
|
283
|
+
currentUrl: cleanURL('' + location),
|
|
284
|
+
/** Specific attributes only supplied if harvesting to endpoint version 2 */
|
|
285
|
+
...getVersion2Attributes(target, this)
|
|
285
286
|
};
|
|
286
287
|
const eventAttributes = {
|
|
287
288
|
/** Agent-level custom attributes */
|
|
@@ -291,7 +292,7 @@ export class Aggregate extends AggregateBase {
|
|
|
291
292
|
/** Event-specific attributes take precedence over agent-level custom attributes and fallbacks */
|
|
292
293
|
...obj
|
|
293
294
|
};
|
|
294
|
-
this.events.add(eventAttributes
|
|
295
|
+
this.events.add(eventAttributes);
|
|
295
296
|
}
|
|
296
297
|
serializer(eventBuffer) {
|
|
297
298
|
return applyFnToProps({
|
|
@@ -11,5 +11,7 @@ export const RAGE_CLICK_THRESHOLD_MS = 1000;
|
|
|
11
11
|
export const FRUSTRATION_TIMEOUT_MS = 2000;
|
|
12
12
|
export const RESERVED_EVENT_TYPES = ['PageAction', 'UserAction', 'BrowserPerformance'];
|
|
13
13
|
export const FEATURE_FLAGS = {
|
|
14
|
-
RESOURCES: 'experimental.resources'
|
|
14
|
+
RESOURCES: 'experimental.resources',
|
|
15
|
+
REGISTER: 'register'
|
|
16
|
+
// register.jserrors and register.generic_events are also used, but not referenced directly so no need to represent here
|
|
15
17
|
};
|