@newrelic/browser-agent 1.291.0 → 1.291.1
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 +9 -0
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/features/generic_events/aggregate/index.js +2 -2
- package/dist/cjs/features/session_trace/aggregate/index.js +1 -1
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +36 -16
- package/dist/cjs/loaders/api/addToTrace.js +8 -0
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/features/generic_events/aggregate/index.js +2 -2
- package/dist/esm/features/session_trace/aggregate/index.js +1 -1
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +36 -16
- package/dist/esm/loaders/api/addToTrace.js +8 -0
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +1 -2
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -1
- package/dist/types/loaders/api/addToTrace.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/features/generic_events/aggregate/index.js +2 -2
- package/src/features/session_trace/aggregate/index.js +1 -1
- package/src/features/session_trace/aggregate/trace/storage.js +37 -15
- package/src/loaders/api/addToTrace.js +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
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.291.1](https://github.com/newrelic/newrelic-browser-agent/compare/v1.291.0...v1.291.1) (2025-06-06)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Add safeguards for addToTrace ([#1490](https://github.com/newrelic/newrelic-browser-agent/issues/1490)) ([e94a36e](https://github.com/newrelic/newrelic-browser-agent/commit/e94a36efaf37f69dfdb8134bc27ee0df0a734e83))
|
|
12
|
+
* Clean BrowserPerformance entryName for resources ([#1493](https://github.com/newrelic/newrelic-browser-agent/issues/1493)) ([09ff0ad](https://github.com/newrelic/newrelic-browser-agent/commit/09ff0adb27c12e99c02c81462aeb921af8686ce8))
|
|
13
|
+
* Prevent ST from holding onto Event refs in memory when aborted ([#1491](https://github.com/newrelic/newrelic-browser-agent/issues/1491)) ([a1d15cb](https://github.com/newrelic/newrelic-browser-agent/commit/a1d15cb9d972a2fa421a648b83e150489799d437))
|
|
14
|
+
|
|
6
15
|
## [1.291.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.290.1...v1.291.0) (2025-05-30)
|
|
7
16
|
|
|
8
17
|
|
|
@@ -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.291.
|
|
20
|
+
const VERSION = exports.VERSION = "1.291.1";
|
|
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.291.
|
|
20
|
+
const VERSION = exports.VERSION = "1.291.1";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -148,7 +148,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
148
148
|
...detailObj,
|
|
149
149
|
eventType: 'BrowserPerformance',
|
|
150
150
|
timestamp: this.toEpoch(entry.startTime),
|
|
151
|
-
entryName:
|
|
151
|
+
entryName: entry.name,
|
|
152
152
|
entryDuration: entry.duration,
|
|
153
153
|
entryType: type
|
|
154
154
|
});
|
|
@@ -214,7 +214,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
214
214
|
...entryObject,
|
|
215
215
|
eventType: 'BrowserPerformance',
|
|
216
216
|
timestamp: Math.floor(agentRef.runtime.timeKeeper.correctRelativeTimestamp(entryObject.startTime)),
|
|
217
|
-
entryName: name,
|
|
217
|
+
entryName: (0, _cleanUrl.cleanURL)(name),
|
|
218
218
|
entryDuration: duration,
|
|
219
219
|
firstParty
|
|
220
220
|
};
|
|
@@ -86,7 +86,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
86
86
|
(0, _registerHandler.registerHandler)('bstResource', (...args) => this.events.storeResources(...args), this.featureName, this.ee);
|
|
87
87
|
(0, _registerHandler.registerHandler)('bstHist', (...args) => this.events.storeHist(...args), this.featureName, this.ee);
|
|
88
88
|
(0, _registerHandler.registerHandler)('bstXhrAgg', (...args) => this.events.storeXhrAgg(...args), this.featureName, this.ee);
|
|
89
|
-
(0, _registerHandler.registerHandler)('bstApi', (...args) => this.events.
|
|
89
|
+
(0, _registerHandler.registerHandler)('bstApi', (...args) => this.events.storeNode(...args), this.featureName, this.ee);
|
|
90
90
|
(0, _registerHandler.registerHandler)('trace-jserror', (...args) => this.events.storeErrorAgg(...args), this.featureName, this.ee);
|
|
91
91
|
(0, _registerHandler.registerHandler)('pvtAdded', (...args) => this.events.processPVT(...args), this.featureName, this.ee);
|
|
92
92
|
if (this.mode !== _constants2.MODE.FULL) {
|
|
@@ -53,16 +53,19 @@ class TraceStorage {
|
|
|
53
53
|
constructor(parent) {
|
|
54
54
|
this.parent = parent;
|
|
55
55
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
storeSTN(stn) {
|
|
59
|
-
if (this.parent.blocked) return;
|
|
56
|
+
#canStoreNewNode() {
|
|
57
|
+
if (this.parent.blocked) return false;
|
|
60
58
|
if (this.nodeCount >= _constants2.MAX_NODES_PER_HARVEST) {
|
|
61
59
|
// limit the amount of pending data awaiting next harvest
|
|
62
|
-
if (this.parent.mode !== _constants.MODE.ERROR) return;
|
|
60
|
+
if (this.parent.mode !== _constants.MODE.ERROR) return false;
|
|
63
61
|
const openedSpace = this.trimSTNs(ERROR_MODE_SECONDS_WINDOW); // but maybe we could make some space by discarding irrelevant nodes if we're in sessioned Error mode
|
|
64
|
-
if (openedSpace === 0) return;
|
|
62
|
+
if (openedSpace === 0) return false;
|
|
65
63
|
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Central internal function called by all the other store__ & addToTrace API to append a trace node. They MUST all have checked #canStoreNewNode before calling this func!! */
|
|
68
|
+
#storeSTN(stn) {
|
|
66
69
|
if (this.trace[stn.n]) this.trace[stn.n].push(stn);else this.trace[stn.n] = [stn];
|
|
67
70
|
if (stn.s < this.earliestTimeStamp) this.earliestTimeStamp = stn.s;
|
|
68
71
|
if (stn.s > this.latestTimeStamp) this.latestTimeStamp = stn.s;
|
|
@@ -142,6 +145,10 @@ class TraceStorage {
|
|
|
142
145
|
return !!(node && typeof node.e === 'number' && typeof node.s === 'number' && node.e - node.s < limit);
|
|
143
146
|
}
|
|
144
147
|
}
|
|
148
|
+
storeNode(node) {
|
|
149
|
+
if (!this.#canStoreNewNode()) return;
|
|
150
|
+
this.#storeSTN(node);
|
|
151
|
+
}
|
|
145
152
|
processPVT(name, value, attrs) {
|
|
146
153
|
this.storeTiming({
|
|
147
154
|
[name]: value
|
|
@@ -165,13 +172,16 @@ class TraceStorage {
|
|
|
165
172
|
if (this.parent.timeKeeper && this.parent.timeKeeper.ready && isAbsoluteTimestamp) {
|
|
166
173
|
val = this.parent.timeKeeper.convertAbsoluteTimestamp(Math.floor(this.parent.timeKeeper.correctAbsoluteTimestamp(val)));
|
|
167
174
|
}
|
|
168
|
-
this
|
|
175
|
+
if (!this.#canStoreNewNode()) return; // at any point when no new nodes can be stored, there's no point in processing the rest of the timing entries
|
|
176
|
+
this.#storeSTN(new _node.TraceNode(key, val, val, 'document', 'timing'));
|
|
169
177
|
}
|
|
170
178
|
}
|
|
171
179
|
|
|
172
180
|
// Tracks the events and their listener's duration on objects wrapped by wrap-events.
|
|
173
181
|
storeEvent(currentEvent, target, start, end) {
|
|
174
182
|
if (this.shouldIgnoreEvent(currentEvent, target)) return;
|
|
183
|
+
if (!this.#canStoreNewNode()) return; // need to check if adding node will succeed BEFORE storing event ref below (*cli Jun'25 - addressing memory leak in aborted ST issue #NR-420780)
|
|
184
|
+
|
|
175
185
|
if (this.prevStoredEvents.has(currentEvent)) return; // prevent multiple listeners of an event from creating duplicate trace nodes per occurrence. Cleared every harvest. near-zero chance for re-duplication after clearing per harvest since the timestamps of the event are considered for uniqueness.
|
|
176
186
|
this.prevStoredEvents.add(currentEvent);
|
|
177
187
|
const evt = new _node.TraceNode(this.evtName(currentEvent.type), start, end, undefined, 'event');
|
|
@@ -182,7 +192,7 @@ class TraceStorage {
|
|
|
182
192
|
} catch (e) {
|
|
183
193
|
evt.o = (0, _eventOrigin.eventOrigin)(null, target, this.parent.ee);
|
|
184
194
|
}
|
|
185
|
-
this
|
|
195
|
+
this.#storeSTN(evt);
|
|
186
196
|
}
|
|
187
197
|
shouldIgnoreEvent(event, target) {
|
|
188
198
|
if (event.type in ignoredEvents.global) return true;
|
|
@@ -218,14 +228,17 @@ class TraceStorage {
|
|
|
218
228
|
|
|
219
229
|
// Tracks when the window history API specified by wrap-history is used.
|
|
220
230
|
storeHist(path, old, time) {
|
|
221
|
-
this
|
|
231
|
+
if (!this.#canStoreNewNode()) return;
|
|
232
|
+
this.#storeSTN(new _node.TraceNode('history.pushState', time, time, path, old));
|
|
222
233
|
}
|
|
223
234
|
#laststart = 0;
|
|
224
235
|
// Processes all the PerformanceResourceTiming entries captured (by observer).
|
|
225
236
|
storeResources(resources) {
|
|
226
237
|
if (!resources || resources.length === 0) return;
|
|
227
|
-
resources.
|
|
228
|
-
|
|
238
|
+
for (let i = 0; i < resources.length; i++) {
|
|
239
|
+
const currentResource = resources[i];
|
|
240
|
+
if ((currentResource.fetchStart | 0) <= this.#laststart) continue; // don't recollect already-seen resources
|
|
241
|
+
if (!this.#canStoreNewNode()) break; // stop processing if we can't store any more resource nodes anyways
|
|
229
242
|
|
|
230
243
|
const {
|
|
231
244
|
initiatorType,
|
|
@@ -240,21 +253,23 @@ class TraceStorage {
|
|
|
240
253
|
pathname
|
|
241
254
|
} = (0, _parseUrl.parseUrl)(currentResource.name);
|
|
242
255
|
const res = new _node.TraceNode(initiatorType, fetchStart | 0, responseEnd | 0, "".concat(protocol, "://").concat(hostname, ":").concat(port).concat(pathname), entryType);
|
|
243
|
-
this
|
|
244
|
-
}
|
|
256
|
+
this.#storeSTN(res);
|
|
257
|
+
}
|
|
245
258
|
this.#laststart = resources[resources.length - 1].fetchStart | 0;
|
|
246
259
|
}
|
|
247
260
|
|
|
248
261
|
// JavascriptError (FEATURE) events pipes into ST here.
|
|
249
262
|
storeErrorAgg(type, name, params, metrics) {
|
|
250
263
|
if (type !== 'err') return; // internal errors are purposefully ignored
|
|
251
|
-
this
|
|
264
|
+
if (!this.#canStoreNewNode()) return;
|
|
265
|
+
this.#storeSTN(new _node.TraceNode('error', metrics.time, metrics.time, params.message, params.stackHash));
|
|
252
266
|
}
|
|
253
267
|
|
|
254
268
|
// Ajax (FEATURE) events--XML & fetches--pipes into ST here.
|
|
255
269
|
storeXhrAgg(type, name, params, metrics) {
|
|
256
270
|
if (type !== 'xhr') return;
|
|
257
|
-
|
|
271
|
+
if (!this.#canStoreNewNode()) return;
|
|
272
|
+
this.#storeSTN(new _node.TraceNode('Ajax', metrics.time, metrics.time + metrics.duration, "".concat(params.status, " ").concat(params.method, ": ").concat(params.host).concat(params.pathname), 'ajax'));
|
|
258
273
|
}
|
|
259
274
|
|
|
260
275
|
/* Below are the interface expected & required of whatever storage is used across all features on an individual basis. This allows a common `.events` property on Trace shared with AggregateBase.
|
|
@@ -279,7 +294,12 @@ class TraceStorage {
|
|
|
279
294
|
this.latestTimeStamp = 0;
|
|
280
295
|
}
|
|
281
296
|
reloadSave() {
|
|
282
|
-
Object.values(this.#backupTrace)
|
|
297
|
+
for (const stnsArray of Object.values(this.#backupTrace)) {
|
|
298
|
+
for (const stn of stnsArray) {
|
|
299
|
+
if (!this.#canStoreNewNode()) return; // stop attempting to re-store nodes
|
|
300
|
+
this.#storeSTN(stn);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
283
303
|
}
|
|
284
304
|
clearSave() {
|
|
285
305
|
this.#backupTrace = undefined;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.setupAddToTraceAPI = setupAddToTraceAPI;
|
|
7
7
|
var _runtime = require("../../common/constants/runtime");
|
|
8
8
|
var _handle = require("../../common/event-emitter/handle");
|
|
9
|
+
var _console = require("../../common/util/console");
|
|
9
10
|
var _features = require("../features/features");
|
|
10
11
|
var _constants = require("./constants");
|
|
11
12
|
var _sharedHandlers = require("./sharedHandlers");
|
|
@@ -24,6 +25,13 @@ function setupAddToTraceAPI(agent) {
|
|
|
24
25
|
o: evt.origin || '',
|
|
25
26
|
t: 'api'
|
|
26
27
|
};
|
|
28
|
+
if (report.s < 0 || report.e < 0 || report.e < report.s) {
|
|
29
|
+
(0, _console.warn)(61, {
|
|
30
|
+
start: report.s,
|
|
31
|
+
end: report.e
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
27
35
|
(0, _handle.handle)('bstApi', [report], undefined, _features.FEATURE_NAMES.sessionTrace, agent.ee);
|
|
28
36
|
}, agent);
|
|
29
37
|
}
|
|
@@ -141,7 +141,7 @@ export class Aggregate extends AggregateBase {
|
|
|
141
141
|
...detailObj,
|
|
142
142
|
eventType: 'BrowserPerformance',
|
|
143
143
|
timestamp: this.toEpoch(entry.startTime),
|
|
144
|
-
entryName:
|
|
144
|
+
entryName: entry.name,
|
|
145
145
|
entryDuration: entry.duration,
|
|
146
146
|
entryType: type
|
|
147
147
|
});
|
|
@@ -207,7 +207,7 @@ export class Aggregate extends AggregateBase {
|
|
|
207
207
|
...entryObject,
|
|
208
208
|
eventType: 'BrowserPerformance',
|
|
209
209
|
timestamp: Math.floor(agentRef.runtime.timeKeeper.correctRelativeTimestamp(entryObject.startTime)),
|
|
210
|
-
entryName: name,
|
|
210
|
+
entryName: cleanURL(name),
|
|
211
211
|
entryDuration: duration,
|
|
212
212
|
firstParty
|
|
213
213
|
};
|
|
@@ -79,7 +79,7 @@ export class Aggregate extends AggregateBase {
|
|
|
79
79
|
registerHandler('bstResource', (...args) => this.events.storeResources(...args), this.featureName, this.ee);
|
|
80
80
|
registerHandler('bstHist', (...args) => this.events.storeHist(...args), this.featureName, this.ee);
|
|
81
81
|
registerHandler('bstXhrAgg', (...args) => this.events.storeXhrAgg(...args), this.featureName, this.ee);
|
|
82
|
-
registerHandler('bstApi', (...args) => this.events.
|
|
82
|
+
registerHandler('bstApi', (...args) => this.events.storeNode(...args), this.featureName, this.ee);
|
|
83
83
|
registerHandler('trace-jserror', (...args) => this.events.storeErrorAgg(...args), this.featureName, this.ee);
|
|
84
84
|
registerHandler('pvtAdded', (...args) => this.events.processPVT(...args), this.featureName, this.ee);
|
|
85
85
|
if (this.mode !== MODE.FULL) {
|
|
@@ -46,16 +46,19 @@ export class TraceStorage {
|
|
|
46
46
|
constructor(parent) {
|
|
47
47
|
this.parent = parent;
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
storeSTN(stn) {
|
|
52
|
-
if (this.parent.blocked) return;
|
|
49
|
+
#canStoreNewNode() {
|
|
50
|
+
if (this.parent.blocked) return false;
|
|
53
51
|
if (this.nodeCount >= MAX_NODES_PER_HARVEST) {
|
|
54
52
|
// limit the amount of pending data awaiting next harvest
|
|
55
|
-
if (this.parent.mode !== MODE.ERROR) return;
|
|
53
|
+
if (this.parent.mode !== MODE.ERROR) return false;
|
|
56
54
|
const openedSpace = this.trimSTNs(ERROR_MODE_SECONDS_WINDOW); // but maybe we could make some space by discarding irrelevant nodes if we're in sessioned Error mode
|
|
57
|
-
if (openedSpace === 0) return;
|
|
55
|
+
if (openedSpace === 0) return false;
|
|
58
56
|
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Central internal function called by all the other store__ & addToTrace API to append a trace node. They MUST all have checked #canStoreNewNode before calling this func!! */
|
|
61
|
+
#storeSTN(stn) {
|
|
59
62
|
if (this.trace[stn.n]) this.trace[stn.n].push(stn);else this.trace[stn.n] = [stn];
|
|
60
63
|
if (stn.s < this.earliestTimeStamp) this.earliestTimeStamp = stn.s;
|
|
61
64
|
if (stn.s > this.latestTimeStamp) this.latestTimeStamp = stn.s;
|
|
@@ -135,6 +138,10 @@ export class TraceStorage {
|
|
|
135
138
|
return !!(node && typeof node.e === 'number' && typeof node.s === 'number' && node.e - node.s < limit);
|
|
136
139
|
}
|
|
137
140
|
}
|
|
141
|
+
storeNode(node) {
|
|
142
|
+
if (!this.#canStoreNewNode()) return;
|
|
143
|
+
this.#storeSTN(node);
|
|
144
|
+
}
|
|
138
145
|
processPVT(name, value, attrs) {
|
|
139
146
|
this.storeTiming({
|
|
140
147
|
[name]: value
|
|
@@ -158,13 +165,16 @@ export class TraceStorage {
|
|
|
158
165
|
if (this.parent.timeKeeper && this.parent.timeKeeper.ready && isAbsoluteTimestamp) {
|
|
159
166
|
val = this.parent.timeKeeper.convertAbsoluteTimestamp(Math.floor(this.parent.timeKeeper.correctAbsoluteTimestamp(val)));
|
|
160
167
|
}
|
|
161
|
-
this
|
|
168
|
+
if (!this.#canStoreNewNode()) return; // at any point when no new nodes can be stored, there's no point in processing the rest of the timing entries
|
|
169
|
+
this.#storeSTN(new TraceNode(key, val, val, 'document', 'timing'));
|
|
162
170
|
}
|
|
163
171
|
}
|
|
164
172
|
|
|
165
173
|
// Tracks the events and their listener's duration on objects wrapped by wrap-events.
|
|
166
174
|
storeEvent(currentEvent, target, start, end) {
|
|
167
175
|
if (this.shouldIgnoreEvent(currentEvent, target)) return;
|
|
176
|
+
if (!this.#canStoreNewNode()) return; // need to check if adding node will succeed BEFORE storing event ref below (*cli Jun'25 - addressing memory leak in aborted ST issue #NR-420780)
|
|
177
|
+
|
|
168
178
|
if (this.prevStoredEvents.has(currentEvent)) return; // prevent multiple listeners of an event from creating duplicate trace nodes per occurrence. Cleared every harvest. near-zero chance for re-duplication after clearing per harvest since the timestamps of the event are considered for uniqueness.
|
|
169
179
|
this.prevStoredEvents.add(currentEvent);
|
|
170
180
|
const evt = new TraceNode(this.evtName(currentEvent.type), start, end, undefined, 'event');
|
|
@@ -175,7 +185,7 @@ export class TraceStorage {
|
|
|
175
185
|
} catch (e) {
|
|
176
186
|
evt.o = eventOrigin(null, target, this.parent.ee);
|
|
177
187
|
}
|
|
178
|
-
this
|
|
188
|
+
this.#storeSTN(evt);
|
|
179
189
|
}
|
|
180
190
|
shouldIgnoreEvent(event, target) {
|
|
181
191
|
if (event.type in ignoredEvents.global) return true;
|
|
@@ -211,14 +221,17 @@ export class TraceStorage {
|
|
|
211
221
|
|
|
212
222
|
// Tracks when the window history API specified by wrap-history is used.
|
|
213
223
|
storeHist(path, old, time) {
|
|
214
|
-
this
|
|
224
|
+
if (!this.#canStoreNewNode()) return;
|
|
225
|
+
this.#storeSTN(new TraceNode('history.pushState', time, time, path, old));
|
|
215
226
|
}
|
|
216
227
|
#laststart = 0;
|
|
217
228
|
// Processes all the PerformanceResourceTiming entries captured (by observer).
|
|
218
229
|
storeResources(resources) {
|
|
219
230
|
if (!resources || resources.length === 0) return;
|
|
220
|
-
resources.
|
|
221
|
-
|
|
231
|
+
for (let i = 0; i < resources.length; i++) {
|
|
232
|
+
const currentResource = resources[i];
|
|
233
|
+
if ((currentResource.fetchStart | 0) <= this.#laststart) continue; // don't recollect already-seen resources
|
|
234
|
+
if (!this.#canStoreNewNode()) break; // stop processing if we can't store any more resource nodes anyways
|
|
222
235
|
|
|
223
236
|
const {
|
|
224
237
|
initiatorType,
|
|
@@ -233,21 +246,23 @@ export class TraceStorage {
|
|
|
233
246
|
pathname
|
|
234
247
|
} = parseUrl(currentResource.name);
|
|
235
248
|
const res = new TraceNode(initiatorType, fetchStart | 0, responseEnd | 0, "".concat(protocol, "://").concat(hostname, ":").concat(port).concat(pathname), entryType);
|
|
236
|
-
this
|
|
237
|
-
}
|
|
249
|
+
this.#storeSTN(res);
|
|
250
|
+
}
|
|
238
251
|
this.#laststart = resources[resources.length - 1].fetchStart | 0;
|
|
239
252
|
}
|
|
240
253
|
|
|
241
254
|
// JavascriptError (FEATURE) events pipes into ST here.
|
|
242
255
|
storeErrorAgg(type, name, params, metrics) {
|
|
243
256
|
if (type !== 'err') return; // internal errors are purposefully ignored
|
|
244
|
-
this
|
|
257
|
+
if (!this.#canStoreNewNode()) return;
|
|
258
|
+
this.#storeSTN(new TraceNode('error', metrics.time, metrics.time, params.message, params.stackHash));
|
|
245
259
|
}
|
|
246
260
|
|
|
247
261
|
// Ajax (FEATURE) events--XML & fetches--pipes into ST here.
|
|
248
262
|
storeXhrAgg(type, name, params, metrics) {
|
|
249
263
|
if (type !== 'xhr') return;
|
|
250
|
-
|
|
264
|
+
if (!this.#canStoreNewNode()) return;
|
|
265
|
+
this.#storeSTN(new TraceNode('Ajax', metrics.time, metrics.time + metrics.duration, "".concat(params.status, " ").concat(params.method, ": ").concat(params.host).concat(params.pathname), 'ajax'));
|
|
251
266
|
}
|
|
252
267
|
|
|
253
268
|
/* Below are the interface expected & required of whatever storage is used across all features on an individual basis. This allows a common `.events` property on Trace shared with AggregateBase.
|
|
@@ -272,7 +287,12 @@ export class TraceStorage {
|
|
|
272
287
|
this.latestTimeStamp = 0;
|
|
273
288
|
}
|
|
274
289
|
reloadSave() {
|
|
275
|
-
Object.values(this.#backupTrace)
|
|
290
|
+
for (const stnsArray of Object.values(this.#backupTrace)) {
|
|
291
|
+
for (const stn of stnsArray) {
|
|
292
|
+
if (!this.#canStoreNewNode()) return; // stop attempting to re-store nodes
|
|
293
|
+
this.#storeSTN(stn);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
276
296
|
}
|
|
277
297
|
clearSave() {
|
|
278
298
|
this.#backupTrace = undefined;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { originTime } from '../../common/constants/runtime';
|
|
6
6
|
import { handle } from '../../common/event-emitter/handle';
|
|
7
|
+
import { warn } from '../../common/util/console';
|
|
7
8
|
import { FEATURE_NAMES } from '../features/features';
|
|
8
9
|
import { ADD_TO_TRACE } from './constants';
|
|
9
10
|
import { setupAPI } from './sharedHandlers';
|
|
@@ -17,6 +18,13 @@ export function setupAddToTraceAPI(agent) {
|
|
|
17
18
|
o: evt.origin || '',
|
|
18
19
|
t: 'api'
|
|
19
20
|
};
|
|
21
|
+
if (report.s < 0 || report.e < 0 || report.e < report.s) {
|
|
22
|
+
warn(61, {
|
|
23
|
+
start: report.s,
|
|
24
|
+
end: report.e
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
20
28
|
handle('bstApi', [report], undefined, FEATURE_NAMES.sessionTrace, agent.ee);
|
|
21
29
|
}, agent);
|
|
22
30
|
}
|
|
@@ -7,8 +7,6 @@ export class TraceStorage {
|
|
|
7
7
|
latestTimeStamp: number;
|
|
8
8
|
prevStoredEvents: Set<any>;
|
|
9
9
|
parent: any;
|
|
10
|
-
/** Central function called by all the other store__ & addToTrace API to append a trace node. */
|
|
11
|
-
storeSTN(stn: any): void;
|
|
12
10
|
/**
|
|
13
11
|
* Trim the collection of nodes awaiting harvest such that those seen outside a certain span of time are discarded.
|
|
14
12
|
* @param {number} lookbackDuration Past length of time until now for which we care about nodes, in milliseconds
|
|
@@ -22,6 +20,7 @@ export class TraceStorage {
|
|
|
22
20
|
latestTimeStamp: number;
|
|
23
21
|
};
|
|
24
22
|
smearEvtsByOrigin(name: any): (byOrigin: any, evtNode: any) => any;
|
|
23
|
+
storeNode(node: any): void;
|
|
25
24
|
processPVT(name: any, value: any, attrs: any): void;
|
|
26
25
|
storeTiming(timingEntry: any, isAbsoluteTimestamp?: boolean): void;
|
|
27
26
|
storeEvent(currentEvent: any, target: any, start: any, end: any): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../../../src/features/session_trace/aggregate/trace/storage.js"],"names":[],"mappings":"AA8BA,+HAA+H;AAC/H;IAQE,yBAEC;IATD,kBAAa;IACb,UAAU;IACV,0BAA4B;IAC5B,wBAAmB;IACnB,2BAA4B;IAI1B,YAAoB;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../../../src/features/session_trace/aggregate/trace/storage.js"],"names":[],"mappings":"AA8BA,+HAA+H;AAC/H;IAQE,yBAEC;IATD,kBAAa;IACb,UAAU;IACV,0BAA4B;IAC5B,wBAAmB;IACnB,2BAA4B;IAI1B,YAAoB;IAuBtB;;;;OAIG;IACH,2BAHW,MAAM,GACJ,MAAM,CAsBlB;IAED,oEAAoE;IACpE;;;;MAgBC;IAED,mEA6BC;IAED,2BAGC;IAED,oDAEC;IAED,mEAwBC;IAGD,uEAgBC;IAED,oDAKC;IAED,wBAwBC;IAGD,gDAGC;IAID,qCAgBC;IAGD,qEAIC;IAGD,mEAIC;IAID,mBAEC;IAED,aAEC;IAED;;;;;;;QAEC;IAED,cAMC;IAED,mBAOC;IAED,kBAEC;;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"addToTrace.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/addToTrace.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"addToTrace.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/addToTrace.js"],"names":[],"mappings":"AAWA,qDAmBC"}
|
package/package.json
CHANGED
|
@@ -143,7 +143,7 @@ export class Aggregate extends AggregateBase {
|
|
|
143
143
|
...detailObj,
|
|
144
144
|
eventType: 'BrowserPerformance',
|
|
145
145
|
timestamp: this.toEpoch(entry.startTime),
|
|
146
|
-
entryName:
|
|
146
|
+
entryName: entry.name,
|
|
147
147
|
entryDuration: entry.duration,
|
|
148
148
|
entryType: type
|
|
149
149
|
})
|
|
@@ -208,7 +208,7 @@ export class Aggregate extends AggregateBase {
|
|
|
208
208
|
...entryObject,
|
|
209
209
|
eventType: 'BrowserPerformance',
|
|
210
210
|
timestamp: Math.floor(agentRef.runtime.timeKeeper.correctRelativeTimestamp(entryObject.startTime)),
|
|
211
|
-
entryName: name,
|
|
211
|
+
entryName: cleanURL(name),
|
|
212
212
|
entryDuration: duration,
|
|
213
213
|
firstParty
|
|
214
214
|
}
|
|
@@ -86,7 +86,7 @@ export class Aggregate extends AggregateBase {
|
|
|
86
86
|
registerHandler('bstResource', (...args) => this.events.storeResources(...args), this.featureName, this.ee)
|
|
87
87
|
registerHandler('bstHist', (...args) => this.events.storeHist(...args), this.featureName, this.ee)
|
|
88
88
|
registerHandler('bstXhrAgg', (...args) => this.events.storeXhrAgg(...args), this.featureName, this.ee)
|
|
89
|
-
registerHandler('bstApi', (...args) => this.events.
|
|
89
|
+
registerHandler('bstApi', (...args) => this.events.storeNode(...args), this.featureName, this.ee)
|
|
90
90
|
registerHandler('trace-jserror', (...args) => this.events.storeErrorAgg(...args), this.featureName, this.ee)
|
|
91
91
|
registerHandler('pvtAdded', (...args) => this.events.processPVT(...args), this.featureName, this.ee)
|
|
92
92
|
|
|
@@ -41,15 +41,18 @@ export class TraceStorage {
|
|
|
41
41
|
this.parent = parent
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (this.parent.blocked) return
|
|
44
|
+
#canStoreNewNode () {
|
|
45
|
+
if (this.parent.blocked) return false
|
|
47
46
|
if (this.nodeCount >= MAX_NODES_PER_HARVEST) { // limit the amount of pending data awaiting next harvest
|
|
48
|
-
if (this.parent.mode !== MODE.ERROR) return
|
|
47
|
+
if (this.parent.mode !== MODE.ERROR) return false
|
|
49
48
|
const openedSpace = this.trimSTNs(ERROR_MODE_SECONDS_WINDOW) // but maybe we could make some space by discarding irrelevant nodes if we're in sessioned Error mode
|
|
50
|
-
if (openedSpace === 0) return
|
|
49
|
+
if (openedSpace === 0) return false
|
|
51
50
|
}
|
|
51
|
+
return true
|
|
52
|
+
}
|
|
52
53
|
|
|
54
|
+
/** Central internal function called by all the other store__ & addToTrace API to append a trace node. They MUST all have checked #canStoreNewNode before calling this func!! */
|
|
55
|
+
#storeSTN (stn) {
|
|
53
56
|
if (this.trace[stn.n]) this.trace[stn.n].push(stn)
|
|
54
57
|
else this.trace[stn.n] = [stn]
|
|
55
58
|
|
|
@@ -135,6 +138,11 @@ export class TraceStorage {
|
|
|
135
138
|
}
|
|
136
139
|
}
|
|
137
140
|
|
|
141
|
+
storeNode (node) {
|
|
142
|
+
if (!this.#canStoreNewNode()) return
|
|
143
|
+
this.#storeSTN(node)
|
|
144
|
+
}
|
|
145
|
+
|
|
138
146
|
processPVT (name, value, attrs) {
|
|
139
147
|
this.storeTiming({ [name]: value })
|
|
140
148
|
}
|
|
@@ -160,13 +168,16 @@ export class TraceStorage {
|
|
|
160
168
|
Math.floor(this.parent.timeKeeper.correctAbsoluteTimestamp(val))
|
|
161
169
|
)
|
|
162
170
|
}
|
|
163
|
-
this
|
|
171
|
+
if (!this.#canStoreNewNode()) return // at any point when no new nodes can be stored, there's no point in processing the rest of the timing entries
|
|
172
|
+
this.#storeSTN(new TraceNode(key, val, val, 'document', 'timing'))
|
|
164
173
|
}
|
|
165
174
|
}
|
|
166
175
|
|
|
167
176
|
// Tracks the events and their listener's duration on objects wrapped by wrap-events.
|
|
168
177
|
storeEvent (currentEvent, target, start, end) {
|
|
169
178
|
if (this.shouldIgnoreEvent(currentEvent, target)) return
|
|
179
|
+
if (!this.#canStoreNewNode()) return // need to check if adding node will succeed BEFORE storing event ref below (*cli Jun'25 - addressing memory leak in aborted ST issue #NR-420780)
|
|
180
|
+
|
|
170
181
|
if (this.prevStoredEvents.has(currentEvent)) return // prevent multiple listeners of an event from creating duplicate trace nodes per occurrence. Cleared every harvest. near-zero chance for re-duplication after clearing per harvest since the timestamps of the event are considered for uniqueness.
|
|
171
182
|
this.prevStoredEvents.add(currentEvent)
|
|
172
183
|
|
|
@@ -178,7 +189,7 @@ export class TraceStorage {
|
|
|
178
189
|
} catch (e) {
|
|
179
190
|
evt.o = eventOrigin(null, target, this.parent.ee)
|
|
180
191
|
}
|
|
181
|
-
this
|
|
192
|
+
this.#storeSTN(evt)
|
|
182
193
|
}
|
|
183
194
|
|
|
184
195
|
shouldIgnoreEvent (event, target) {
|
|
@@ -216,7 +227,8 @@ export class TraceStorage {
|
|
|
216
227
|
|
|
217
228
|
// Tracks when the window history API specified by wrap-history is used.
|
|
218
229
|
storeHist (path, old, time) {
|
|
219
|
-
this
|
|
230
|
+
if (!this.#canStoreNewNode()) return
|
|
231
|
+
this.#storeSTN(new TraceNode('history.pushState', time, time, path, old))
|
|
220
232
|
}
|
|
221
233
|
|
|
222
234
|
#laststart = 0
|
|
@@ -224,14 +236,17 @@ export class TraceStorage {
|
|
|
224
236
|
storeResources (resources) {
|
|
225
237
|
if (!resources || resources.length === 0) return
|
|
226
238
|
|
|
227
|
-
resources.
|
|
228
|
-
|
|
239
|
+
for (let i = 0; i < resources.length; i++) {
|
|
240
|
+
const currentResource = resources[i]
|
|
241
|
+
if ((currentResource.fetchStart | 0) <= this.#laststart) continue // don't recollect already-seen resources
|
|
242
|
+
if (!this.#canStoreNewNode()) break // stop processing if we can't store any more resource nodes anyways
|
|
229
243
|
|
|
230
244
|
const { initiatorType, fetchStart, responseEnd, entryType } = currentResource
|
|
231
245
|
const { protocol, hostname, port, pathname } = parseUrl(currentResource.name)
|
|
232
246
|
const res = new TraceNode(initiatorType, fetchStart | 0, responseEnd | 0, `${protocol}://${hostname}:${port}${pathname}`, entryType)
|
|
233
|
-
|
|
234
|
-
|
|
247
|
+
|
|
248
|
+
this.#storeSTN(res)
|
|
249
|
+
}
|
|
235
250
|
|
|
236
251
|
this.#laststart = resources[resources.length - 1].fetchStart | 0
|
|
237
252
|
}
|
|
@@ -239,13 +254,15 @@ export class TraceStorage {
|
|
|
239
254
|
// JavascriptError (FEATURE) events pipes into ST here.
|
|
240
255
|
storeErrorAgg (type, name, params, metrics) {
|
|
241
256
|
if (type !== 'err') return // internal errors are purposefully ignored
|
|
242
|
-
this
|
|
257
|
+
if (!this.#canStoreNewNode()) return
|
|
258
|
+
this.#storeSTN(new TraceNode('error', metrics.time, metrics.time, params.message, params.stackHash))
|
|
243
259
|
}
|
|
244
260
|
|
|
245
261
|
// Ajax (FEATURE) events--XML & fetches--pipes into ST here.
|
|
246
262
|
storeXhrAgg (type, name, params, metrics) {
|
|
247
263
|
if (type !== 'xhr') return
|
|
248
|
-
this
|
|
264
|
+
if (!this.#canStoreNewNode()) return
|
|
265
|
+
this.#storeSTN(new TraceNode('Ajax', metrics.time, metrics.time + metrics.duration, `${params.status} ${params.method}: ${params.host}${params.pathname}`, 'ajax'))
|
|
249
266
|
}
|
|
250
267
|
|
|
251
268
|
/* Below are the interface expected & required of whatever storage is used across all features on an individual basis. This allows a common `.events` property on Trace shared with AggregateBase.
|
|
@@ -271,7 +288,12 @@ export class TraceStorage {
|
|
|
271
288
|
}
|
|
272
289
|
|
|
273
290
|
reloadSave () {
|
|
274
|
-
Object.values(this.#backupTrace)
|
|
291
|
+
for (const stnsArray of Object.values(this.#backupTrace)) {
|
|
292
|
+
for (const stn of stnsArray) {
|
|
293
|
+
if (!this.#canStoreNewNode()) return // stop attempting to re-store nodes
|
|
294
|
+
this.#storeSTN(stn)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
275
297
|
}
|
|
276
298
|
|
|
277
299
|
clearSave () {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { originTime } from '../../common/constants/runtime'
|
|
6
6
|
import { handle } from '../../common/event-emitter/handle'
|
|
7
|
+
import { warn } from '../../common/util/console'
|
|
7
8
|
import { FEATURE_NAMES } from '../features/features'
|
|
8
9
|
import { ADD_TO_TRACE } from './constants'
|
|
9
10
|
import { setupAPI } from './sharedHandlers'
|
|
@@ -20,6 +21,11 @@ export function setupAddToTraceAPI (agent) {
|
|
|
20
21
|
t: 'api'
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
if (report.s < 0 || report.e < 0 || report.e < report.s) {
|
|
25
|
+
warn(61, { start: report.s, end: report.e })
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
handle('bstApi', [report], undefined, FEATURE_NAMES.sessionTrace, agent.ee)
|
|
24
30
|
}, agent)
|
|
25
31
|
}
|