@newrelic/browser-agent 1.295.0 → 1.296.0-rc.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 +12 -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/wrap/wrap-events.js +2 -1
- package/dist/cjs/features/session_trace/aggregate/index.js +20 -21
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +198 -185
- package/dist/cjs/features/session_trace/aggregate/trace/utils.js +41 -0
- package/dist/cjs/features/session_trace/constants.js +3 -2
- package/dist/cjs/features/utils/aggregate-base.js +1 -2
- package/dist/cjs/features/utils/event-buffer.js +34 -3
- package/dist/cjs/features/utils/event-store-manager.js +18 -11
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/wrap/wrap-events.js +2 -1
- package/dist/esm/features/session_trace/aggregate/index.js +21 -21
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +199 -186
- package/dist/esm/features/session_trace/aggregate/trace/utils.js +34 -0
- package/dist/esm/features/session_trace/constants.js +2 -1
- package/dist/esm/features/utils/aggregate-base.js +1 -2
- package/dist/esm/features/utils/event-buffer.js +34 -3
- package/dist/esm/features/utils/event-store-manager.js +18 -11
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/wrap/wrap-events.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts +5 -10
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +81 -39
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/trace/utils.d.ts +7 -0
- package/dist/types/features/session_trace/aggregate/trace/utils.d.ts.map +1 -0
- package/dist/types/features/session_trace/constants.d.ts +1 -0
- package/dist/types/features/session_trace/constants.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/event-buffer.d.ts +18 -1
- package/dist/types/features/utils/event-buffer.d.ts.map +1 -1
- package/dist/types/features/utils/event-store-manager.d.ts +12 -0
- package/dist/types/features/utils/event-store-manager.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/common/wrap/wrap-events.js +2 -1
- package/src/features/session_trace/aggregate/index.js +23 -15
- package/src/features/session_trace/aggregate/trace/storage.js +186 -189
- package/src/features/session_trace/aggregate/trace/utils.js +35 -0
- package/src/features/session_trace/constants.js +1 -0
- package/src/features/utils/aggregate-base.js +1 -2
- package/src/features/utils/event-buffer.js +35 -3
- package/src/features/utils/event-store-manager.js +18 -11
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.evtName = evtName;
|
|
7
|
+
exports.isTrivial = isTrivial;
|
|
8
|
+
/**
|
|
9
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
10
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
11
|
+
*/
|
|
12
|
+
function evtName(type) {
|
|
13
|
+
switch (type) {
|
|
14
|
+
case 'keydown':
|
|
15
|
+
case 'keyup':
|
|
16
|
+
case 'keypress':
|
|
17
|
+
return 'typing';
|
|
18
|
+
case 'mousemove':
|
|
19
|
+
case 'mouseenter':
|
|
20
|
+
case 'mouseleave':
|
|
21
|
+
case 'mouseover':
|
|
22
|
+
case 'mouseout':
|
|
23
|
+
return 'mousing';
|
|
24
|
+
case 'touchstart':
|
|
25
|
+
case 'touchmove':
|
|
26
|
+
case 'touchend':
|
|
27
|
+
case 'touchcancel':
|
|
28
|
+
case 'touchenter':
|
|
29
|
+
case 'touchleave':
|
|
30
|
+
return 'touching';
|
|
31
|
+
case 'scroll':
|
|
32
|
+
case 'scrollend':
|
|
33
|
+
return 'scrolling';
|
|
34
|
+
default:
|
|
35
|
+
return type;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function isTrivial(node) {
|
|
39
|
+
const limit = 4;
|
|
40
|
+
return !!(node && typeof node.e === 'number' && typeof node.s === 'number' && node.e - node.s < limit);
|
|
41
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.START = exports.RESOURCE = exports.PUSH_STATE = exports.MAX_NODES_PER_HARVEST = exports.FN_START = exports.FN_END = exports.FEATURE_NAME = exports.END = exports.BST_RESOURCE = void 0;
|
|
6
|
+
exports.START = exports.RESOURCE = exports.PUSH_STATE = exports.MAX_NODES_PER_HARVEST = exports.FN_START = exports.FN_END = exports.FEATURE_NAME = exports.ERROR_MODE_SECONDS_WINDOW = exports.END = exports.BST_RESOURCE = void 0;
|
|
7
7
|
var _features = require("../../loaders/features/features");
|
|
8
8
|
/**
|
|
9
9
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
@@ -18,4 +18,5 @@ const END = exports.END = '-end';
|
|
|
18
18
|
const FN_START = exports.FN_START = 'fn' + START;
|
|
19
19
|
const FN_END = exports.FN_END = 'fn' + END;
|
|
20
20
|
const PUSH_STATE = exports.PUSH_STATE = 'pushState';
|
|
21
|
-
const MAX_NODES_PER_HARVEST = exports.MAX_NODES_PER_HARVEST = 1000;
|
|
21
|
+
const MAX_NODES_PER_HARVEST = exports.MAX_NODES_PER_HARVEST = 1000;
|
|
22
|
+
const ERROR_MODE_SECONDS_WINDOW = exports.ERROR_MODE_SECONDS_WINDOW = 30 * 1000; // sliding window of nodes to track when simply monitoring (but not harvesting) in error mode
|
|
@@ -65,8 +65,7 @@ class AggregateBase extends _featureBase.FeatureBase {
|
|
|
65
65
|
#setupEventStore(entityGuid) {
|
|
66
66
|
if (this.events) return;
|
|
67
67
|
switch (this.featureName) {
|
|
68
|
-
//
|
|
69
|
-
case _features.FEATURE_NAMES.sessionTrace:
|
|
68
|
+
// SessionReplay has its own storage mechanisms.
|
|
70
69
|
case _features.FEATURE_NAMES.sessionReplay:
|
|
71
70
|
break;
|
|
72
71
|
// Jserror and Metric features uses a singleton EventAggregator instead of a regular EventBuffer.
|
|
@@ -26,6 +26,9 @@ class EventBuffer {
|
|
|
26
26
|
this.maxPayloadSize = maxPayloadSize;
|
|
27
27
|
this.featureAgg = featureAgg;
|
|
28
28
|
}
|
|
29
|
+
get length() {
|
|
30
|
+
return this.#buffer.length;
|
|
31
|
+
}
|
|
29
32
|
isEmpty() {
|
|
30
33
|
return this.#buffer.length === 0;
|
|
31
34
|
}
|
|
@@ -58,12 +61,40 @@ class EventBuffer {
|
|
|
58
61
|
return true;
|
|
59
62
|
}
|
|
60
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Merges events in the buffer that match the given criteria.
|
|
66
|
+
* @param {Function} matcher - A function that takes an event and returns true if it should be merged.
|
|
67
|
+
* @param {Object} data - The data to merge into the matching events.
|
|
68
|
+
* @returns {boolean} true if a match was found and merged; false otherwise.
|
|
69
|
+
*/
|
|
70
|
+
merge(matcher, data) {
|
|
71
|
+
if (this.isEmpty() || !matcher) return false;
|
|
72
|
+
const matchIdx = this.#buffer.findIndex(matcher);
|
|
73
|
+
if (matchIdx < 0) return false;
|
|
74
|
+
this.#buffer[matchIdx] = {
|
|
75
|
+
...this.#buffer[matchIdx],
|
|
76
|
+
...data
|
|
77
|
+
};
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
61
81
|
/**
|
|
62
82
|
* Wipes the main buffer
|
|
83
|
+
* @param {Object} [opts] - options for clearing the buffer
|
|
84
|
+
* @param {Number} [opts.clearBeforeTime] - timestamp before which all events should be cleared
|
|
85
|
+
* @param {String} [opts.timestampKey] - the key in the event object that contains the timestamp to compare against `clearBefore`
|
|
86
|
+
* @param {Number} [opts.clearBeforeIndex] - index before which all events should be cleared
|
|
87
|
+
* @returns {void}
|
|
63
88
|
*/
|
|
64
|
-
clear() {
|
|
65
|
-
|
|
66
|
-
|
|
89
|
+
clear(opts = {}) {
|
|
90
|
+
if (opts.clearBeforeTime !== undefined && opts.timestampKey) {
|
|
91
|
+
this.#buffer = this.#buffer.filter(event => event[opts.timestampKey] >= opts.clearBeforeTime);
|
|
92
|
+
} else if (opts.clearBeforeIndex !== undefined) {
|
|
93
|
+
this.#buffer = this.#buffer.slice(opts.clearBeforeIndex);
|
|
94
|
+
} else {
|
|
95
|
+
this.#buffer = [];
|
|
96
|
+
}
|
|
97
|
+
this.#rawBytes = this.#buffer.length ? (0, _stringify.stringify)(this.#buffer)?.length || 0 : 0; // recalculate raw bytes after clearing
|
|
67
98
|
}
|
|
68
99
|
|
|
69
100
|
/**
|
|
@@ -5,8 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.EventStoreManager = void 0;
|
|
7
7
|
var _agentConstants = require("../../common/constants/agent-constants");
|
|
8
|
-
var _globalEvent = require("../../common/dispatch/global-event");
|
|
9
|
-
var _featureFlags = require("../../common/util/feature-flags");
|
|
10
8
|
var _target = require("../../common/util/target");
|
|
11
9
|
/**
|
|
12
10
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
@@ -50,7 +48,24 @@ class EventStoreManager {
|
|
|
50
48
|
this.appStorageMap.set(targetEntityGuid, eventStorage);
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
|
|
51
|
+
/** IMPORTANT
|
|
52
|
+
* This class must contain an union of all methods from all supported storage classes and conceptualize away the target app argument.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
get length() {
|
|
56
|
+
return this.#getEventStore().length;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Calls the merge method on the underlying storage class.
|
|
61
|
+
* @param {*} matcher
|
|
62
|
+
* @param {*} data
|
|
63
|
+
* @param {*} targetEntityGuid
|
|
64
|
+
* @returns {boolean} True if the merge was successful
|
|
65
|
+
*/
|
|
66
|
+
merge(matcher, data, targetEntityGuid) {
|
|
67
|
+
return this.#getEventStore(targetEntityGuid).merge(matcher, data);
|
|
68
|
+
}
|
|
54
69
|
|
|
55
70
|
/**
|
|
56
71
|
* Calls the isEmpty method on the underlying storage class. If target is provided, runs just for the target, otherwise runs for all apps.
|
|
@@ -73,14 +88,6 @@ class EventStoreManager {
|
|
|
73
88
|
* @returns {boolean} True if the event was successfully added
|
|
74
89
|
*/
|
|
75
90
|
add(event, targetEntityGuid) {
|
|
76
|
-
(0, _globalEvent.dispatchGlobalEvent)({
|
|
77
|
-
agentIdentifier: this.agentRef.agentIdentifier,
|
|
78
|
-
drained: !!_featureFlags.activatedFeatures?.[this.agentRef.agentIdentifier],
|
|
79
|
-
type: 'data',
|
|
80
|
-
name: 'buffer',
|
|
81
|
-
feature: this.featureAgg.featureName,
|
|
82
|
-
data: event
|
|
83
|
-
});
|
|
84
91
|
return this.#getEventStore(targetEntityGuid).add(event);
|
|
85
92
|
}
|
|
86
93
|
|
|
@@ -42,7 +42,8 @@ export function wrapEvents(sharedEE) {
|
|
|
42
42
|
}
|
|
43
43
|
ee.on(ADD_EVENT_LISTENER + '-start', function (args, target) {
|
|
44
44
|
var originalListener = args[1];
|
|
45
|
-
if (originalListener === null || typeof originalListener !== 'function' && typeof originalListener !== 'object'
|
|
45
|
+
if (originalListener === null || typeof originalListener !== 'function' && typeof originalListener !== 'object' || args[0] === 'newrelic' // ignore our own window events
|
|
46
|
+
) {
|
|
46
47
|
return;
|
|
47
48
|
}
|
|
48
49
|
var wrapped = getOrSet(originalListener, flag, function () {
|
|
@@ -12,7 +12,7 @@ import { MODE, SESSION_EVENTS } from '../../../common/session/constants';
|
|
|
12
12
|
import { applyFnToProps } from '../../../common/util/traverse';
|
|
13
13
|
import { cleanURL } from '../../../common/url/clean-url';
|
|
14
14
|
import { warn } from '../../../common/util/console';
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
/** Reserved room for query param attrs */
|
|
17
17
|
const QUERY_PARAM_PADDING = 5000;
|
|
18
18
|
export class Aggregate extends AggregateBase {
|
|
@@ -27,8 +27,8 @@ export class Aggregate extends AggregateBase {
|
|
|
27
27
|
this.everHarvested = false;
|
|
28
28
|
/** If the harvest module is harvesting */
|
|
29
29
|
this.harvesting = false;
|
|
30
|
-
/** TraceStorage is
|
|
31
|
-
this.
|
|
30
|
+
/** TraceStorage is a middleware that decides how to format data before passing events to `this.events` */
|
|
31
|
+
this.traceStorage = new TraceStorage(this);
|
|
32
32
|
|
|
33
33
|
/* This agg needs information about sampling (sts) and entitlements (st) to make the appropriate decisions on running */
|
|
34
34
|
this.waitForFlags(['sts', 'st']).then(([stMode, stEntitled]) => this.initialize(stMode, stEntitled));
|
|
@@ -59,9 +59,9 @@ export class Aggregate extends AggregateBase {
|
|
|
59
59
|
if (this.sessionId !== sessionState.value || eventType === 'cross-tab' && sessionState.sessionTraceMode === MODE.OFF) this.abort(2);
|
|
60
60
|
});
|
|
61
61
|
if (typeof PerformanceNavigationTiming !== 'undefined') {
|
|
62
|
-
this.
|
|
62
|
+
this.traceStorage.storeTiming(globalScope.performance?.getEntriesByType?.('navigation')[0]);
|
|
63
63
|
} else {
|
|
64
|
-
this.
|
|
64
|
+
this.traceStorage.storeTiming(globalScope.performance?.timing, true);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -75,13 +75,13 @@ export class Aggregate extends AggregateBase {
|
|
|
75
75
|
this.timeKeeper ??= this.agentRef.runtime.timeKeeper;
|
|
76
76
|
|
|
77
77
|
/** The handlers set up by the Inst file */
|
|
78
|
-
registerHandler('bst', (...args) => this.
|
|
79
|
-
registerHandler('bstResource', (...args) => this.
|
|
80
|
-
registerHandler('bstHist', (...args) => this.
|
|
81
|
-
registerHandler('bstXhrAgg', (...args) => this.
|
|
82
|
-
registerHandler('bstApi', (...args) => this.
|
|
83
|
-
registerHandler('trace-jserror', (...args) => this.
|
|
84
|
-
registerHandler('pvtAdded', (...args) => this.
|
|
78
|
+
registerHandler('bst', (...args) => this.traceStorage.storeEvent(...args), this.featureName, this.ee);
|
|
79
|
+
registerHandler('bstResource', (...args) => this.traceStorage.storeResources(...args), this.featureName, this.ee);
|
|
80
|
+
registerHandler('bstHist', (...args) => this.traceStorage.storeHist(...args), this.featureName, this.ee);
|
|
81
|
+
registerHandler('bstXhrAgg', (...args) => this.traceStorage.storeXhrAgg(...args), this.featureName, this.ee);
|
|
82
|
+
registerHandler('bstApi', (...args) => this.traceStorage.storeNode(...args), this.featureName, this.ee);
|
|
83
|
+
registerHandler('trace-jserror', (...args) => this.traceStorage.storeErrorAgg(...args), this.featureName, this.ee);
|
|
84
|
+
registerHandler('pvtAdded', (...args) => this.traceStorage.processPVT(...args), this.featureName, this.ee);
|
|
85
85
|
if (this.mode !== MODE.FULL) {
|
|
86
86
|
/** A separate handler for noticing errors, and switching to "full" mode if running in "error" mode */
|
|
87
87
|
registerHandler('trace-jserror', () => {
|
|
@@ -106,18 +106,12 @@ export class Aggregate extends AggregateBase {
|
|
|
106
106
|
}
|
|
107
107
|
return true;
|
|
108
108
|
}
|
|
109
|
-
serializer({
|
|
110
|
-
stns
|
|
111
|
-
}) {
|
|
109
|
+
serializer(stns) {
|
|
112
110
|
if (!stns.length) return; // there are no processed nodes
|
|
113
111
|
this.everHarvested = true;
|
|
114
112
|
return applyFnToProps(stns, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string');
|
|
115
113
|
}
|
|
116
|
-
queryStringsBuilder({
|
|
117
|
-
stns,
|
|
118
|
-
earliestTimeStamp,
|
|
119
|
-
latestTimeStamp
|
|
120
|
-
}) {
|
|
114
|
+
queryStringsBuilder(stns) {
|
|
121
115
|
const firstSessionHarvest = !this.agentRef.runtime.session.state.traceHarvestStarted;
|
|
122
116
|
if (firstSessionHarvest) this.agentRef.runtime.session.write({
|
|
123
117
|
traceHarvestStarted: true
|
|
@@ -125,6 +119,8 @@ export class Aggregate extends AggregateBase {
|
|
|
125
119
|
const hasReplay = this.agentRef.runtime.session.state.sessionReplayMode === 1;
|
|
126
120
|
const endUserId = this.agentRef.info.jsAttributes['enduser.id'];
|
|
127
121
|
const entityGuid = this.agentRef.runtime.appMetadata.agents?.[0]?.entityGuid;
|
|
122
|
+
const earliestTimeStamp = stns.reduce((earliest, stn) => Math.min(earliest, stn.s), Infinity);
|
|
123
|
+
const latestTimeStamp = stns.reduce((latest, stn) => Math.max(latest, stn.s), -Infinity);
|
|
128
124
|
|
|
129
125
|
/* The blob consumer expects the following and will reject if not supplied:
|
|
130
126
|
* browser_monitoring_key
|
|
@@ -184,7 +180,7 @@ export class Aggregate extends AggregateBase {
|
|
|
184
180
|
});
|
|
185
181
|
if (prevMode === MODE.OFF || !this.initialized) return this.initialize(this.mode, this.entitled);
|
|
186
182
|
if (this.initialized) {
|
|
187
|
-
this.
|
|
183
|
+
this.traceStorage.trimSTNsByTime(); // up until now, Trace would've been just buffering nodes up to max, which needs to be trimmed to last X seconds
|
|
188
184
|
this.agentRef.runtime.harvester.triggerHarvestFor(this);
|
|
189
185
|
}
|
|
190
186
|
}
|
|
@@ -199,4 +195,8 @@ export class Aggregate extends AggregateBase {
|
|
|
199
195
|
});
|
|
200
196
|
this.events.clear();
|
|
201
197
|
}
|
|
198
|
+
postHarvestCleanup(result) {
|
|
199
|
+
this.traceStorage.clear(); // clear the trace storage state
|
|
200
|
+
super.postHarvestCleanup(result);
|
|
201
|
+
}
|
|
202
202
|
}
|