@newrelic/browser-agent 1.284.1 → 1.285.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 +14 -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/harvest/harvester.js +29 -2
- package/dist/cjs/common/util/feature-flags.js +6 -1
- package/dist/cjs/features/logging/aggregate/index.js +1 -1
- package/dist/cjs/features/session_replay/shared/recorder.js +3 -10
- package/dist/cjs/features/session_replay/shared/utils.js +12 -0
- package/dist/cjs/features/utils/aggregate-base.js +2 -2
- package/dist/cjs/features/utils/event-store-manager.js +15 -1
- package/dist/cjs/loaders/api/api.js +13 -0
- package/dist/cjs/loaders/configure/configure.js +16 -0
- package/dist/cjs/loaders/features/features.js +4 -3
- 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 +30 -3
- package/dist/esm/common/util/feature-flags.js +6 -1
- package/dist/esm/features/logging/aggregate/index.js +1 -1
- package/dist/esm/features/session_replay/shared/recorder.js +2 -9
- package/dist/esm/features/session_replay/shared/utils.js +11 -0
- package/dist/esm/features/utils/aggregate-base.js +2 -2
- package/dist/esm/features/utils/event-store-manager.js +15 -1
- package/dist/esm/loaders/api/api.js +13 -0
- package/dist/esm/loaders/configure/configure.js +16 -0
- package/dist/esm/loaders/features/features.js +3 -2
- package/dist/types/common/harvest/harvester.d.ts.map +1 -1
- package/dist/types/common/util/feature-flags.d.ts.map +1 -1
- package/dist/types/features/logging/aggregate/index.d.ts +0 -1
- package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/utils.d.ts +1 -0
- package/dist/types/features/session_replay/shared/utils.d.ts.map +1 -1
- package/dist/types/features/utils/event-store-manager.d.ts +5 -1
- package/dist/types/features/utils/event-store-manager.d.ts.map +1 -1
- 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 +2 -0
- package/dist/types/loaders/features/features.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/common/harvest/harvester.js +33 -3
- package/src/common/util/feature-flags.js +8 -1
- package/src/features/logging/aggregate/index.js +2 -2
- package/src/features/session_replay/shared/recorder.js +2 -9
- package/src/features/session_replay/shared/utils.js +12 -0
- package/src/features/utils/aggregate-base.js +2 -2
- package/src/features/utils/event-store-manager.js +15 -1
- package/src/loaders/api/api.js +10 -0
- package/src/loaders/configure/configure.js +13 -0
- package/src/loaders/features/features.js +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.285.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.284.1...v1.285.0) (2025-03-18)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Decorate harvest requests with ht (hasTrace) param ([#1409](https://github.com/newrelic/newrelic-browser-agent/issues/1409)) ([b8ed2b0](https://github.com/newrelic/newrelic-browser-agent/commit/b8ed2b0aeef8b8db651ddb8001171f28785c7673))
|
|
12
|
+
* Inspection events ([#1413](https://github.com/newrelic/newrelic-browser-agent/issues/1413)) ([1832562](https://github.com/newrelic/newrelic-browser-agent/commit/1832562f52c1e2e26c49c2855ad1996d6251b803))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* Logging mode on session update ([#1417](https://github.com/newrelic/newrelic-browser-agent/issues/1417)) ([3f59afe](https://github.com/newrelic/newrelic-browser-agent/commit/3f59afef8a53848d80f7f32d28302b6b0bcf7d2f))
|
|
18
|
+
* Session Replay text masking for whitespace ([#1416](https://github.com/newrelic/newrelic-browser-agent/issues/1416)) ([97bf326](https://github.com/newrelic/newrelic-browser-agent/commit/97bf32655d6e608ea7248acc680d983b1d1e0eea))
|
|
19
|
+
|
|
6
20
|
## [1.284.1](https://github.com/newrelic/newrelic-browser-agent/compare/v1.284.0...v1.284.1) (2025-03-11)
|
|
7
21
|
|
|
8
22
|
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.
|
|
20
|
+
const VERSION = exports.VERSION = "1.285.0";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.
|
|
20
|
+
const VERSION = exports.VERSION = "1.285.0";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -18,6 +18,8 @@ var _encode = require("../url/encode");
|
|
|
18
18
|
var _console = require("../util/console");
|
|
19
19
|
var _stringify = require("../util/stringify");
|
|
20
20
|
var _submitData = require("../util/submit-data");
|
|
21
|
+
var _featureFlags = require("../util/feature-flags");
|
|
22
|
+
var _globalEvent = require("../dispatch/global-event");
|
|
21
23
|
/**
|
|
22
24
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
23
25
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -88,7 +90,8 @@ class Harvester {
|
|
|
88
90
|
localOpts,
|
|
89
91
|
submitMethod,
|
|
90
92
|
cbFinished,
|
|
91
|
-
raw: aggregateInst.harvestOpts.raw
|
|
93
|
+
raw: aggregateInst.harvestOpts.raw,
|
|
94
|
+
featureName: aggregateInst.featureName
|
|
92
95
|
});
|
|
93
96
|
ranSend = true;
|
|
94
97
|
});
|
|
@@ -130,7 +133,8 @@ function send(agentRef, {
|
|
|
130
133
|
localOpts = {},
|
|
131
134
|
submitMethod,
|
|
132
135
|
cbFinished,
|
|
133
|
-
raw
|
|
136
|
+
raw,
|
|
137
|
+
featureName
|
|
134
138
|
}) {
|
|
135
139
|
if (!agentRef.info.errorBeacon) return false;
|
|
136
140
|
let {
|
|
@@ -211,6 +215,22 @@ function send(agentRef, {
|
|
|
211
215
|
});
|
|
212
216
|
}
|
|
213
217
|
}
|
|
218
|
+
(0, _globalEvent.dispatchGlobalEvent)({
|
|
219
|
+
agentIdentifier: agentRef.agentIdentifier,
|
|
220
|
+
loaded: !!_featureFlags.activatedFeatures?.[agentRef.agentIdentifier],
|
|
221
|
+
type: 'data',
|
|
222
|
+
name: 'harvest',
|
|
223
|
+
feature: featureName,
|
|
224
|
+
data: {
|
|
225
|
+
endpoint,
|
|
226
|
+
headers,
|
|
227
|
+
targetApp,
|
|
228
|
+
payload,
|
|
229
|
+
submitMethod: getSubmitMethodName(),
|
|
230
|
+
raw,
|
|
231
|
+
synchronousXhr: !!(localOpts.isFinalHarvest && _runtime.isWorkerScope)
|
|
232
|
+
}
|
|
233
|
+
});
|
|
214
234
|
return true;
|
|
215
235
|
function shouldRetry(status) {
|
|
216
236
|
switch (status) {
|
|
@@ -221,6 +241,11 @@ function send(agentRef, {
|
|
|
221
241
|
}
|
|
222
242
|
return status >= 502 && status <= 504 || status >= 512 && status <= 530;
|
|
223
243
|
}
|
|
244
|
+
function getSubmitMethodName() {
|
|
245
|
+
if (submitMethod === _submitData.xhr) return 'xhr';
|
|
246
|
+
if (submitMethod === _submitData.xhrFetch) return 'fetch';
|
|
247
|
+
return 'beacon';
|
|
248
|
+
}
|
|
224
249
|
}
|
|
225
250
|
|
|
226
251
|
/**
|
|
@@ -252,12 +277,14 @@ function cleanPayload(payload = {}) {
|
|
|
252
277
|
function baseQueryString(agentRef, qs, endpoint, applicationID) {
|
|
253
278
|
const ref = agentRef.runtime.obfuscator.obfuscateString((0, _cleanUrl.cleanURL)('' + _runtime.globalScope.location));
|
|
254
279
|
const hr = agentRef.runtime.session?.state.sessionReplayMode === 1 && endpoint !== _features.JSERRORS;
|
|
280
|
+
const ht = agentRef.runtime.session?.state.sessionTraceMode === 1 && ![_features.LOGS, _features.BLOBS].includes(endpoint);
|
|
255
281
|
const qps = ['a=' + applicationID, (0, _encode.param)('sa', agentRef.info.sa ? '' + agentRef.info.sa : ''), (0, _encode.param)('v', _env.VERSION), transactionNameParam(), (0, _encode.param)('ct', agentRef.runtime.customTransaction), '&rst=' + (0, _now.now)(), '&ck=0',
|
|
256
282
|
// ck param DEPRECATED - still expected by backend
|
|
257
283
|
'&s=' + (agentRef.runtime.session?.state.value || '0'),
|
|
258
284
|
// the 0 id encaps all untrackable and default traffic
|
|
259
285
|
(0, _encode.param)('ref', ref), (0, _encode.param)('ptid', agentRef.runtime.ptid ? '' + agentRef.runtime.ptid : '')];
|
|
260
286
|
if (hr) qps.push((0, _encode.param)('hr', '1', qs));
|
|
287
|
+
if (ht) qps.push((0, _encode.param)('ht', '1', qs));
|
|
261
288
|
return qps.join('');
|
|
262
289
|
|
|
263
290
|
// Constructs the transaction name param for the beacon URL.
|
|
@@ -35,6 +35,11 @@ function activateFeatures(flags, agentIdentifier) {
|
|
|
35
35
|
|
|
36
36
|
// let any window level subscribers know that the agent is running
|
|
37
37
|
(0, _globalEvent.dispatchGlobalEvent)({
|
|
38
|
-
|
|
38
|
+
agentIdentifier,
|
|
39
|
+
loaded: true,
|
|
40
|
+
type: 'lifecycle',
|
|
41
|
+
name: 'load',
|
|
42
|
+
feature: undefined,
|
|
43
|
+
data: flags
|
|
39
44
|
});
|
|
40
45
|
}
|
|
@@ -33,7 +33,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
33
33
|
});
|
|
34
34
|
this.ee.on(_constants2.SESSION_EVENTS.UPDATE, (type, data) => {
|
|
35
35
|
if (this.blocked || type !== _constants2.SESSION_EVENT_TYPES.CROSS_TAB) return;
|
|
36
|
-
if (this.
|
|
36
|
+
if (this.loggingMode !== _constants.LOGGING_MODE.OFF && data.loggingMode === _constants.LOGGING_MODE.OFF) this.abort(_constants3.ABORT_REASONS.CROSS_TAB);else this.loggingMode = data.loggingMode;
|
|
37
37
|
});
|
|
38
38
|
this.harvestOpts.raw = true;
|
|
39
39
|
this.waitForFlags(['log']).then(([loggingMode]) => {
|
|
@@ -90,14 +90,7 @@ class Recorder {
|
|
|
90
90
|
inline_images,
|
|
91
91
|
collect_fonts
|
|
92
92
|
} = this.parent.agentRef.init.session_replay;
|
|
93
|
-
|
|
94
|
-
try {
|
|
95
|
-
if (typeof element?.type === 'string' && element.type.toLowerCase() !== 'password' && (element?.dataset?.nrUnmask !== undefined || element?.classList?.contains('nr-unmask'))) return text;
|
|
96
|
-
} catch (err) {
|
|
97
|
-
// likely an element was passed to this handler that was invalid and was missing attributes or methods
|
|
98
|
-
}
|
|
99
|
-
return '*'.repeat(text?.length || 0);
|
|
100
|
-
};
|
|
93
|
+
|
|
101
94
|
// set up rrweb configurations for maximum privacy --
|
|
102
95
|
// https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
|
|
103
96
|
const stop = (0, _rrweb.record)({
|
|
@@ -108,9 +101,9 @@ class Recorder {
|
|
|
108
101
|
blockSelector: block_selector,
|
|
109
102
|
maskInputOptions: mask_input_options,
|
|
110
103
|
maskTextSelector: mask_text_selector,
|
|
111
|
-
maskTextFn: customMasker,
|
|
104
|
+
maskTextFn: _utils.customMasker,
|
|
112
105
|
maskAllInputs: mask_all_inputs,
|
|
113
|
-
maskInputFn: customMasker,
|
|
106
|
+
maskInputFn: _utils.customMasker,
|
|
114
107
|
inlineStylesheet: true,
|
|
115
108
|
inlineImages: inline_images,
|
|
116
109
|
collectFonts: collect_fonts,
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.buildNRMetaNode = buildNRMetaNode;
|
|
7
|
+
exports.customMasker = customMasker;
|
|
7
8
|
exports.hasReplayPrerequisite = hasReplayPrerequisite;
|
|
8
9
|
exports.isPreloadAllowed = isPreloadAllowed;
|
|
9
10
|
var _nreum = require("../../../common/window/nreum");
|
|
@@ -35,4 +36,15 @@ function buildNRMetaNode(timestamp, timeKeeper) {
|
|
|
35
36
|
correctedOriginTime: timeKeeper.correctedOriginTime,
|
|
36
37
|
originTimeDiff: Math.floor(_runtime.originTime - timeKeeper.correctedOriginTime)
|
|
37
38
|
};
|
|
39
|
+
}
|
|
40
|
+
function customMasker(text, element) {
|
|
41
|
+
try {
|
|
42
|
+
if (typeof element?.type === 'string') {
|
|
43
|
+
if (element.type.toLowerCase() === 'password') return '*'.repeat(text?.length || 0);
|
|
44
|
+
if (element?.dataset?.nrUnmask !== undefined || element?.classList?.contains('nr-unmask')) return text;
|
|
45
|
+
}
|
|
46
|
+
} catch (err) {
|
|
47
|
+
// likely an element was passed to this handler that was invalid and was missing attributes or methods
|
|
48
|
+
}
|
|
49
|
+
return typeof text === 'string' ? text.replace(/[\S]/g, '*') : '*'.repeat(text?.length || 0);
|
|
38
50
|
}
|
|
@@ -43,7 +43,7 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
43
43
|
This was necessary to prevent race cond. issues where the event buffer was checked before the feature could "block" itself.
|
|
44
44
|
Its easier to just keep an empty event buffer in place. */
|
|
45
45
|
default:
|
|
46
|
-
this.events = new _eventStoreManager.EventStoreManager(agentRef.mainAppKey, 1);
|
|
46
|
+
this.events = new _eventStoreManager.EventStoreManager(agentRef.mainAppKey, 1, agentRef.agentIdentifier, this.featureName);
|
|
47
47
|
break;
|
|
48
48
|
}
|
|
49
49
|
this.harvestOpts = {}; // features aggregate classes can define custom opts for when their harvest is called
|
|
@@ -170,7 +170,7 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
170
170
|
appId: agentRef.info.applicationID
|
|
171
171
|
};
|
|
172
172
|
// Create a single Aggregator for this agent if DNE yet; to be used by jserror endpoint features.
|
|
173
|
-
if (!agentRef.sharedAggregator) agentRef.sharedAggregator = new _eventStoreManager.EventStoreManager(agentRef.mainAppKey, 2);
|
|
173
|
+
if (!agentRef.sharedAggregator) agentRef.sharedAggregator = new _eventStoreManager.EventStoreManager(agentRef.mainAppKey, 2, agentRef.agentIdentifier, 'shared_aggregator');
|
|
174
174
|
if (!agentRef.runtime.harvester) agentRef.runtime.harvester = new _harvester.Harvester(agentRef);
|
|
175
175
|
}
|
|
176
176
|
|
|
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.EventStoreManager = void 0;
|
|
7
7
|
var _eventAggregator = require("../../common/aggregate/event-aggregator");
|
|
8
|
+
var _globalEvent = require("../../common/dispatch/global-event");
|
|
9
|
+
var _featureFlags = require("../../common/util/feature-flags");
|
|
8
10
|
var _eventBuffer = require("./event-buffer");
|
|
9
11
|
/**
|
|
10
12
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
@@ -19,12 +21,16 @@ class EventStoreManager {
|
|
|
19
21
|
/**
|
|
20
22
|
* @param {object} defaultTarget - should contain licenseKey and appId of the main app from NREUM.info at startup
|
|
21
23
|
* @param {1|2} storageChoice - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
|
|
24
|
+
* @param {string} agentIdentifier - agent identifier used in inspection events
|
|
25
|
+
* @param {string} featureName - feature name used in inspection events for non-shared aggregators
|
|
22
26
|
*/
|
|
23
|
-
constructor(defaultTarget, storageChoice) {
|
|
27
|
+
constructor(defaultTarget, storageChoice, agentIdentifier, featureName) {
|
|
24
28
|
this.mainApp = defaultTarget;
|
|
25
29
|
this.StorageClass = storageChoice === 1 ? _eventBuffer.EventBuffer : _eventAggregator.EventAggregator;
|
|
26
30
|
this.appStorageMap = new Map();
|
|
27
31
|
this.appStorageMap.set(defaultTarget, new this.StorageClass());
|
|
32
|
+
this.agentIdentifier = agentIdentifier;
|
|
33
|
+
this.featureName = featureName;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
// This class must contain an union of all methods from all supported storage classes and conceptualize away the target app argument.
|
|
@@ -50,6 +56,14 @@ class EventStoreManager {
|
|
|
50
56
|
* @returns {boolean} True if the event was successfully added
|
|
51
57
|
*/
|
|
52
58
|
add(event, target) {
|
|
59
|
+
(0, _globalEvent.dispatchGlobalEvent)({
|
|
60
|
+
agentIdentifier: this.agentIdentifier,
|
|
61
|
+
loaded: !!_featureFlags.activatedFeatures?.[this.agentIdentifier],
|
|
62
|
+
type: 'data',
|
|
63
|
+
name: 'buffer',
|
|
64
|
+
feature: this.featureName,
|
|
65
|
+
data: event
|
|
66
|
+
});
|
|
53
67
|
if (target && !this.appStorageMap.has(target)) this.appStorageMap.set(target, new this.StorageClass());
|
|
54
68
|
return this.appStorageMap.get(target || this.mainApp).add(event);
|
|
55
69
|
}
|
|
@@ -23,6 +23,8 @@ var _constants3 = require("../../common/session/constants");
|
|
|
23
23
|
var _constants4 = require("../../features/logging/constants");
|
|
24
24
|
var _utils = require("../../features/logging/shared/utils");
|
|
25
25
|
var _wrapLogger = require("../../common/wrap/wrap-logger");
|
|
26
|
+
var _globalEvent = require("../../common/dispatch/global-event");
|
|
27
|
+
var _featureFlags = require("../../common/util/feature-flags");
|
|
26
28
|
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); }
|
|
27
29
|
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; } /**
|
|
28
30
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
@@ -199,6 +201,17 @@ function setAPI(agentIdentifier, forceDrain, runSoftNavOverSpa = false) {
|
|
|
199
201
|
function apiCall(prefix, name, notSpa, bufferGroup) {
|
|
200
202
|
return function () {
|
|
201
203
|
(0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['API/' + name + '/called'], undefined, _features.FEATURE_NAMES.metrics, instanceEE);
|
|
204
|
+
(0, _globalEvent.dispatchGlobalEvent)({
|
|
205
|
+
agentIdentifier,
|
|
206
|
+
loaded: !!_featureFlags.activatedFeatures?.[agentIdentifier],
|
|
207
|
+
type: 'data',
|
|
208
|
+
name: 'api',
|
|
209
|
+
feature: prefix + name,
|
|
210
|
+
data: {
|
|
211
|
+
notSpa,
|
|
212
|
+
bufferGroup
|
|
213
|
+
}
|
|
214
|
+
});
|
|
202
215
|
if (bufferGroup) (0, _handle.handle)(prefix + name, [notSpa ? (0, _now.now)() : performance.now(), ...arguments], notSpa ? null : this, bufferGroup, instanceEE); // no bufferGroup means only the SM is emitted
|
|
203
216
|
return notSpa ? undefined : this; // returns the InteractionHandle which allows these methods to be chained
|
|
204
217
|
};
|
|
@@ -14,6 +14,7 @@ var _featureFlags = require("../../common/util/feature-flags");
|
|
|
14
14
|
var _runtime2 = require("../../common/constants/runtime");
|
|
15
15
|
var _publicPath = require("./public-path");
|
|
16
16
|
var _contextualEe = require("../../common/event-emitter/contextual-ee");
|
|
17
|
+
var _globalEvent = require("../../common/dispatch/global-event");
|
|
17
18
|
/**
|
|
18
19
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
19
20
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -70,5 +71,20 @@ function configure(agent, opts = {}, loaderType, forceDrain) {
|
|
|
70
71
|
agent.ee = _contextualEe.ee.get(agent.agentIdentifier);
|
|
71
72
|
if (agent.api === undefined) agent.api = (0, _api.setAPI)(agent.agentIdentifier, forceDrain, agent.runSoftNavOverSpa);
|
|
72
73
|
if (agent.exposed === undefined) agent.exposed = exposed;
|
|
74
|
+
if (!alreadySetOnce) {
|
|
75
|
+
(0, _globalEvent.dispatchGlobalEvent)({
|
|
76
|
+
agentIdentifier: agent.agentIdentifier,
|
|
77
|
+
loaded: !!_featureFlags.activatedFeatures?.[agent.agentIdentifier],
|
|
78
|
+
type: 'lifecycle',
|
|
79
|
+
name: 'initialize',
|
|
80
|
+
feature: undefined,
|
|
81
|
+
data: {
|
|
82
|
+
init: updatedInit,
|
|
83
|
+
info,
|
|
84
|
+
loader_config,
|
|
85
|
+
runtime
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
73
89
|
alreadySetOnce = true;
|
|
74
90
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.featurePriority = exports.RUM = exports.JSERRORS = exports.FEATURE_TO_ENDPOINT = exports.FEATURE_NAMES = exports.EVENTS = void 0;
|
|
6
|
+
exports.featurePriority = exports.RUM = exports.LOGS = exports.JSERRORS = exports.FEATURE_TO_ENDPOINT = exports.FEATURE_NAMES = exports.EVENTS = exports.BLOBS = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
9
9
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -12,8 +12,9 @@ exports.featurePriority = exports.RUM = exports.JSERRORS = exports.FEATURE_TO_EN
|
|
|
12
12
|
// To reduce build size a bit:
|
|
13
13
|
const EVENTS = exports.EVENTS = 'events';
|
|
14
14
|
const JSERRORS = exports.JSERRORS = 'jserrors';
|
|
15
|
-
const BLOBS = 'browser/blobs';
|
|
15
|
+
const BLOBS = exports.BLOBS = 'browser/blobs';
|
|
16
16
|
const RUM = exports.RUM = 'rum';
|
|
17
|
+
const LOGS = exports.LOGS = 'browser/logs';
|
|
17
18
|
const FEATURE_NAMES = exports.FEATURE_NAMES = {
|
|
18
19
|
ajax: 'ajax',
|
|
19
20
|
genericEvents: 'generic_events',
|
|
@@ -59,6 +60,6 @@ const FEATURE_TO_ENDPOINT = exports.FEATURE_TO_ENDPOINT = {
|
|
|
59
60
|
[FEATURE_NAMES.jserrors]: JSERRORS,
|
|
60
61
|
[FEATURE_NAMES.sessionTrace]: BLOBS,
|
|
61
62
|
[FEATURE_NAMES.sessionReplay]: BLOBS,
|
|
62
|
-
[FEATURE_NAMES.logging]:
|
|
63
|
+
[FEATURE_NAMES.logging]: LOGS,
|
|
63
64
|
[FEATURE_NAMES.genericEvents]: 'ins'
|
|
64
65
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants';
|
|
6
|
-
import { FEATURE_TO_ENDPOINT, JSERRORS, RUM, EVENTS, FEATURE_NAMES } from '../../loaders/features/features';
|
|
6
|
+
import { FEATURE_TO_ENDPOINT, JSERRORS, RUM, EVENTS, FEATURE_NAMES, BLOBS, LOGS } from '../../loaders/features/features';
|
|
7
7
|
import { VERSION } from "../constants/env.npm";
|
|
8
8
|
import { globalScope, isWorkerScope } from '../constants/runtime';
|
|
9
9
|
import { handle } from '../event-emitter/handle';
|
|
@@ -16,6 +16,8 @@ import { obj, param } from '../url/encode';
|
|
|
16
16
|
import { warn } from '../util/console';
|
|
17
17
|
import { stringify } from '../util/stringify';
|
|
18
18
|
import { getSubmitMethod, xhr as xhrMethod, xhrFetch as fetchMethod } from '../util/submit-data';
|
|
19
|
+
import { activatedFeatures } from '../util/feature-flags';
|
|
20
|
+
import { dispatchGlobalEvent } from '../dispatch/global-event';
|
|
19
21
|
const RETRY_FAILED = 'Harvester/Retry/Failed/';
|
|
20
22
|
const RETRY_SUCCEEDED = 'Harvester/Retry/Succeeded/';
|
|
21
23
|
export class Harvester {
|
|
@@ -81,7 +83,8 @@ export class Harvester {
|
|
|
81
83
|
localOpts,
|
|
82
84
|
submitMethod,
|
|
83
85
|
cbFinished,
|
|
84
|
-
raw: aggregateInst.harvestOpts.raw
|
|
86
|
+
raw: aggregateInst.harvestOpts.raw,
|
|
87
|
+
featureName: aggregateInst.featureName
|
|
85
88
|
});
|
|
86
89
|
ranSend = true;
|
|
87
90
|
});
|
|
@@ -123,7 +126,8 @@ function send(agentRef, {
|
|
|
123
126
|
localOpts = {},
|
|
124
127
|
submitMethod,
|
|
125
128
|
cbFinished,
|
|
126
|
-
raw
|
|
129
|
+
raw,
|
|
130
|
+
featureName
|
|
127
131
|
}) {
|
|
128
132
|
if (!agentRef.info.errorBeacon) return false;
|
|
129
133
|
let {
|
|
@@ -204,6 +208,22 @@ function send(agentRef, {
|
|
|
204
208
|
});
|
|
205
209
|
}
|
|
206
210
|
}
|
|
211
|
+
dispatchGlobalEvent({
|
|
212
|
+
agentIdentifier: agentRef.agentIdentifier,
|
|
213
|
+
loaded: !!activatedFeatures?.[agentRef.agentIdentifier],
|
|
214
|
+
type: 'data',
|
|
215
|
+
name: 'harvest',
|
|
216
|
+
feature: featureName,
|
|
217
|
+
data: {
|
|
218
|
+
endpoint,
|
|
219
|
+
headers,
|
|
220
|
+
targetApp,
|
|
221
|
+
payload,
|
|
222
|
+
submitMethod: getSubmitMethodName(),
|
|
223
|
+
raw,
|
|
224
|
+
synchronousXhr: !!(localOpts.isFinalHarvest && isWorkerScope)
|
|
225
|
+
}
|
|
226
|
+
});
|
|
207
227
|
return true;
|
|
208
228
|
function shouldRetry(status) {
|
|
209
229
|
switch (status) {
|
|
@@ -214,6 +234,11 @@ function send(agentRef, {
|
|
|
214
234
|
}
|
|
215
235
|
return status >= 502 && status <= 504 || status >= 512 && status <= 530;
|
|
216
236
|
}
|
|
237
|
+
function getSubmitMethodName() {
|
|
238
|
+
if (submitMethod === xhrMethod) return 'xhr';
|
|
239
|
+
if (submitMethod === fetchMethod) return 'fetch';
|
|
240
|
+
return 'beacon';
|
|
241
|
+
}
|
|
217
242
|
}
|
|
218
243
|
|
|
219
244
|
/**
|
|
@@ -245,12 +270,14 @@ function cleanPayload(payload = {}) {
|
|
|
245
270
|
function baseQueryString(agentRef, qs, endpoint, applicationID) {
|
|
246
271
|
const ref = agentRef.runtime.obfuscator.obfuscateString(cleanURL('' + globalScope.location));
|
|
247
272
|
const hr = agentRef.runtime.session?.state.sessionReplayMode === 1 && endpoint !== JSERRORS;
|
|
273
|
+
const ht = agentRef.runtime.session?.state.sessionTraceMode === 1 && ![LOGS, BLOBS].includes(endpoint);
|
|
248
274
|
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',
|
|
249
275
|
// ck param DEPRECATED - still expected by backend
|
|
250
276
|
'&s=' + (agentRef.runtime.session?.state.value || '0'),
|
|
251
277
|
// the 0 id encaps all untrackable and default traffic
|
|
252
278
|
param('ref', ref), param('ptid', agentRef.runtime.ptid ? '' + agentRef.runtime.ptid : '')];
|
|
253
279
|
if (hr) qps.push(param('hr', '1', qs));
|
|
280
|
+
if (ht) qps.push(param('ht', '1', qs));
|
|
254
281
|
return qps.join('');
|
|
255
282
|
|
|
256
283
|
// Constructs the transaction name param for the beacon URL.
|
|
@@ -27,6 +27,11 @@ export function activateFeatures(flags, agentIdentifier) {
|
|
|
27
27
|
|
|
28
28
|
// let any window level subscribers know that the agent is running
|
|
29
29
|
dispatchGlobalEvent({
|
|
30
|
-
|
|
30
|
+
agentIdentifier,
|
|
31
|
+
loaded: true,
|
|
32
|
+
type: 'lifecycle',
|
|
33
|
+
name: 'load',
|
|
34
|
+
feature: undefined,
|
|
35
|
+
data: flags
|
|
31
36
|
});
|
|
32
37
|
}
|
|
@@ -26,7 +26,7 @@ export class Aggregate extends AggregateBase {
|
|
|
26
26
|
});
|
|
27
27
|
this.ee.on(SESSION_EVENTS.UPDATE, (type, data) => {
|
|
28
28
|
if (this.blocked || type !== SESSION_EVENT_TYPES.CROSS_TAB) return;
|
|
29
|
-
if (this.
|
|
29
|
+
if (this.loggingMode !== LOGGING_MODE.OFF && data.loggingMode === LOGGING_MODE.OFF) this.abort(ABORT_REASONS.CROSS_TAB);else this.loggingMode = data.loggingMode;
|
|
30
30
|
});
|
|
31
31
|
this.harvestOpts.raw = true;
|
|
32
32
|
this.waitForFlags(['log']).then(([loggingMode]) => {
|
|
@@ -11,7 +11,7 @@ import { stylesheetEvaluator } from './stylesheet-evaluator';
|
|
|
11
11
|
import { handle } from '../../../common/event-emitter/handle';
|
|
12
12
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants';
|
|
13
13
|
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
14
|
-
import { buildNRMetaNode } from './utils';
|
|
14
|
+
import { buildNRMetaNode, customMasker } from './utils';
|
|
15
15
|
import { IDEAL_PAYLOAD_SIZE } from '../../../common/constants/agent-constants';
|
|
16
16
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
17
17
|
export class Recorder {
|
|
@@ -83,14 +83,7 @@ export class Recorder {
|
|
|
83
83
|
inline_images,
|
|
84
84
|
collect_fonts
|
|
85
85
|
} = this.parent.agentRef.init.session_replay;
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
if (typeof element?.type === 'string' && element.type.toLowerCase() !== 'password' && (element?.dataset?.nrUnmask !== undefined || element?.classList?.contains('nr-unmask'))) return text;
|
|
89
|
-
} catch (err) {
|
|
90
|
-
// likely an element was passed to this handler that was invalid and was missing attributes or methods
|
|
91
|
-
}
|
|
92
|
-
return '*'.repeat(text?.length || 0);
|
|
93
|
-
};
|
|
86
|
+
|
|
94
87
|
// set up rrweb configurations for maximum privacy --
|
|
95
88
|
// https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
|
|
96
89
|
const stop = recorder({
|
|
@@ -26,4 +26,15 @@ export function buildNRMetaNode(timestamp, timeKeeper) {
|
|
|
26
26
|
correctedOriginTime: timeKeeper.correctedOriginTime,
|
|
27
27
|
originTimeDiff: Math.floor(originTime - timeKeeper.correctedOriginTime)
|
|
28
28
|
};
|
|
29
|
+
}
|
|
30
|
+
export function customMasker(text, element) {
|
|
31
|
+
try {
|
|
32
|
+
if (typeof element?.type === 'string') {
|
|
33
|
+
if (element.type.toLowerCase() === 'password') return '*'.repeat(text?.length || 0);
|
|
34
|
+
if (element?.dataset?.nrUnmask !== undefined || element?.classList?.contains('nr-unmask')) return text;
|
|
35
|
+
}
|
|
36
|
+
} catch (err) {
|
|
37
|
+
// likely an element was passed to this handler that was invalid and was missing attributes or methods
|
|
38
|
+
}
|
|
39
|
+
return typeof text === 'string' ? text.replace(/[\S]/g, '*') : '*'.repeat(text?.length || 0);
|
|
29
40
|
}
|
|
@@ -36,7 +36,7 @@ export class AggregateBase extends FeatureBase {
|
|
|
36
36
|
This was necessary to prevent race cond. issues where the event buffer was checked before the feature could "block" itself.
|
|
37
37
|
Its easier to just keep an empty event buffer in place. */
|
|
38
38
|
default:
|
|
39
|
-
this.events = new EventStoreManager(agentRef.mainAppKey, 1);
|
|
39
|
+
this.events = new EventStoreManager(agentRef.mainAppKey, 1, agentRef.agentIdentifier, this.featureName);
|
|
40
40
|
break;
|
|
41
41
|
}
|
|
42
42
|
this.harvestOpts = {}; // features aggregate classes can define custom opts for when their harvest is called
|
|
@@ -163,7 +163,7 @@ export class AggregateBase extends FeatureBase {
|
|
|
163
163
|
appId: agentRef.info.applicationID
|
|
164
164
|
};
|
|
165
165
|
// Create a single Aggregator for this agent if DNE yet; to be used by jserror endpoint features.
|
|
166
|
-
if (!agentRef.sharedAggregator) agentRef.sharedAggregator = new EventStoreManager(agentRef.mainAppKey, 2);
|
|
166
|
+
if (!agentRef.sharedAggregator) agentRef.sharedAggregator = new EventStoreManager(agentRef.mainAppKey, 2, agentRef.agentIdentifier, 'shared_aggregator');
|
|
167
167
|
if (!agentRef.runtime.harvester) agentRef.runtime.harvester = new Harvester(agentRef);
|
|
168
168
|
}
|
|
169
169
|
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { EventAggregator } from '../../common/aggregate/event-aggregator';
|
|
6
|
+
import { dispatchGlobalEvent } from '../../common/dispatch/global-event';
|
|
7
|
+
import { activatedFeatures } from '../../common/util/feature-flags';
|
|
6
8
|
import { EventBuffer } from './event-buffer';
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -13,12 +15,16 @@ export class EventStoreManager {
|
|
|
13
15
|
/**
|
|
14
16
|
* @param {object} defaultTarget - should contain licenseKey and appId of the main app from NREUM.info at startup
|
|
15
17
|
* @param {1|2} storageChoice - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
|
|
18
|
+
* @param {string} agentIdentifier - agent identifier used in inspection events
|
|
19
|
+
* @param {string} featureName - feature name used in inspection events for non-shared aggregators
|
|
16
20
|
*/
|
|
17
|
-
constructor(defaultTarget, storageChoice) {
|
|
21
|
+
constructor(defaultTarget, storageChoice, agentIdentifier, featureName) {
|
|
18
22
|
this.mainApp = defaultTarget;
|
|
19
23
|
this.StorageClass = storageChoice === 1 ? EventBuffer : EventAggregator;
|
|
20
24
|
this.appStorageMap = new Map();
|
|
21
25
|
this.appStorageMap.set(defaultTarget, new this.StorageClass());
|
|
26
|
+
this.agentIdentifier = agentIdentifier;
|
|
27
|
+
this.featureName = featureName;
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
// This class must contain an union of all methods from all supported storage classes and conceptualize away the target app argument.
|
|
@@ -44,6 +50,14 @@ export class EventStoreManager {
|
|
|
44
50
|
* @returns {boolean} True if the event was successfully added
|
|
45
51
|
*/
|
|
46
52
|
add(event, target) {
|
|
53
|
+
dispatchGlobalEvent({
|
|
54
|
+
agentIdentifier: this.agentIdentifier,
|
|
55
|
+
loaded: !!activatedFeatures?.[this.agentIdentifier],
|
|
56
|
+
type: 'data',
|
|
57
|
+
name: 'buffer',
|
|
58
|
+
feature: this.featureName,
|
|
59
|
+
data: event
|
|
60
|
+
});
|
|
47
61
|
if (target && !this.appStorageMap.has(target)) this.appStorageMap.set(target, new this.StorageClass());
|
|
48
62
|
return this.appStorageMap.get(target || this.mainApp).add(event);
|
|
49
63
|
}
|
|
@@ -20,6 +20,8 @@ import { MODE } from '../../common/session/constants';
|
|
|
20
20
|
import { LOG_LEVELS } from '../../features/logging/constants';
|
|
21
21
|
import { bufferLog } from '../../features/logging/shared/utils';
|
|
22
22
|
import { wrapLogger } from '../../common/wrap/wrap-logger';
|
|
23
|
+
import { dispatchGlobalEvent } from '../../common/dispatch/global-event';
|
|
24
|
+
import { activatedFeatures } from '../../common/util/feature-flags';
|
|
23
25
|
export function setTopLevelCallers() {
|
|
24
26
|
const nr = gosCDN();
|
|
25
27
|
apiMethods.forEach(f => {
|
|
@@ -191,6 +193,17 @@ export function setAPI(agentIdentifier, forceDrain, runSoftNavOverSpa = false) {
|
|
|
191
193
|
function apiCall(prefix, name, notSpa, bufferGroup) {
|
|
192
194
|
return function () {
|
|
193
195
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/' + name + '/called'], undefined, FEATURE_NAMES.metrics, instanceEE);
|
|
196
|
+
dispatchGlobalEvent({
|
|
197
|
+
agentIdentifier,
|
|
198
|
+
loaded: !!activatedFeatures?.[agentIdentifier],
|
|
199
|
+
type: 'data',
|
|
200
|
+
name: 'api',
|
|
201
|
+
feature: prefix + name,
|
|
202
|
+
data: {
|
|
203
|
+
notSpa,
|
|
204
|
+
bufferGroup
|
|
205
|
+
}
|
|
206
|
+
});
|
|
194
207
|
if (bufferGroup) handle(prefix + name, [notSpa ? now() : performance.now(), ...arguments], notSpa ? null : this, bufferGroup, instanceEE); // no bufferGroup means only the SM is emitted
|
|
195
208
|
return notSpa ? undefined : this; // returns the InteractionHandle which allows these methods to be chained
|
|
196
209
|
};
|
|
@@ -12,6 +12,7 @@ import { activatedFeatures } from '../../common/util/feature-flags';
|
|
|
12
12
|
import { isWorkerScope } from '../../common/constants/runtime';
|
|
13
13
|
import { redefinePublicPath } from './public-path';
|
|
14
14
|
import { ee } from '../../common/event-emitter/contextual-ee';
|
|
15
|
+
import { dispatchGlobalEvent } from '../../common/dispatch/global-event';
|
|
15
16
|
let alreadySetOnce = false; // the configure() function can run multiple times in agent lifecycle
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -63,5 +64,20 @@ export function configure(agent, opts = {}, loaderType, forceDrain) {
|
|
|
63
64
|
agent.ee = ee.get(agent.agentIdentifier);
|
|
64
65
|
if (agent.api === undefined) agent.api = setAPI(agent.agentIdentifier, forceDrain, agent.runSoftNavOverSpa);
|
|
65
66
|
if (agent.exposed === undefined) agent.exposed = exposed;
|
|
67
|
+
if (!alreadySetOnce) {
|
|
68
|
+
dispatchGlobalEvent({
|
|
69
|
+
agentIdentifier: agent.agentIdentifier,
|
|
70
|
+
loaded: !!activatedFeatures?.[agent.agentIdentifier],
|
|
71
|
+
type: 'lifecycle',
|
|
72
|
+
name: 'initialize',
|
|
73
|
+
feature: undefined,
|
|
74
|
+
data: {
|
|
75
|
+
init: updatedInit,
|
|
76
|
+
info,
|
|
77
|
+
loader_config,
|
|
78
|
+
runtime
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
66
82
|
alreadySetOnce = true;
|
|
67
83
|
}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
// To reduce build size a bit:
|
|
7
7
|
export const EVENTS = 'events';
|
|
8
8
|
export const JSERRORS = 'jserrors';
|
|
9
|
-
const BLOBS = 'browser/blobs';
|
|
9
|
+
export const BLOBS = 'browser/blobs';
|
|
10
10
|
export const RUM = 'rum';
|
|
11
|
+
export const LOGS = 'browser/logs';
|
|
11
12
|
export const FEATURE_NAMES = {
|
|
12
13
|
ajax: 'ajax',
|
|
13
14
|
genericEvents: 'generic_events',
|
|
@@ -53,6 +54,6 @@ export const FEATURE_TO_ENDPOINT = {
|
|
|
53
54
|
[FEATURE_NAMES.jserrors]: JSERRORS,
|
|
54
55
|
[FEATURE_NAMES.sessionTrace]: BLOBS,
|
|
55
56
|
[FEATURE_NAMES.sessionReplay]: BLOBS,
|
|
56
|
-
[FEATURE_NAMES.logging]:
|
|
57
|
+
[FEATURE_NAMES.logging]: LOGS,
|
|
57
58
|
[FEATURE_NAMES.genericEvents]: 'ins'
|
|
58
59
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harvester.d.ts","sourceRoot":"","sources":["../../../../src/common/harvest/harvester.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"harvester.d.ts","sourceRoot":"","sources":["../../../../src/common/harvest/harvester.js"],"names":[],"mappings":"AAwBA;IAIE,2BAcC;IAhBD,6BAA0B;IAGxB,cAAwB;IAe1B,wCASC;IAED;;;;;OAKG;IACH,iCAJW,MAAM,cACN,MAAM,GACJ,OAAO,CA+CnB;;CACF;8BAGY,OAAO,YAAY,EAAE,eAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-flags.d.ts","sourceRoot":"","sources":["../../../../src/common/util/feature-flags.js"],"names":[],"mappings":"AAYA;;;;;;GAMG;AACH,wCAJW;IAAC,CAAC,GAAG,EAAC,MAAM,GAAE,MAAM,CAAA;CAAC,mBACrB,MAAM,GACJ,IAAI,
|
|
1
|
+
{"version":3,"file":"feature-flags.d.ts","sourceRoot":"","sources":["../../../../src/common/util/feature-flags.js"],"names":[],"mappings":"AAYA;;;;;;GAMG;AACH,wCAJW;IAAC,CAAC,GAAG,EAAC,MAAM,GAAE,MAAM,CAAA;CAAC,mBACrB,MAAM,GACJ,IAAI,CAsBhB;AA9BD,gGAAgG;AAChG,mCAAmC"}
|
|
@@ -2,7 +2,6 @@ export class Aggregate extends AggregateBase {
|
|
|
2
2
|
static featureName: string;
|
|
3
3
|
constructor(agentRef: any);
|
|
4
4
|
isSessionTrackingEnabled: any;
|
|
5
|
-
mode: any;
|
|
6
5
|
loggingMode: any;
|
|
7
6
|
updateLoggingMode(loggingMode: any): void;
|
|
8
7
|
handleLog(timestamp: any, message: any, attributes?: {}, level?: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/aggregate/index.js"],"names":[],"mappings":"AAiBA;IACE,2BAAiC;IACjC,2BAmCC;IAjCC,8BAA+G;IAUxG,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/aggregate/index.js"],"names":[],"mappings":"AAiBA;IACE,2BAAiC;IACjC,2BAmCC;IAjCC,8BAA+G;IAUxG,iBAAmC;IAyB5C,0CAKC;IAED,+EAuDC;IAED;;YAIM,0FAA0F;;;QAoB5F,0DAA0D;;QAM7D;IAED;;MAEC;IAED,yDAAyD;IACzD,yBAOC;IAED,yCAIC;CACF;8BApK6B,4BAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder.js"],"names":[],"mappings":"AAiBA;IAUE,yBAkBC;IAdC,iEAAiE;IACjE,mBAAsB;IACtB,6DAA6D;IAC7D,oCAAuC;IACvC,+IAA+I;IAC/I,yBAA4B;IAC5B,kIAAkI;IAClI,kBAAqB;IACrB,sDAAsD;IACtD,YAAoB;IACpB,0FAA0F;IAC1F,eAAyE;IACzE,uIAAuI;IACvI,0BAAyE;IAG3E;;;;;;;;;MAmBC;IAED,mFAAmF;IACnF,oBAKC;IAED,qDAAqD;IACrD,
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder.js"],"names":[],"mappings":"AAiBA;IAUE,yBAkBC;IAdC,iEAAiE;IACjE,mBAAsB;IACtB,6DAA6D;IAC7D,oCAAuC;IACvC,+IAA+I;IAC/I,yBAA4B;IAC5B,kIAAkI;IAClI,kBAAqB;IACrB,sDAAsD;IACtD,YAAoB;IACpB,0FAA0F;IAC1F,eAAyE;IACzE,uIAAuI;IACvI,0BAAyE;IAG3E;;;;;;;;;MAmBC;IAED,mFAAmF;IACnF,oBAKC;IAED,qDAAqD;IACrD,uBA6BC;IAED;;;;;OAKG;IACH,aAHW,GAAC,cACD,GAAC,QAgCX;IAED,0HAA0H;IAC1H,yCAoDC;IA1CG,8BAAoB;IA4CxB,0HAA0H;IAC1H,yBAOC;IAED,wBAEC;IAED,gCAAgC;IAChC,uCAGC;IAED;;;SAGK;IACL,oCAGC;;CACF;+BA9N8B,mBAAmB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/utils.js"],"names":[],"mappings":"AASA,6DAIC;AAED,wDAEC;AAED;;;;;;;EAUC"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/utils.js"],"names":[],"mappings":"AASA,6DAIC;AAED,wDAEC;AAED;;;;;;;EAUC;AAED,2DAUC"}
|
|
@@ -6,11 +6,15 @@ export class EventStoreManager {
|
|
|
6
6
|
/**
|
|
7
7
|
* @param {object} defaultTarget - should contain licenseKey and appId of the main app from NREUM.info at startup
|
|
8
8
|
* @param {1|2} storageChoice - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
|
|
9
|
+
* @param {string} agentIdentifier - agent identifier used in inspection events
|
|
10
|
+
* @param {string} featureName - feature name used in inspection events for non-shared aggregators
|
|
9
11
|
*/
|
|
10
|
-
constructor(defaultTarget: object, storageChoice: 1 | 2);
|
|
12
|
+
constructor(defaultTarget: object, storageChoice: 1 | 2, agentIdentifier: string, featureName: string);
|
|
11
13
|
mainApp: object;
|
|
12
14
|
StorageClass: typeof EventAggregator | typeof EventBuffer;
|
|
13
15
|
appStorageMap: Map<any, any>;
|
|
16
|
+
agentIdentifier: string;
|
|
17
|
+
featureName: string;
|
|
14
18
|
/**
|
|
15
19
|
* @param {object} optsIfPresent - exists if called during harvest interval, @see AggregateBase.makeHarvestPayload
|
|
16
20
|
* @param {object} target - specific app's storage to check; if not provided, this method takes into account all apps recorded by this manager
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-store-manager.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/event-store-manager.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"event-store-manager.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/event-store-manager.js"],"names":[],"mappings":"AASA;;;GAGG;AACH;IACE;;;;;OAKG;IACH,2BALW,MAAM,iBACN,CAAC,GAAC,CAAC,mBACH,MAAM,eACN,MAAM,EAShB;IANC,gBAA4B;IAC5B,0DAAuE;IACvE,6BAA8B;IAE9B,wBAAsC;IACtC,oBAA8B;IAKhC;;;;OAIG;IACH,uBAJW,MAAM,UACN,MAAM,GACJ,OAAO,CAWnB;IAED;;;;OAIG;IACH,WAJW,MAAM,UACN,MAAM,GACJ,OAAO,CAanB;IAED,0GAA0G;IAC1G,8DAEC;IAED;;;;OAIG;IACH,mBAJW,MAAM,UACN,MAAM,SAUhB;IAED,2BAEC;IAED,wDAEC;IAED,2CAGC;IAED,4CAGC;IAGD,iDAMC;IAED,gDAMC;CACF;gCAlH+B,yCAAyC;4BAG7C,gBAAgB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/api.js"],"names":[],"mappings":"AAyBA,2CAiBC;AAID;;;;;;;;;;;;;qBAqEa,MAAM;iCAaN,MAAM,GAAC,IAAI;;;;;EAyGvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../../../../src/loaders/configure/configure.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../../../../src/loaders/configure/configure.js"],"names":[],"mappings":"AAkBA;;GAEG;AACH,oGA+DC"}
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export const EVENTS: "events";
|
|
6
6
|
export const JSERRORS: "jserrors";
|
|
7
|
+
export const BLOBS: "browser/blobs";
|
|
7
8
|
export const RUM: "rum";
|
|
9
|
+
export const LOGS: "browser/logs";
|
|
8
10
|
export namespace FEATURE_NAMES {
|
|
9
11
|
export let ajax: string;
|
|
10
12
|
export let genericEvents: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../../../src/loaders/features/features.js"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,qBAAsB,QAAQ,CAAA;AAC9B,uBAAwB,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../../../src/loaders/features/features.js"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,qBAAsB,QAAQ,CAAA;AAC9B,uBAAwB,UAAU,CAAA;AAClC,oBAAqB,eAAe,CAAA;AACpC,kBAAmB,KAAK,CAAA;AACxB,mBAAoB,cAAc,CAAA;;;;;;;;;;;;;;;AAoBlC;;;GAGG;AACH;;EAYC;AAED;;EAYC"}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants'
|
|
6
|
-
import { FEATURE_TO_ENDPOINT, JSERRORS, RUM, EVENTS, FEATURE_NAMES } from '../../loaders/features/features'
|
|
6
|
+
import { FEATURE_TO_ENDPOINT, JSERRORS, RUM, EVENTS, FEATURE_NAMES, BLOBS, LOGS } from '../../loaders/features/features'
|
|
7
7
|
import { VERSION } from '../constants/env'
|
|
8
8
|
import { globalScope, isWorkerScope } from '../constants/runtime'
|
|
9
9
|
import { handle } from '../event-emitter/handle'
|
|
@@ -16,6 +16,8 @@ import { obj, param } from '../url/encode'
|
|
|
16
16
|
import { warn } from '../util/console'
|
|
17
17
|
import { stringify } from '../util/stringify'
|
|
18
18
|
import { getSubmitMethod, xhr as xhrMethod, xhrFetch as fetchMethod } from '../util/submit-data'
|
|
19
|
+
import { activatedFeatures } from '../util/feature-flags'
|
|
20
|
+
import { dispatchGlobalEvent } from '../dispatch/global-event'
|
|
19
21
|
|
|
20
22
|
const RETRY_FAILED = 'Harvester/Retry/Failed/'
|
|
21
23
|
const RETRY_SUCCEEDED = 'Harvester/Retry/Succeeded/'
|
|
@@ -80,7 +82,8 @@ export class Harvester {
|
|
|
80
82
|
localOpts,
|
|
81
83
|
submitMethod,
|
|
82
84
|
cbFinished,
|
|
83
|
-
raw: aggregateInst.harvestOpts.raw
|
|
85
|
+
raw: aggregateInst.harvestOpts.raw,
|
|
86
|
+
featureName: aggregateInst.featureName
|
|
84
87
|
})
|
|
85
88
|
ranSend = true
|
|
86
89
|
})
|
|
@@ -114,7 +117,7 @@ const warnings = {}
|
|
|
114
117
|
* @param {NetworkSendSpec} param0 Specification for sending data
|
|
115
118
|
* @returns {boolean} True if a network call was made. Note that this does not mean or guarantee that it was successful.
|
|
116
119
|
*/
|
|
117
|
-
function send (agentRef, { endpoint, targetApp, payload, localOpts = {}, submitMethod, cbFinished, raw }) {
|
|
120
|
+
function send (agentRef, { endpoint, targetApp, payload, localOpts = {}, submitMethod, cbFinished, raw, featureName }) {
|
|
118
121
|
if (!agentRef.info.errorBeacon) return false
|
|
119
122
|
|
|
120
123
|
let { body, qs } = cleanPayload(payload)
|
|
@@ -172,6 +175,24 @@ function send (agentRef, { endpoint, targetApp, payload, localOpts = {}, submitM
|
|
|
172
175
|
})
|
|
173
176
|
}
|
|
174
177
|
}
|
|
178
|
+
|
|
179
|
+
dispatchGlobalEvent({
|
|
180
|
+
agentIdentifier: agentRef.agentIdentifier,
|
|
181
|
+
loaded: !!activatedFeatures?.[agentRef.agentIdentifier],
|
|
182
|
+
type: 'data',
|
|
183
|
+
name: 'harvest',
|
|
184
|
+
feature: featureName,
|
|
185
|
+
data: {
|
|
186
|
+
endpoint,
|
|
187
|
+
headers,
|
|
188
|
+
targetApp,
|
|
189
|
+
payload,
|
|
190
|
+
submitMethod: getSubmitMethodName(),
|
|
191
|
+
raw,
|
|
192
|
+
synchronousXhr: !!(localOpts.isFinalHarvest && isWorkerScope)
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
|
|
175
196
|
return true
|
|
176
197
|
|
|
177
198
|
function shouldRetry (status) {
|
|
@@ -183,6 +204,12 @@ function send (agentRef, { endpoint, targetApp, payload, localOpts = {}, submitM
|
|
|
183
204
|
}
|
|
184
205
|
return (status >= 502 && status <= 504) || (status >= 512 && status <= 530)
|
|
185
206
|
}
|
|
207
|
+
|
|
208
|
+
function getSubmitMethodName () {
|
|
209
|
+
if (submitMethod === xhrMethod) return 'xhr'
|
|
210
|
+
if (submitMethod === fetchMethod) return 'fetch'
|
|
211
|
+
return 'beacon'
|
|
212
|
+
}
|
|
186
213
|
}
|
|
187
214
|
|
|
188
215
|
/**
|
|
@@ -218,6 +245,7 @@ function cleanPayload (payload = {}) {
|
|
|
218
245
|
function baseQueryString (agentRef, qs, endpoint, applicationID) {
|
|
219
246
|
const ref = agentRef.runtime.obfuscator.obfuscateString(cleanURL('' + globalScope.location))
|
|
220
247
|
const hr = agentRef.runtime.session?.state.sessionReplayMode === 1 && endpoint !== JSERRORS
|
|
248
|
+
const ht = agentRef.runtime.session?.state.sessionTraceMode === 1 && ![LOGS, BLOBS].includes(endpoint)
|
|
221
249
|
|
|
222
250
|
const qps = [
|
|
223
251
|
'a=' + applicationID,
|
|
@@ -232,6 +260,8 @@ function baseQueryString (agentRef, qs, endpoint, applicationID) {
|
|
|
232
260
|
param('ptid', (agentRef.runtime.ptid ? '' + agentRef.runtime.ptid : ''))
|
|
233
261
|
]
|
|
234
262
|
if (hr) qps.push(param('hr', '1', qs))
|
|
263
|
+
if (ht) qps.push(param('ht', '1', qs))
|
|
264
|
+
|
|
235
265
|
return qps.join('')
|
|
236
266
|
|
|
237
267
|
// Constructs the transaction name param for the beacon URL.
|
|
@@ -29,5 +29,12 @@ export function activateFeatures (flags, agentIdentifier) {
|
|
|
29
29
|
sentIds.add(agentIdentifier)
|
|
30
30
|
|
|
31
31
|
// let any window level subscribers know that the agent is running
|
|
32
|
-
dispatchGlobalEvent({
|
|
32
|
+
dispatchGlobalEvent({
|
|
33
|
+
agentIdentifier,
|
|
34
|
+
loaded: true,
|
|
35
|
+
type: 'lifecycle',
|
|
36
|
+
name: 'load',
|
|
37
|
+
feature: undefined,
|
|
38
|
+
data: flags
|
|
39
|
+
})
|
|
33
40
|
}
|
|
@@ -28,8 +28,8 @@ export class Aggregate extends AggregateBase {
|
|
|
28
28
|
|
|
29
29
|
this.ee.on(SESSION_EVENTS.UPDATE, (type, data) => {
|
|
30
30
|
if (this.blocked || type !== SESSION_EVENT_TYPES.CROSS_TAB) return
|
|
31
|
-
if (this.
|
|
32
|
-
else this.
|
|
31
|
+
if (this.loggingMode !== LOGGING_MODE.OFF && data.loggingMode === LOGGING_MODE.OFF) this.abort(ABORT_REASONS.CROSS_TAB)
|
|
32
|
+
else this.loggingMode = data.loggingMode
|
|
33
33
|
})
|
|
34
34
|
|
|
35
35
|
this.harvestOpts.raw = true
|
|
@@ -11,7 +11,7 @@ import { stylesheetEvaluator } from './stylesheet-evaluator'
|
|
|
11
11
|
import { handle } from '../../../common/event-emitter/handle'
|
|
12
12
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
13
13
|
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
14
|
-
import { buildNRMetaNode } from './utils'
|
|
14
|
+
import { buildNRMetaNode, customMasker } from './utils'
|
|
15
15
|
import { IDEAL_PAYLOAD_SIZE } from '../../../common/constants/agent-constants'
|
|
16
16
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
17
17
|
|
|
@@ -78,14 +78,7 @@ export class Recorder {
|
|
|
78
78
|
startRecording () {
|
|
79
79
|
this.recording = true
|
|
80
80
|
const { block_class, ignore_class, mask_text_class, block_selector, mask_input_options, mask_text_selector, mask_all_inputs, inline_images, collect_fonts } = this.parent.agentRef.init.session_replay
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
if (typeof element?.type === 'string' && element.type.toLowerCase() !== 'password' && (element?.dataset?.nrUnmask !== undefined || element?.classList?.contains('nr-unmask'))) return text
|
|
84
|
-
} catch (err) {
|
|
85
|
-
// likely an element was passed to this handler that was invalid and was missing attributes or methods
|
|
86
|
-
}
|
|
87
|
-
return '*'.repeat(text?.length || 0)
|
|
88
|
-
}
|
|
81
|
+
|
|
89
82
|
// set up rrweb configurations for maximum privacy --
|
|
90
83
|
// https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
|
|
91
84
|
const stop = recorder({
|
|
@@ -28,3 +28,15 @@ export function buildNRMetaNode (timestamp, timeKeeper) {
|
|
|
28
28
|
originTimeDiff: Math.floor(originTime - timeKeeper.correctedOriginTime)
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
export function customMasker (text, element) {
|
|
33
|
+
try {
|
|
34
|
+
if (typeof element?.type === 'string') {
|
|
35
|
+
if (element.type.toLowerCase() === 'password') return '*'.repeat(text?.length || 0)
|
|
36
|
+
if (element?.dataset?.nrUnmask !== undefined || element?.classList?.contains('nr-unmask')) return text
|
|
37
|
+
}
|
|
38
|
+
} catch (err) {
|
|
39
|
+
// likely an element was passed to this handler that was invalid and was missing attributes or methods
|
|
40
|
+
}
|
|
41
|
+
return typeof text === 'string' ? text.replace(/[\S]/g, '*') : '*'.repeat(text?.length || 0)
|
|
42
|
+
}
|
|
@@ -37,7 +37,7 @@ export class AggregateBase extends FeatureBase {
|
|
|
37
37
|
This was necessary to prevent race cond. issues where the event buffer was checked before the feature could "block" itself.
|
|
38
38
|
Its easier to just keep an empty event buffer in place. */
|
|
39
39
|
default:
|
|
40
|
-
this.events = new EventStoreManager(agentRef.mainAppKey, 1)
|
|
40
|
+
this.events = new EventStoreManager(agentRef.mainAppKey, 1, agentRef.agentIdentifier, this.featureName)
|
|
41
41
|
break
|
|
42
42
|
}
|
|
43
43
|
this.harvestOpts = {} // features aggregate classes can define custom opts for when their harvest is called
|
|
@@ -157,7 +157,7 @@ export class AggregateBase extends FeatureBase {
|
|
|
157
157
|
|
|
158
158
|
if (!agentRef.mainAppKey) agentRef.mainAppKey = { licenseKey: agentRef.info.licenseKey, appId: agentRef.info.applicationID }
|
|
159
159
|
// Create a single Aggregator for this agent if DNE yet; to be used by jserror endpoint features.
|
|
160
|
-
if (!agentRef.sharedAggregator) agentRef.sharedAggregator = new EventStoreManager(agentRef.mainAppKey, 2)
|
|
160
|
+
if (!agentRef.sharedAggregator) agentRef.sharedAggregator = new EventStoreManager(agentRef.mainAppKey, 2, agentRef.agentIdentifier, 'shared_aggregator')
|
|
161
161
|
|
|
162
162
|
if (!agentRef.runtime.harvester) agentRef.runtime.harvester = new Harvester(agentRef)
|
|
163
163
|
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { EventAggregator } from '../../common/aggregate/event-aggregator'
|
|
6
|
+
import { dispatchGlobalEvent } from '../../common/dispatch/global-event'
|
|
7
|
+
import { activatedFeatures } from '../../common/util/feature-flags'
|
|
6
8
|
import { EventBuffer } from './event-buffer'
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -13,12 +15,16 @@ export class EventStoreManager {
|
|
|
13
15
|
/**
|
|
14
16
|
* @param {object} defaultTarget - should contain licenseKey and appId of the main app from NREUM.info at startup
|
|
15
17
|
* @param {1|2} storageChoice - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
|
|
18
|
+
* @param {string} agentIdentifier - agent identifier used in inspection events
|
|
19
|
+
* @param {string} featureName - feature name used in inspection events for non-shared aggregators
|
|
16
20
|
*/
|
|
17
|
-
constructor (defaultTarget, storageChoice) {
|
|
21
|
+
constructor (defaultTarget, storageChoice, agentIdentifier, featureName) {
|
|
18
22
|
this.mainApp = defaultTarget
|
|
19
23
|
this.StorageClass = storageChoice === 1 ? EventBuffer : EventAggregator
|
|
20
24
|
this.appStorageMap = new Map()
|
|
21
25
|
this.appStorageMap.set(defaultTarget, new this.StorageClass())
|
|
26
|
+
this.agentIdentifier = agentIdentifier
|
|
27
|
+
this.featureName = featureName
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
// This class must contain an union of all methods from all supported storage classes and conceptualize away the target app argument.
|
|
@@ -45,6 +51,14 @@ export class EventStoreManager {
|
|
|
45
51
|
* @returns {boolean} True if the event was successfully added
|
|
46
52
|
*/
|
|
47
53
|
add (event, target) {
|
|
54
|
+
dispatchGlobalEvent({
|
|
55
|
+
agentIdentifier: this.agentIdentifier,
|
|
56
|
+
loaded: !!activatedFeatures?.[this.agentIdentifier],
|
|
57
|
+
type: 'data',
|
|
58
|
+
name: 'buffer',
|
|
59
|
+
feature: this.featureName,
|
|
60
|
+
data: event
|
|
61
|
+
})
|
|
48
62
|
if (target && !this.appStorageMap.has(target)) this.appStorageMap.set(target, new this.StorageClass())
|
|
49
63
|
return this.appStorageMap.get(target || this.mainApp).add(event)
|
|
50
64
|
}
|
package/src/loaders/api/api.js
CHANGED
|
@@ -20,6 +20,8 @@ import { MODE } from '../../common/session/constants'
|
|
|
20
20
|
import { LOG_LEVELS } from '../../features/logging/constants'
|
|
21
21
|
import { bufferLog } from '../../features/logging/shared/utils'
|
|
22
22
|
import { wrapLogger } from '../../common/wrap/wrap-logger'
|
|
23
|
+
import { dispatchGlobalEvent } from '../../common/dispatch/global-event'
|
|
24
|
+
import { activatedFeatures } from '../../common/util/feature-flags'
|
|
23
25
|
|
|
24
26
|
export function setTopLevelCallers () {
|
|
25
27
|
const nr = gosCDN()
|
|
@@ -194,6 +196,14 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
|
|
|
194
196
|
function apiCall (prefix, name, notSpa, bufferGroup) {
|
|
195
197
|
return function () {
|
|
196
198
|
handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/' + name + '/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
|
|
199
|
+
dispatchGlobalEvent({
|
|
200
|
+
agentIdentifier,
|
|
201
|
+
loaded: !!activatedFeatures?.[agentIdentifier],
|
|
202
|
+
type: 'data',
|
|
203
|
+
name: 'api',
|
|
204
|
+
feature: prefix + name,
|
|
205
|
+
data: { notSpa, bufferGroup }
|
|
206
|
+
})
|
|
197
207
|
if (bufferGroup) handle(prefix + name, [notSpa ? now() : performance.now(), ...arguments], notSpa ? null : this, bufferGroup, instanceEE) // no bufferGroup means only the SM is emitted
|
|
198
208
|
return notSpa ? undefined : this // returns the InteractionHandle which allows these methods to be chained
|
|
199
209
|
}
|
|
@@ -12,6 +12,7 @@ import { activatedFeatures } from '../../common/util/feature-flags'
|
|
|
12
12
|
import { isWorkerScope } from '../../common/constants/runtime'
|
|
13
13
|
import { redefinePublicPath } from './public-path'
|
|
14
14
|
import { ee } from '../../common/event-emitter/contextual-ee'
|
|
15
|
+
import { dispatchGlobalEvent } from '../../common/dispatch/global-event'
|
|
15
16
|
|
|
16
17
|
let alreadySetOnce = false // the configure() function can run multiple times in agent lifecycle
|
|
17
18
|
|
|
@@ -68,5 +69,17 @@ export function configure (agent, opts = {}, loaderType, forceDrain) {
|
|
|
68
69
|
|
|
69
70
|
if (agent.api === undefined) agent.api = setAPI(agent.agentIdentifier, forceDrain, agent.runSoftNavOverSpa)
|
|
70
71
|
if (agent.exposed === undefined) agent.exposed = exposed
|
|
72
|
+
|
|
73
|
+
if (!alreadySetOnce) {
|
|
74
|
+
dispatchGlobalEvent({
|
|
75
|
+
agentIdentifier: agent.agentIdentifier,
|
|
76
|
+
loaded: !!activatedFeatures?.[agent.agentIdentifier],
|
|
77
|
+
type: 'lifecycle',
|
|
78
|
+
name: 'initialize',
|
|
79
|
+
feature: undefined,
|
|
80
|
+
data: { init: updatedInit, info, loader_config, runtime }
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
71
84
|
alreadySetOnce = true
|
|
72
85
|
}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
// To reduce build size a bit:
|
|
7
7
|
export const EVENTS = 'events'
|
|
8
8
|
export const JSERRORS = 'jserrors'
|
|
9
|
-
const BLOBS = 'browser/blobs'
|
|
9
|
+
export const BLOBS = 'browser/blobs'
|
|
10
10
|
export const RUM = 'rum'
|
|
11
|
+
export const LOGS = 'browser/logs'
|
|
11
12
|
|
|
12
13
|
export const FEATURE_NAMES = {
|
|
13
14
|
ajax: 'ajax',
|
|
@@ -55,6 +56,6 @@ export const FEATURE_TO_ENDPOINT = {
|
|
|
55
56
|
[FEATURE_NAMES.jserrors]: JSERRORS,
|
|
56
57
|
[FEATURE_NAMES.sessionTrace]: BLOBS,
|
|
57
58
|
[FEATURE_NAMES.sessionReplay]: BLOBS,
|
|
58
|
-
[FEATURE_NAMES.logging]:
|
|
59
|
+
[FEATURE_NAMES.logging]: LOGS,
|
|
59
60
|
[FEATURE_NAMES.genericEvents]: 'ins'
|
|
60
61
|
}
|