@newrelic/browser-agent 1.294.0 → 1.295.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 +13 -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/timing/time-keeper.js +2 -0
- package/dist/cjs/common/util/monkey-patched.js +30 -0
- package/dist/cjs/common/window/nreum.js +3 -1
- package/dist/cjs/features/jserrors/aggregate/cause-string.js +31 -0
- package/dist/cjs/features/jserrors/aggregate/index.js +6 -1
- package/dist/cjs/features/jserrors/shared/cast-error.js +2 -2
- package/dist/cjs/features/logging/instrument/index.js +8 -17
- package/dist/cjs/features/session_replay/aggregate/index.js +24 -4
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/timing/time-keeper.js +2 -0
- package/dist/esm/common/util/monkey-patched.js +23 -0
- package/dist/esm/common/window/nreum.js +3 -1
- package/dist/esm/features/jserrors/aggregate/cause-string.js +26 -0
- package/dist/esm/features/jserrors/aggregate/index.js +6 -1
- package/dist/esm/features/jserrors/shared/cast-error.js +2 -2
- package/dist/esm/features/logging/instrument/index.js +8 -17
- package/dist/esm/features/session_replay/aggregate/index.js +24 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
- package/dist/types/common/util/monkey-patched.d.ts +7 -0
- package/dist/types/common/util/monkey-patched.d.ts.map +1 -0
- package/dist/types/common/window/nreum.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/cause-string.d.ts +7 -0
- package/dist/types/features/jserrors/aggregate/cause-string.d.ts.map +1 -0
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/shared/cast-error.d.ts.map +1 -1
- package/dist/types/features/logging/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +9 -0
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/common/timing/time-keeper.js +2 -0
- package/src/common/util/monkey-patched.js +24 -0
- package/src/common/window/nreum.js +3 -1
- package/src/features/jserrors/aggregate/cause-string.js +26 -0
- package/src/features/jserrors/aggregate/index.js +5 -1
- package/src/features/jserrors/shared/cast-error.js +3 -2
- package/src/features/logging/instrument/index.js +8 -6
- package/src/features/session_replay/aggregate/index.js +18 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
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.295.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.294.0...v1.295.0) (2025-08-04)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add error cause detection ([#1531](https://github.com/newrelic/newrelic-browser-agent/issues/1531)) ([3e6bda7](https://github.com/newrelic/newrelic-browser-agent/commit/3e6bda74bfd19d4379a41d357c800eebc5d28ed5))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* Add monkey-patching warnings ([#1527](https://github.com/newrelic/newrelic-browser-agent/issues/1527)) ([412d469](https://github.com/newrelic/newrelic-browser-agent/commit/412d4690f4d8df59c3b6fb14ec8e6910e84db5b4))
|
|
17
|
+
* Calculate first and last timestamps from raw data ([#1535](https://github.com/newrelic/newrelic-browser-agent/issues/1535)) ([1ead794](https://github.com/newrelic/newrelic-browser-agent/commit/1ead794106af6160fd26c1c2036d59a3b2718bf0))
|
|
18
|
+
|
|
6
19
|
## [1.294.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.293.0...v1.294.0) (2025-07-23)
|
|
7
20
|
|
|
8
21
|
|
|
@@ -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.295.0-rc.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.295.0-rc.0";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.TimeKeeper = void 0;
|
|
7
7
|
var _runtime = require("../constants/runtime");
|
|
8
|
+
var _monkeyPatched = require("../util/monkey-patched");
|
|
8
9
|
/**
|
|
9
10
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
10
11
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -44,6 +45,7 @@ class TimeKeeper {
|
|
|
44
45
|
constructor(sessionObj) {
|
|
45
46
|
this.#session = sessionObj;
|
|
46
47
|
this.processStoredDiff();
|
|
48
|
+
(0, _monkeyPatched.isNative)(performance.now, Date.now); // will warn the user if these are not native functions. We need these to be native for time in the agent to be accurate in general.
|
|
47
49
|
}
|
|
48
50
|
get ready() {
|
|
49
51
|
return this.#ready;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isNative = isNative;
|
|
7
|
+
var _console = require("./console");
|
|
8
|
+
/**
|
|
9
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
10
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const checked = new Map();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks if the provided functions are native functions.
|
|
17
|
+
* @param {...Function} fns - An array of functions to check if they are native.
|
|
18
|
+
* @returns {boolean} true if all the expected globals are native, false otherwise
|
|
19
|
+
*/
|
|
20
|
+
function isNative(...fns) {
|
|
21
|
+
return fns.every(fn => {
|
|
22
|
+
if (checked.has(fn)) return checked.get(fn);
|
|
23
|
+
const isNative = typeof fn === 'function' && fn.toString().includes('[native code]');
|
|
24
|
+
if (!isNative) {
|
|
25
|
+
(0, _console.warn)(64, fn?.name || fn?.toString());
|
|
26
|
+
}
|
|
27
|
+
checked.set(fn, isNative);
|
|
28
|
+
return isNative;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -16,6 +16,7 @@ exports.gosNREUMOriginals = gosNREUMOriginals;
|
|
|
16
16
|
exports.setNREUMInitializedAgent = setNREUMInitializedAgent;
|
|
17
17
|
var _runtime = require("../constants/runtime");
|
|
18
18
|
var _now = require("../timing/now");
|
|
19
|
+
var _monkeyPatched = require("../util/monkey-patched");
|
|
19
20
|
/**
|
|
20
21
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
21
22
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -63,7 +64,7 @@ function gosNREUMOriginals() {
|
|
|
63
64
|
if (!nr.o) {
|
|
64
65
|
nr.o = {
|
|
65
66
|
ST: _runtime.globalScope.setTimeout,
|
|
66
|
-
SI: _runtime.globalScope.setImmediate,
|
|
67
|
+
SI: _runtime.globalScope.setImmediate || _runtime.globalScope.setInterval,
|
|
67
68
|
CT: _runtime.globalScope.clearTimeout,
|
|
68
69
|
XHR: _runtime.globalScope.XMLHttpRequest,
|
|
69
70
|
REQ: _runtime.globalScope.Request,
|
|
@@ -74,6 +75,7 @@ function gosNREUMOriginals() {
|
|
|
74
75
|
FETCH: _runtime.globalScope.fetch,
|
|
75
76
|
WS: _runtime.globalScope.WebSocket
|
|
76
77
|
};
|
|
78
|
+
(0, _monkeyPatched.isNative)(...Object.values(nr.o)); // Warns if the originals are not native, which is typically required for the agent to work properly
|
|
77
79
|
}
|
|
78
80
|
return nr;
|
|
79
81
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.buildCauseString = buildCauseString;
|
|
7
|
+
var _stringify = require("../../../common/util/stringify");
|
|
8
|
+
var _computeStackTrace = require("./compute-stack-trace");
|
|
9
|
+
/**
|
|
10
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
11
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
12
|
+
* @fileoverview; Extracts the cause string from an error object.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Extracts and normalizes a string from an error instance with a cause attribute.
|
|
17
|
+
* @param {Error} err - The error object to extract the cause from.
|
|
18
|
+
* @returns {string} The cause string extracted from the error object. Will be an empty string if no cause is present.
|
|
19
|
+
*/
|
|
20
|
+
function buildCauseString(err) {
|
|
21
|
+
let causeStackString = '';
|
|
22
|
+
if (!err?.cause) return causeStackString;
|
|
23
|
+
if (err.cause instanceof Error) {
|
|
24
|
+
const stackInfo = (0, _computeStackTrace.computeStackTrace)(err.cause);
|
|
25
|
+
causeStackString = stackInfo.stackString || err.cause.stack;
|
|
26
|
+
if (stackInfo.message && !causeStackString.includes(stackInfo.message)) causeStackString = stackInfo.message + '\n' + causeStackString;
|
|
27
|
+
if (stackInfo.name && !causeStackString.includes(stackInfo.name)) causeStackString = stackInfo.name + ': ' + causeStackString;
|
|
28
|
+
} else causeStackString = typeof err.cause === 'string' ? err.cause : (0, _stringify.stringify)(err.cause);
|
|
29
|
+
causeStackString ||= err.cause.toString(); // fallback to try the string representation if all else fails
|
|
30
|
+
return causeStackString;
|
|
31
|
+
}
|
|
@@ -20,6 +20,7 @@ var _traverse = require("../../../common/util/traverse");
|
|
|
20
20
|
var _internalErrors = require("./internal-errors");
|
|
21
21
|
var _target = require("../../../common/util/target");
|
|
22
22
|
var _console = require("../../../common/util/console");
|
|
23
|
+
var _causeString = require("./cause-string");
|
|
23
24
|
/**
|
|
24
25
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
25
26
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -132,10 +133,14 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
132
133
|
return;
|
|
133
134
|
}
|
|
134
135
|
var canonicalStackString = this.buildCanonicalStackString(stackInfo);
|
|
136
|
+
const causeStackString = (0, _causeString.buildCauseString)(err);
|
|
135
137
|
const params = {
|
|
136
138
|
stackHash: (0, _stringHashCode.stringHashCode)(canonicalStackString),
|
|
137
139
|
exceptionClass: stackInfo.name,
|
|
138
|
-
request_uri: _runtime.globalScope?.location.pathname
|
|
140
|
+
request_uri: _runtime.globalScope?.location.pathname,
|
|
141
|
+
...(causeStackString && {
|
|
142
|
+
cause: causeStackString
|
|
143
|
+
})
|
|
139
144
|
};
|
|
140
145
|
if (stackInfo.message) params.message = '' + stackInfo.message;
|
|
141
146
|
// Notice if filterOutput isn't false|undefined OR our specified object, this func would've returned already (so it's unnecessary to req-check group).
|
|
@@ -28,7 +28,7 @@ function castError(error) {
|
|
|
28
28
|
* The thrown value may contain a message property. If it does, try to treat the thrown
|
|
29
29
|
* value as an Error-like object.
|
|
30
30
|
*/
|
|
31
|
-
return new _uncaughtError.UncaughtError(error?.message !== undefined ? error.message : error, error?.filename || error?.sourceURL, error?.lineno || error?.line, error?.colno || error?.col, error?.__newrelic);
|
|
31
|
+
return new _uncaughtError.UncaughtError(error?.message !== undefined ? error.message : error, error?.filename || error?.sourceURL, error?.lineno || error?.line, error?.colno || error?.col, error?.__newrelic, error?.cause);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
@@ -65,7 +65,7 @@ function castPromiseRejectionEvent(promiseRejectionEvent) {
|
|
|
65
65
|
*/
|
|
66
66
|
function castErrorEvent(errorEvent) {
|
|
67
67
|
if (errorEvent.error instanceof SyntaxError && !/:\d+$/.test(errorEvent.error.stack?.trim())) {
|
|
68
|
-
const error = new _uncaughtError.UncaughtError(errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error.__newrelic);
|
|
68
|
+
const error = new _uncaughtError.UncaughtError(errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error.__newrelic, errorEvent.cause);
|
|
69
69
|
error.name = SyntaxError.name;
|
|
70
70
|
return error;
|
|
71
71
|
}
|
|
@@ -12,6 +12,7 @@ var _runtime = require("../../../common/constants/runtime");
|
|
|
12
12
|
var _log = require("../../../loaders/api/log");
|
|
13
13
|
var _wrapLogger2 = require("../../../loaders/api/wrapLogger");
|
|
14
14
|
var _register = require("../../../loaders/api/register");
|
|
15
|
+
var _monkeyPatched = require("../../../common/util/monkey-patched");
|
|
15
16
|
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); }
|
|
16
17
|
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; } /**
|
|
17
18
|
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
@@ -27,24 +28,14 @@ class Instrument extends _instrumentBase.InstrumentBase {
|
|
|
27
28
|
(0, _wrapLogger2.setupWrapLoggerAPI)(agentRef);
|
|
28
29
|
(0, _register.setupRegisterAPI)(agentRef);
|
|
29
30
|
const instanceEE = this.ee;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
(0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, 'warn', {
|
|
37
|
-
level: 'warn'
|
|
38
|
-
});
|
|
39
|
-
(0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, 'info', {
|
|
40
|
-
level: 'info'
|
|
41
|
-
});
|
|
42
|
-
(0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, 'debug', {
|
|
43
|
-
level: 'debug'
|
|
44
|
-
});
|
|
45
|
-
(0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, 'trace', {
|
|
46
|
-
level: 'trace'
|
|
31
|
+
const globals = ['log', 'error', 'warn', 'info', 'debug', 'trace'];
|
|
32
|
+
globals.forEach(method => {
|
|
33
|
+
(0, _monkeyPatched.isNative)(_runtime.globalScope.console[method]);
|
|
34
|
+
(0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, method, {
|
|
35
|
+
level: method === 'log' ? 'info' : method
|
|
36
|
+
});
|
|
47
37
|
});
|
|
38
|
+
|
|
48
39
|
/** emitted by wrap-logger function */
|
|
49
40
|
this.ee.on('wrap-logger-end', function handleLog([message]) {
|
|
50
41
|
const {
|
|
@@ -291,6 +291,24 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
291
291
|
if (node.__newrelic) return node.timestamp;
|
|
292
292
|
return this.timeKeeper.correctAbsoluteTimestamp(node.timestamp);
|
|
293
293
|
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* returns the timestamps for the earliest and latest nodes in the provided array, even if out of order
|
|
297
|
+
* @param {Object[]} [nodes] - the nodes to evaluate
|
|
298
|
+
* @returns {{ firstEvent: Object|undefined, lastEvent: Object|undefined }} - the earliest and latest nodes. Defaults to undefined if no nodes are provided or if no timestamps are found in the nodes.
|
|
299
|
+
*/
|
|
300
|
+
getFirstAndLastNodes(nodes = []) {
|
|
301
|
+
const output = {
|
|
302
|
+
firstEvent: nodes[0],
|
|
303
|
+
lastEvent: nodes[nodes.length - 1]
|
|
304
|
+
};
|
|
305
|
+
nodes.forEach(node => {
|
|
306
|
+
const timestamp = node?.timestamp;
|
|
307
|
+
if (!output.firstEvent?.timestamp || (timestamp || Infinity) < output.firstEvent.timestamp) output.firstEvent = node;
|
|
308
|
+
if (!output.lastEvent?.timestamp || (timestamp || -Infinity) > output.lastEvent.timestamp) output.lastEvent = node;
|
|
309
|
+
});
|
|
310
|
+
return output;
|
|
311
|
+
}
|
|
294
312
|
getHarvestContents(recorderEvents) {
|
|
295
313
|
recorderEvents ??= this.recorder.getEvents();
|
|
296
314
|
let events = recorderEvents.events;
|
|
@@ -315,11 +333,13 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
315
333
|
recorderEvents.hasMeta = !!events.find(x => x.type === _constants.RRWEB_EVENT_TYPES.Meta);
|
|
316
334
|
}
|
|
317
335
|
const relativeNow = (0, _now.now)();
|
|
318
|
-
const
|
|
319
|
-
|
|
336
|
+
const {
|
|
337
|
+
firstEvent,
|
|
338
|
+
lastEvent
|
|
339
|
+
} = this.getFirstAndLastNodes(events);
|
|
320
340
|
// from rrweb node || from when the harvest cycle started
|
|
321
|
-
const firstTimestamp =
|
|
322
|
-
const lastTimestamp =
|
|
341
|
+
const firstTimestamp = this.getCorrectedTimestamp(firstEvent) || Math.floor(this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp));
|
|
342
|
+
const lastTimestamp = this.getCorrectedTimestamp(lastEvent) || Math.floor(this.timeKeeper.correctRelativeTimestamp(relativeNow));
|
|
323
343
|
const agentMetadata = agentRuntime.appMetadata?.agents?.[0] || {};
|
|
324
344
|
return {
|
|
325
345
|
qs: {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { originTime } from '../constants/runtime';
|
|
6
|
+
import { isNative } from '../util/monkey-patched';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Class used to adjust the timestamp of harvested data to New Relic server time. This
|
|
@@ -38,6 +39,7 @@ export class TimeKeeper {
|
|
|
38
39
|
constructor(sessionObj) {
|
|
39
40
|
this.#session = sessionObj;
|
|
40
41
|
this.processStoredDiff();
|
|
42
|
+
isNative(performance.now, Date.now); // will warn the user if these are not native functions. We need these to be native for time in the agent to be accurate in general.
|
|
41
43
|
}
|
|
42
44
|
get ready() {
|
|
43
45
|
return this.#ready;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { warn } from './console';
|
|
6
|
+
const checked = new Map();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Checks if the provided functions are native functions.
|
|
10
|
+
* @param {...Function} fns - An array of functions to check if they are native.
|
|
11
|
+
* @returns {boolean} true if all the expected globals are native, false otherwise
|
|
12
|
+
*/
|
|
13
|
+
export function isNative(...fns) {
|
|
14
|
+
return fns.every(fn => {
|
|
15
|
+
if (checked.has(fn)) return checked.get(fn);
|
|
16
|
+
const isNative = typeof fn === 'function' && fn.toString().includes('[native code]');
|
|
17
|
+
if (!isNative) {
|
|
18
|
+
warn(64, fn?.name || fn?.toString());
|
|
19
|
+
}
|
|
20
|
+
checked.set(fn, isNative);
|
|
21
|
+
return isNative;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { globalScope } from '../constants/runtime';
|
|
6
6
|
import { now } from '../timing/now';
|
|
7
|
+
import { isNative } from '../util/monkey-patched';
|
|
7
8
|
export const defaults = {
|
|
8
9
|
beacon: 'bam.nr-data.net',
|
|
9
10
|
errorBeacon: 'bam.nr-data.net'
|
|
@@ -46,7 +47,7 @@ export function gosNREUMOriginals() {
|
|
|
46
47
|
if (!nr.o) {
|
|
47
48
|
nr.o = {
|
|
48
49
|
ST: globalScope.setTimeout,
|
|
49
|
-
SI: globalScope.setImmediate,
|
|
50
|
+
SI: globalScope.setImmediate || globalScope.setInterval,
|
|
50
51
|
CT: globalScope.clearTimeout,
|
|
51
52
|
XHR: globalScope.XMLHttpRequest,
|
|
52
53
|
REQ: globalScope.Request,
|
|
@@ -57,6 +58,7 @@ export function gosNREUMOriginals() {
|
|
|
57
58
|
FETCH: globalScope.fetch,
|
|
58
59
|
WS: globalScope.WebSocket
|
|
59
60
|
};
|
|
61
|
+
isNative(...Object.values(nr.o)); // Warns if the originals are not native, which is typically required for the agent to work properly
|
|
60
62
|
}
|
|
61
63
|
return nr;
|
|
62
64
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
* @fileoverview; Extracts the cause string from an error object.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { stringify } from '../../../common/util/stringify';
|
|
8
|
+
import { computeStackTrace } from './compute-stack-trace';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extracts and normalizes a string from an error instance with a cause attribute.
|
|
12
|
+
* @param {Error} err - The error object to extract the cause from.
|
|
13
|
+
* @returns {string} The cause string extracted from the error object. Will be an empty string if no cause is present.
|
|
14
|
+
*/
|
|
15
|
+
export function buildCauseString(err) {
|
|
16
|
+
let causeStackString = '';
|
|
17
|
+
if (!err?.cause) return causeStackString;
|
|
18
|
+
if (err.cause instanceof Error) {
|
|
19
|
+
const stackInfo = computeStackTrace(err.cause);
|
|
20
|
+
causeStackString = stackInfo.stackString || err.cause.stack;
|
|
21
|
+
if (stackInfo.message && !causeStackString.includes(stackInfo.message)) causeStackString = stackInfo.message + '\n' + causeStackString;
|
|
22
|
+
if (stackInfo.name && !causeStackString.includes(stackInfo.name)) causeStackString = stackInfo.name + ': ' + causeStackString;
|
|
23
|
+
} else causeStackString = typeof err.cause === 'string' ? err.cause : stringify(err.cause);
|
|
24
|
+
causeStackString ||= err.cause.toString(); // fallback to try the string representation if all else fails
|
|
25
|
+
return causeStackString;
|
|
26
|
+
}
|
|
@@ -19,6 +19,7 @@ import { applyFnToProps } from '../../../common/util/traverse';
|
|
|
19
19
|
import { evaluateInternalError } from './internal-errors';
|
|
20
20
|
import { isContainerAgentTarget } from '../../../common/util/target';
|
|
21
21
|
import { warn } from '../../../common/util/console';
|
|
22
|
+
import { buildCauseString } from './cause-string';
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* @typedef {import('./compute-stack-trace.js').StackInfo} StackInfo
|
|
@@ -127,10 +128,14 @@ export class Aggregate extends AggregateBase {
|
|
|
127
128
|
return;
|
|
128
129
|
}
|
|
129
130
|
var canonicalStackString = this.buildCanonicalStackString(stackInfo);
|
|
131
|
+
const causeStackString = buildCauseString(err);
|
|
130
132
|
const params = {
|
|
131
133
|
stackHash: stringHashCode(canonicalStackString),
|
|
132
134
|
exceptionClass: stackInfo.name,
|
|
133
|
-
request_uri: globalScope?.location.pathname
|
|
135
|
+
request_uri: globalScope?.location.pathname,
|
|
136
|
+
...(causeStackString && {
|
|
137
|
+
cause: causeStackString
|
|
138
|
+
})
|
|
134
139
|
};
|
|
135
140
|
if (stackInfo.message) params.message = '' + stackInfo.message;
|
|
136
141
|
// Notice if filterOutput isn't false|undefined OR our specified object, this func would've returned already (so it's unnecessary to req-check group).
|
|
@@ -20,7 +20,7 @@ export function castError(error) {
|
|
|
20
20
|
* The thrown value may contain a message property. If it does, try to treat the thrown
|
|
21
21
|
* value as an Error-like object.
|
|
22
22
|
*/
|
|
23
|
-
return new UncaughtError(error?.message !== undefined ? error.message : error, error?.filename || error?.sourceURL, error?.lineno || error?.line, error?.colno || error?.col, error?.__newrelic);
|
|
23
|
+
return new UncaughtError(error?.message !== undefined ? error.message : error, error?.filename || error?.sourceURL, error?.lineno || error?.line, error?.colno || error?.col, error?.__newrelic, error?.cause);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -57,7 +57,7 @@ export function castPromiseRejectionEvent(promiseRejectionEvent) {
|
|
|
57
57
|
*/
|
|
58
58
|
export function castErrorEvent(errorEvent) {
|
|
59
59
|
if (errorEvent.error instanceof SyntaxError && !/:\d+$/.test(errorEvent.error.stack?.trim())) {
|
|
60
|
-
const error = new UncaughtError(errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error.__newrelic);
|
|
60
|
+
const error = new UncaughtError(errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error.__newrelic, errorEvent.cause);
|
|
61
61
|
error.name = SyntaxError.name;
|
|
62
62
|
return error;
|
|
63
63
|
}
|
|
@@ -10,6 +10,7 @@ import { globalScope } from '../../../common/constants/runtime';
|
|
|
10
10
|
import { setupLogAPI } from '../../../loaders/api/log';
|
|
11
11
|
import { setupWrapLoggerAPI } from '../../../loaders/api/wrapLogger';
|
|
12
12
|
import { setupRegisterAPI } from '../../../loaders/api/register';
|
|
13
|
+
import { isNative } from '../../../common/util/monkey-patched';
|
|
13
14
|
export class Instrument extends InstrumentBase {
|
|
14
15
|
static featureName = FEATURE_NAME;
|
|
15
16
|
constructor(agentRef) {
|
|
@@ -20,24 +21,14 @@ export class Instrument extends InstrumentBase {
|
|
|
20
21
|
setupWrapLoggerAPI(agentRef);
|
|
21
22
|
setupRegisterAPI(agentRef);
|
|
22
23
|
const instanceEE = this.ee;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
wrapLogger(instanceEE, globalScope.console, 'warn', {
|
|
30
|
-
level: 'warn'
|
|
31
|
-
});
|
|
32
|
-
wrapLogger(instanceEE, globalScope.console, 'info', {
|
|
33
|
-
level: 'info'
|
|
34
|
-
});
|
|
35
|
-
wrapLogger(instanceEE, globalScope.console, 'debug', {
|
|
36
|
-
level: 'debug'
|
|
37
|
-
});
|
|
38
|
-
wrapLogger(instanceEE, globalScope.console, 'trace', {
|
|
39
|
-
level: 'trace'
|
|
24
|
+
const globals = ['log', 'error', 'warn', 'info', 'debug', 'trace'];
|
|
25
|
+
globals.forEach(method => {
|
|
26
|
+
isNative(globalScope.console[method]);
|
|
27
|
+
wrapLogger(instanceEE, globalScope.console, method, {
|
|
28
|
+
level: method === 'log' ? 'info' : method
|
|
29
|
+
});
|
|
40
30
|
});
|
|
31
|
+
|
|
41
32
|
/** emitted by wrap-logger function */
|
|
42
33
|
this.ee.on('wrap-logger-end', function handleLog([message]) {
|
|
43
34
|
const {
|
|
@@ -286,6 +286,24 @@ export class Aggregate extends AggregateBase {
|
|
|
286
286
|
if (node.__newrelic) return node.timestamp;
|
|
287
287
|
return this.timeKeeper.correctAbsoluteTimestamp(node.timestamp);
|
|
288
288
|
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* returns the timestamps for the earliest and latest nodes in the provided array, even if out of order
|
|
292
|
+
* @param {Object[]} [nodes] - the nodes to evaluate
|
|
293
|
+
* @returns {{ firstEvent: Object|undefined, lastEvent: Object|undefined }} - the earliest and latest nodes. Defaults to undefined if no nodes are provided or if no timestamps are found in the nodes.
|
|
294
|
+
*/
|
|
295
|
+
getFirstAndLastNodes(nodes = []) {
|
|
296
|
+
const output = {
|
|
297
|
+
firstEvent: nodes[0],
|
|
298
|
+
lastEvent: nodes[nodes.length - 1]
|
|
299
|
+
};
|
|
300
|
+
nodes.forEach(node => {
|
|
301
|
+
const timestamp = node?.timestamp;
|
|
302
|
+
if (!output.firstEvent?.timestamp || (timestamp || Infinity) < output.firstEvent.timestamp) output.firstEvent = node;
|
|
303
|
+
if (!output.lastEvent?.timestamp || (timestamp || -Infinity) > output.lastEvent.timestamp) output.lastEvent = node;
|
|
304
|
+
});
|
|
305
|
+
return output;
|
|
306
|
+
}
|
|
289
307
|
getHarvestContents(recorderEvents) {
|
|
290
308
|
recorderEvents ??= this.recorder.getEvents();
|
|
291
309
|
let events = recorderEvents.events;
|
|
@@ -310,11 +328,13 @@ export class Aggregate extends AggregateBase {
|
|
|
310
328
|
recorderEvents.hasMeta = !!events.find(x => x.type === RRWEB_EVENT_TYPES.Meta);
|
|
311
329
|
}
|
|
312
330
|
const relativeNow = now();
|
|
313
|
-
const
|
|
314
|
-
|
|
331
|
+
const {
|
|
332
|
+
firstEvent,
|
|
333
|
+
lastEvent
|
|
334
|
+
} = this.getFirstAndLastNodes(events);
|
|
315
335
|
// from rrweb node || from when the harvest cycle started
|
|
316
|
-
const firstTimestamp =
|
|
317
|
-
const lastTimestamp =
|
|
336
|
+
const firstTimestamp = this.getCorrectedTimestamp(firstEvent) || Math.floor(this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp));
|
|
337
|
+
const lastTimestamp = this.getCorrectedTimestamp(lastEvent) || Math.floor(this.timeKeeper.correctRelativeTimestamp(relativeNow));
|
|
318
338
|
const agentMetadata = agentRuntime.appMetadata?.agents?.[0] || {};
|
|
319
339
|
return {
|
|
320
340
|
qs: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.js","../src/cdn/experimental.js","../src/cdn/lite.js","../src/cdn/pro.js","../src/cdn/spa.js","../src/common/aggregate/aggregator.js","../src/common/aggregate/event-aggregator.js","../src/common/config/configurable.js","../src/common/config/info.js","../src/common/config/init-types.js","../src/common/config/init.js","../src/common/config/loader-config.js","../src/common/config/runtime.js","../src/common/constants/agent-constants.js","../src/common/constants/env.cdn.js","../src/common/constants/env.js","../src/common/constants/env.npm.js","../src/common/constants/runtime.js","../src/common/constants/shared-channel.js","../src/common/deny-list/deny-list.js","../src/common/dispatch/global-event.js","../src/common/dom/iframe.js","../src/common/dom/query-selector.js","../src/common/dom/selector-path.js","../src/common/drain/drain.js","../src/common/event-emitter/contextual-ee.js","../src/common/event-emitter/event-context.js","../src/common/event-emitter/handle.js","../src/common/event-emitter/register-handler.js","../src/common/event-listener/event-listener-opts.js","../src/common/harvest/harvester.js","../src/common/harvest/types.js","../src/common/ids/bundle-id.js","../src/common/ids/id.js","../src/common/ids/unique-id.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/storage/local-storage.js","../src/common/timer/interaction-timer.js","../src/common/timer/timer.js","../src/common/timing/nav-timing.js","../src/common/timing/now.js","../src/common/timing/time-keeper.js","../src/common/unload/eol.js","../src/common/url/canonicalize-url.js","../src/common/url/clean-url.js","../src/common/url/encode.js","../src/common/url/location.js","../src/common/url/parse-url.js","../src/common/url/protocol.js","../src/common/util/attribute-size.js","../src/common/util/console.js","../src/common/util/data-size.js","../src/common/util/event-origin.js","../src/common/util/feature-flags.js","../src/common/util/get-or-set.js","../src/common/util/invoke.js","../src/common/util/obfuscate.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/target.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/vitals/constants.js","../src/common/vitals/cumulative-layout-shift.js","../src/common/vitals/first-contentful-paint.js","../src/common/vitals/first-paint.js","../src/common/vitals/interaction-to-next-paint.js","../src/common/vitals/largest-contentful-paint.js","../src/common/vitals/time-to-first-byte.js","../src/common/vitals/vital-metric.js","../src/common/window/load.js","../src/common/window/nreum.js","../src/common/window/page-visibility.js","../src/common/wrap/wrap-events.js","../src/common/wrap/wrap-fetch.js","../src/common/wrap/wrap-function.js","../src/common/wrap/wrap-history.js","../src/common/wrap/wrap-jsonp.js","../src/common/wrap/wrap-logger.js","../src/common/wrap/wrap-mutation.js","../src/common/wrap/wrap-promise.js","../src/common/wrap/wrap-timer.js","../src/common/wrap/wrap-websocket.js","../src/common/wrap/wrap-xhr.js","../src/features/ajax/constants.js","../src/features/ajax/index.js","../src/features/ajax/aggregate/gql.js","../src/features/ajax/aggregate/index.js","../src/features/ajax/instrument/distributed-tracing.js","../src/features/ajax/instrument/index.js","../src/features/ajax/instrument/response-size.js","../src/features/generic_events/constants.js","../src/features/generic_events/index.js","../src/features/generic_events/aggregate/index.js","../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js","../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js","../src/features/generic_events/instrument/index.js","../src/features/jserrors/constants.js","../src/features/jserrors/index.js","../src/features/jserrors/aggregate/canonical-function-name.js","../src/features/jserrors/aggregate/compute-stack-trace.js","../src/features/jserrors/aggregate/format-stack-trace.js","../src/features/jserrors/aggregate/index.js","../src/features/jserrors/aggregate/internal-errors.js","../src/features/jserrors/aggregate/string-hash-code.js","../src/features/jserrors/instrument/index.js","../src/features/jserrors/shared/cast-error.js","../src/features/jserrors/shared/uncaught-error.js","../src/features/logging/constants.js","../src/features/logging/index.js","../src/features/logging/aggregate/index.js","../src/features/logging/instrument/index.js","../src/features/logging/shared/log.js","../src/features/logging/shared/utils.js","../src/features/metrics/constants.js","../src/features/metrics/index.js","../src/features/metrics/aggregate/framework-detection.js","../src/features/metrics/aggregate/index.js","../src/features/metrics/aggregate/websocket-detection.js","../src/features/metrics/instrument/index.js","../src/features/page_action/constants.js","../src/features/page_action/index.js","../src/features/page_action/instrument/index.js","../src/features/page_view_event/constants.js","../src/features/page_view_event/index.js","../src/features/page_view_event/aggregate/index.js","../src/features/page_view_event/aggregate/initialized-features.js","../src/features/page_view_event/instrument/index.js","../src/features/page_view_timing/constants.js","../src/features/page_view_timing/index.js","../src/features/page_view_timing/aggregate/index.js","../src/features/page_view_timing/instrument/index.js","../src/features/session_replay/constants.js","../src/features/session_replay/index.js","../src/features/session_replay/aggregate/index.js","../src/features/session_replay/instrument/index.js","../src/features/session_replay/shared/recorder-events.js","../src/features/session_replay/shared/recorder.js","../src/features/session_replay/shared/stylesheet-evaluator.js","../src/features/session_replay/shared/utils.js","../src/features/session_trace/constants.js","../src/features/session_trace/index.js","../src/features/session_trace/aggregate/index.js","../src/features/session_trace/aggregate/trace/node.js","../src/features/session_trace/aggregate/trace/storage.js","../src/features/session_trace/instrument/index.js","../src/features/soft_navigations/constants.js","../src/features/soft_navigations/index.js","../src/features/soft_navigations/aggregate/ajax-node.js","../src/features/soft_navigations/aggregate/bel-node.js","../src/features/soft_navigations/aggregate/index.js","../src/features/soft_navigations/aggregate/initial-page-load-interaction.js","../src/features/soft_navigations/aggregate/interaction.js","../src/features/soft_navigations/instrument/index.js","../src/features/spa/constants.js","../src/features/spa/index.js","../src/features/spa/aggregate/index.js","../src/features/spa/aggregate/interaction-node.js","../src/features/spa/aggregate/interaction.js","../src/features/spa/aggregate/serializer.js","../src/features/spa/instrument/index.js","../src/features/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/entity-manager.js","../src/features/utils/event-buffer.js","../src/features/utils/event-store-manager.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.js","../src/features/utils/nr1-debugger.js","../src/interfaces/registered-entity.js","../src/loaders/agent-base.js","../src/loaders/agent.js","../src/loaders/api-base.js","../src/loaders/browser-agent.js","../src/loaders/micro-agent-base.js","../src/loaders/micro-agent.js","../src/loaders/api/addPageAction.js","../src/loaders/api/addRelease.js","../src/loaders/api/addToTrace.js","../src/loaders/api/constants.js","../src/loaders/api/finished.js","../src/loaders/api/interaction-types.js","../src/loaders/api/interaction.js","../src/loaders/api/log.js","../src/loaders/api/measure.js","../src/loaders/api/noticeError.js","../src/loaders/api/pauseReplay.js","../src/loaders/api/recordCustomEvent.js","../src/loaders/api/recordReplay.js","../src/loaders/api/register-api-types.js","../src/loaders/api/register-api.js","../src/loaders/api/register.js","../src/loaders/api/setApplicationVersion.js","../src/loaders/api/setCustomAttribute.js","../src/loaders/api/setErrorHandler.js","../src/loaders/api/setPageViewName.js","../src/loaders/api/setUserId.js","../src/loaders/api/sharedHandlers.js","../src/loaders/api/start.js","../src/loaders/api/topLevelCallers.js","../src/loaders/api/wrapLogger.js","../src/loaders/configure/configure.js","../src/loaders/configure/nonce.js","../src/loaders/configure/public-path.js","../src/loaders/features/enabled-features.js","../src/loaders/features/featureDependencies.js","../src/loaders/features/features.js"],"version":"5.7.3"}
|
|
1
|
+
{"root":["../src/index.js","../src/cdn/experimental.js","../src/cdn/lite.js","../src/cdn/pro.js","../src/cdn/spa.js","../src/common/aggregate/aggregator.js","../src/common/aggregate/event-aggregator.js","../src/common/config/configurable.js","../src/common/config/info.js","../src/common/config/init-types.js","../src/common/config/init.js","../src/common/config/loader-config.js","../src/common/config/runtime.js","../src/common/constants/agent-constants.js","../src/common/constants/env.cdn.js","../src/common/constants/env.js","../src/common/constants/env.npm.js","../src/common/constants/runtime.js","../src/common/constants/shared-channel.js","../src/common/deny-list/deny-list.js","../src/common/dispatch/global-event.js","../src/common/dom/iframe.js","../src/common/dom/query-selector.js","../src/common/dom/selector-path.js","../src/common/drain/drain.js","../src/common/event-emitter/contextual-ee.js","../src/common/event-emitter/event-context.js","../src/common/event-emitter/handle.js","../src/common/event-emitter/register-handler.js","../src/common/event-listener/event-listener-opts.js","../src/common/harvest/harvester.js","../src/common/harvest/types.js","../src/common/ids/bundle-id.js","../src/common/ids/id.js","../src/common/ids/unique-id.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/storage/local-storage.js","../src/common/timer/interaction-timer.js","../src/common/timer/timer.js","../src/common/timing/nav-timing.js","../src/common/timing/now.js","../src/common/timing/time-keeper.js","../src/common/unload/eol.js","../src/common/url/canonicalize-url.js","../src/common/url/clean-url.js","../src/common/url/encode.js","../src/common/url/location.js","../src/common/url/parse-url.js","../src/common/url/protocol.js","../src/common/util/attribute-size.js","../src/common/util/console.js","../src/common/util/data-size.js","../src/common/util/event-origin.js","../src/common/util/feature-flags.js","../src/common/util/get-or-set.js","../src/common/util/invoke.js","../src/common/util/monkey-patched.js","../src/common/util/obfuscate.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/target.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/vitals/constants.js","../src/common/vitals/cumulative-layout-shift.js","../src/common/vitals/first-contentful-paint.js","../src/common/vitals/first-paint.js","../src/common/vitals/interaction-to-next-paint.js","../src/common/vitals/largest-contentful-paint.js","../src/common/vitals/time-to-first-byte.js","../src/common/vitals/vital-metric.js","../src/common/window/load.js","../src/common/window/nreum.js","../src/common/window/page-visibility.js","../src/common/wrap/wrap-events.js","../src/common/wrap/wrap-fetch.js","../src/common/wrap/wrap-function.js","../src/common/wrap/wrap-history.js","../src/common/wrap/wrap-jsonp.js","../src/common/wrap/wrap-logger.js","../src/common/wrap/wrap-mutation.js","../src/common/wrap/wrap-promise.js","../src/common/wrap/wrap-timer.js","../src/common/wrap/wrap-websocket.js","../src/common/wrap/wrap-xhr.js","../src/features/ajax/constants.js","../src/features/ajax/index.js","../src/features/ajax/aggregate/gql.js","../src/features/ajax/aggregate/index.js","../src/features/ajax/instrument/distributed-tracing.js","../src/features/ajax/instrument/index.js","../src/features/ajax/instrument/response-size.js","../src/features/generic_events/constants.js","../src/features/generic_events/index.js","../src/features/generic_events/aggregate/index.js","../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js","../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js","../src/features/generic_events/instrument/index.js","../src/features/jserrors/constants.js","../src/features/jserrors/index.js","../src/features/jserrors/aggregate/canonical-function-name.js","../src/features/jserrors/aggregate/cause-string.js","../src/features/jserrors/aggregate/compute-stack-trace.js","../src/features/jserrors/aggregate/format-stack-trace.js","../src/features/jserrors/aggregate/index.js","../src/features/jserrors/aggregate/internal-errors.js","../src/features/jserrors/aggregate/string-hash-code.js","../src/features/jserrors/instrument/index.js","../src/features/jserrors/shared/cast-error.js","../src/features/jserrors/shared/uncaught-error.js","../src/features/logging/constants.js","../src/features/logging/index.js","../src/features/logging/aggregate/index.js","../src/features/logging/instrument/index.js","../src/features/logging/shared/log.js","../src/features/logging/shared/utils.js","../src/features/metrics/constants.js","../src/features/metrics/index.js","../src/features/metrics/aggregate/framework-detection.js","../src/features/metrics/aggregate/index.js","../src/features/metrics/aggregate/websocket-detection.js","../src/features/metrics/instrument/index.js","../src/features/page_action/constants.js","../src/features/page_action/index.js","../src/features/page_action/instrument/index.js","../src/features/page_view_event/constants.js","../src/features/page_view_event/index.js","../src/features/page_view_event/aggregate/index.js","../src/features/page_view_event/aggregate/initialized-features.js","../src/features/page_view_event/instrument/index.js","../src/features/page_view_timing/constants.js","../src/features/page_view_timing/index.js","../src/features/page_view_timing/aggregate/index.js","../src/features/page_view_timing/instrument/index.js","../src/features/session_replay/constants.js","../src/features/session_replay/index.js","../src/features/session_replay/aggregate/index.js","../src/features/session_replay/instrument/index.js","../src/features/session_replay/shared/recorder-events.js","../src/features/session_replay/shared/recorder.js","../src/features/session_replay/shared/stylesheet-evaluator.js","../src/features/session_replay/shared/utils.js","../src/features/session_trace/constants.js","../src/features/session_trace/index.js","../src/features/session_trace/aggregate/index.js","../src/features/session_trace/aggregate/trace/node.js","../src/features/session_trace/aggregate/trace/storage.js","../src/features/session_trace/instrument/index.js","../src/features/soft_navigations/constants.js","../src/features/soft_navigations/index.js","../src/features/soft_navigations/aggregate/ajax-node.js","../src/features/soft_navigations/aggregate/bel-node.js","../src/features/soft_navigations/aggregate/index.js","../src/features/soft_navigations/aggregate/initial-page-load-interaction.js","../src/features/soft_navigations/aggregate/interaction.js","../src/features/soft_navigations/instrument/index.js","../src/features/spa/constants.js","../src/features/spa/index.js","../src/features/spa/aggregate/index.js","../src/features/spa/aggregate/interaction-node.js","../src/features/spa/aggregate/interaction.js","../src/features/spa/aggregate/serializer.js","../src/features/spa/instrument/index.js","../src/features/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/entity-manager.js","../src/features/utils/event-buffer.js","../src/features/utils/event-store-manager.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.js","../src/features/utils/nr1-debugger.js","../src/interfaces/registered-entity.js","../src/loaders/agent-base.js","../src/loaders/agent.js","../src/loaders/api-base.js","../src/loaders/browser-agent.js","../src/loaders/micro-agent-base.js","../src/loaders/micro-agent.js","../src/loaders/api/addPageAction.js","../src/loaders/api/addRelease.js","../src/loaders/api/addToTrace.js","../src/loaders/api/constants.js","../src/loaders/api/finished.js","../src/loaders/api/interaction-types.js","../src/loaders/api/interaction.js","../src/loaders/api/log.js","../src/loaders/api/measure.js","../src/loaders/api/noticeError.js","../src/loaders/api/pauseReplay.js","../src/loaders/api/recordCustomEvent.js","../src/loaders/api/recordReplay.js","../src/loaders/api/register-api-types.js","../src/loaders/api/register-api.js","../src/loaders/api/register.js","../src/loaders/api/setApplicationVersion.js","../src/loaders/api/setCustomAttribute.js","../src/loaders/api/setErrorHandler.js","../src/loaders/api/setPageViewName.js","../src/loaders/api/setUserId.js","../src/loaders/api/sharedHandlers.js","../src/loaders/api/start.js","../src/loaders/api/topLevelCallers.js","../src/loaders/api/wrapLogger.js","../src/loaders/configure/configure.js","../src/loaders/configure/nonce.js","../src/loaders/configure/public-path.js","../src/loaders/features/enabled-features.js","../src/loaders/features/featureDependencies.js","../src/loaders/features/features.js"],"version":"5.7.3"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"AAOA;;;;GAIG;AACH;IA2BE,6BAIC;IAED,qBAEC;IAED,kCAEC;IAED,4BAEC;IAED;;;;;;OAMG;IACH,8BALsB,cAAc,aACf,MAAM,WACR,MAAM,gBACD,MAAM,QAqB7B;IAED;;;;;OAKG;IACH,uCAHwB,MAAM,GACjB,MAAM,CAIlB;IAED;;;;;OAKG;IACH,0CAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,oCAHqB,MAAM,GACf,MAAM,CAIjB;IAED;;;;OAIG;IACH,uCAHW,mBAAmB,GACjB,MAAM,CAIlB;IAED,+FAA+F;IAC/F,0BASC;;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if the provided functions are native functions.
|
|
3
|
+
* @param {...Function} fns - An array of functions to check if they are native.
|
|
4
|
+
* @returns {boolean} true if all the expected globals are native, false otherwise
|
|
5
|
+
*/
|
|
6
|
+
export function isNative(...fns: Function[]): boolean;
|
|
7
|
+
//# sourceMappingURL=monkey-patched.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monkey-patched.d.ts","sourceRoot":"","sources":["../../../../src/common/util/monkey-patched.js"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,iCAHW,UAAW,GACT,OAAO,CAYnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nreum.d.ts","sourceRoot":"","sources":["../../../../src/common/window/nreum.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nreum.d.ts","sourceRoot":"","sources":["../../../../src/common/window/nreum.js"],"names":[],"mappings":"AAaA,gCAMC;AAED,oCAWC;AAED,4CASC;AAED,oCASC;AAED,yCAkBC;AAED,+EAQC;AAED;;;;GAIG;AACH,uDAGC;AAED,uDAGC;AAED,yCAGC;AAED,8BAMC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts and normalizes a string from an error instance with a cause attribute.
|
|
3
|
+
* @param {Error} err - The error object to extract the cause from.
|
|
4
|
+
* @returns {string} The cause string extracted from the error object. Will be an empty string if no cause is present.
|
|
5
|
+
*/
|
|
6
|
+
export function buildCauseString(err: Error): string;
|
|
7
|
+
//# sourceMappingURL=cause-string.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cause-string.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/cause-string.js"],"names":[],"mappings":"AASA;;;;GAIG;AACH,sCAHW,KAAK,GACH,MAAM,CAalB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/index.js"],"names":[],"mappings":"AAyBA;;GAEG;AAEH;IACE,2BAAiC;IACjC,2BA4BC;IAzBC,kBAAuB;IACvB,eAAoB;IACpB,qBAA0B;IAC1B,2BAAgC;IAChC,qBAAwB;IAuB1B,oDAEC;IAED;;;MAcC;IAED;;;;;;OAMG;IACH,qCAHW,SAAS,GACP,MAAM,CAgBlB;IAED;;;;;;;;;;OAUG;IACH,gBATW,KAAK,GAAC,aAAa,QACnB,MAAM,aACN,OAAO,YAAC,qBACR,MAAM,YAAC,cACP,OAAO,YAAC,kBACR,MAAM,YAAC,+BAiHjB;IA4BD;;;;;MAKE;IACF,0CAHU,MAAM,GACJ,OAAO,CAIlB;IAGD,yDA6BC;IAED,qFAOC;;CACF;wBApRY,OAAO,0BAA0B,EAAE,SAAS;8BAT3B,4BAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cast-error.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/shared/cast-error.js"],"names":[],"mappings":"AAMA;;;;;KAKK;AACL,iCAHa,GAAG,GACD,KAAK,GAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"cast-error.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/shared/cast-error.js"],"names":[],"mappings":"AAMA;;;;;KAKK;AACL,iCAHa,GAAG,GACD,KAAK,GAAC,aAAa,CAoBjC;AAED;;;;KAIK;AACL,uEAFe,KAAK,CAwBnB;AAED;;;;KAIK;AACL,2CAHa,UAAU,GACR,KAAK,GAAC,aAAa,CAUjC;8BAtE6B,kBAAkB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/instrument/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/instrument/index.js"],"names":[],"mappings":"AAcA;IACE,2BAAiC;IACjC,2BAsBC;CACF;AAED,wCAAiC;+BArCF,6BAA6B"}
|
|
@@ -31,6 +31,15 @@ export class Aggregate extends AggregateBase {
|
|
|
31
31
|
payload: undefined;
|
|
32
32
|
}[] | undefined;
|
|
33
33
|
getCorrectedTimestamp(node: any): any;
|
|
34
|
+
/**
|
|
35
|
+
* returns the timestamps for the earliest and latest nodes in the provided array, even if out of order
|
|
36
|
+
* @param {Object[]} [nodes] - the nodes to evaluate
|
|
37
|
+
* @returns {{ firstEvent: Object|undefined, lastEvent: Object|undefined }} - the earliest and latest nodes. Defaults to undefined if no nodes are provided or if no timestamps are found in the nodes.
|
|
38
|
+
*/
|
|
39
|
+
getFirstAndLastNodes(nodes?: Object[]): {
|
|
40
|
+
firstEvent: Object | undefined;
|
|
41
|
+
lastEvent: Object | undefined;
|
|
42
|
+
};
|
|
34
43
|
getHarvestContents(recorderEvents: any): {
|
|
35
44
|
qs: {
|
|
36
45
|
browser_monitoring_key: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AAyBA;IACE,2BAAiC;IAIjC,sCAsFC;IAzFD,aAAe;IAKb,iFAAiF;IACjF,qBAAwB;IAGxB,2CAA2C;IAC3C,sDAAwB;IACxB,6CAA6C;IAC7C,gDAAmB;IAEnB,0BAA0B;IAC1B,kBAAqB;IACrB,6CAA6C;IAC7C,gBAA2B;IAE3B,cAA8B;IAC9B,kBAA+C;IAG/C,kCAAqG;IAoEvG,0BAEC;IAED,0BAMC;IAED,qBAUC;IAED;;;;;OAKG;IACH,4BAJW,OAAO,iBACP,OAAO,GACL,IAAI,CAuDhB;IAED,2BASC;IAED;;;oBAuDC;IAED,sCAIC;IAED;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AAyBA;IACE,2BAAiC;IAIjC,sCAsFC;IAzFD,aAAe;IAKb,iFAAiF;IACjF,qBAAwB;IAGxB,2CAA2C;IAC3C,sDAAwB;IACxB,6CAA6C;IAC7C,gDAAmB;IAEnB,0BAA0B;IAC1B,kBAAqB;IACrB,6CAA6C;IAC7C,gBAA2B;IAE3B,cAA8B;IAC9B,kBAA+C;IAG/C,kCAAqG;IAoEvG,0BAEC;IAED,0BAMC;IAED,qBAUC;IAED;;;;;OAKG;IACH,4BAJW,OAAO,iBACP,OAAO,GACL,IAAI,CAuDhB;IAED,2BASC;IAED;;;oBAuDC;IAED,sCAIC;IAED;;;;OAIG;IACH,6BAHW,MAAM,EAAE,GACN;QAAE,UAAU,EAAE,MAAM,GAAC,SAAS,CAAC;QAAC,SAAS,EAAE,MAAM,GAAC,SAAS,CAAA;KAAE,CAUzE;IAED;;;;;;;;;;MAsEC;IAED,sCAKC;IAED;;;;OAIG;IACH,mCAKC;IAED,yDAAyD;IACzD,+CASC;IAED,yCAIC;CACF;8BAtY6B,4BAA4B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/browser-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.295.0-rc.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
|
|
6
6
|
"description": "New Relic Browser Agent",
|
|
@@ -295,4 +295,4 @@
|
|
|
295
295
|
"README.md",
|
|
296
296
|
"CHANGELOG.md"
|
|
297
297
|
]
|
|
298
|
-
}
|
|
298
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { originTime } from '../constants/runtime'
|
|
6
|
+
import { isNative } from '../util/monkey-patched'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Class used to adjust the timestamp of harvested data to New Relic server time. This
|
|
@@ -39,6 +40,7 @@ export class TimeKeeper {
|
|
|
39
40
|
constructor (sessionObj) {
|
|
40
41
|
this.#session = sessionObj
|
|
41
42
|
this.processStoredDiff()
|
|
43
|
+
isNative(performance.now, Date.now) // will warn the user if these are not native functions. We need these to be native for time in the agent to be accurate in general.
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
get ready () {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { warn } from './console'
|
|
6
|
+
|
|
7
|
+
const checked = new Map()
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Checks if the provided functions are native functions.
|
|
11
|
+
* @param {...Function} fns - An array of functions to check if they are native.
|
|
12
|
+
* @returns {boolean} true if all the expected globals are native, false otherwise
|
|
13
|
+
*/
|
|
14
|
+
export function isNative (...fns) {
|
|
15
|
+
return fns.every(fn => {
|
|
16
|
+
if (checked.has(fn)) return checked.get(fn)
|
|
17
|
+
const isNative = typeof fn === 'function' && fn.toString().includes('[native code]')
|
|
18
|
+
if (!isNative) {
|
|
19
|
+
warn(64, fn?.name || fn?.toString())
|
|
20
|
+
}
|
|
21
|
+
checked.set(fn, isNative)
|
|
22
|
+
return isNative
|
|
23
|
+
})
|
|
24
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { globalScope } from '../constants/runtime'
|
|
6
6
|
import { now } from '../timing/now'
|
|
7
|
+
import { isNative } from '../util/monkey-patched'
|
|
7
8
|
|
|
8
9
|
export const defaults = {
|
|
9
10
|
beacon: 'bam.nr-data.net',
|
|
@@ -58,7 +59,7 @@ export function gosNREUMOriginals () {
|
|
|
58
59
|
if (!nr.o) {
|
|
59
60
|
nr.o = {
|
|
60
61
|
ST: globalScope.setTimeout,
|
|
61
|
-
SI: globalScope.setImmediate,
|
|
62
|
+
SI: globalScope.setImmediate || globalScope.setInterval,
|
|
62
63
|
CT: globalScope.clearTimeout,
|
|
63
64
|
XHR: globalScope.XMLHttpRequest,
|
|
64
65
|
REQ: globalScope.Request,
|
|
@@ -68,6 +69,7 @@ export function gosNREUMOriginals () {
|
|
|
68
69
|
FETCH: globalScope.fetch,
|
|
69
70
|
WS: globalScope.WebSocket
|
|
70
71
|
}
|
|
72
|
+
isNative(...Object.values(nr.o)) // Warns if the originals are not native, which is typically required for the agent to work properly
|
|
71
73
|
}
|
|
72
74
|
return nr
|
|
73
75
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2025 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
* @fileoverview; Extracts the cause string from an error object.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { stringify } from '../../../common/util/stringify'
|
|
8
|
+
import { computeStackTrace } from './compute-stack-trace'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extracts and normalizes a string from an error instance with a cause attribute.
|
|
12
|
+
* @param {Error} err - The error object to extract the cause from.
|
|
13
|
+
* @returns {string} The cause string extracted from the error object. Will be an empty string if no cause is present.
|
|
14
|
+
*/
|
|
15
|
+
export function buildCauseString (err) {
|
|
16
|
+
let causeStackString = ''
|
|
17
|
+
if (!err?.cause) return causeStackString
|
|
18
|
+
if (err.cause instanceof Error) {
|
|
19
|
+
const stackInfo = computeStackTrace(err.cause)
|
|
20
|
+
causeStackString = stackInfo.stackString || err.cause.stack
|
|
21
|
+
if (stackInfo.message && !causeStackString.includes(stackInfo.message)) causeStackString = stackInfo.message + '\n' + causeStackString
|
|
22
|
+
if (stackInfo.name && !causeStackString.includes(stackInfo.name)) causeStackString = stackInfo.name + ': ' + causeStackString
|
|
23
|
+
} else causeStackString = typeof err.cause === 'string' ? err.cause : stringify(err.cause)
|
|
24
|
+
causeStackString ||= err.cause.toString() // fallback to try the string representation if all else fails
|
|
25
|
+
return causeStackString
|
|
26
|
+
}
|
|
@@ -21,6 +21,7 @@ import { applyFnToProps } from '../../../common/util/traverse'
|
|
|
21
21
|
import { evaluateInternalError } from './internal-errors'
|
|
22
22
|
import { isContainerAgentTarget } from '../../../common/util/target'
|
|
23
23
|
import { warn } from '../../../common/util/console'
|
|
24
|
+
import { buildCauseString } from './cause-string'
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* @typedef {import('./compute-stack-trace.js').StackInfo} StackInfo
|
|
@@ -140,10 +141,13 @@ export class Aggregate extends AggregateBase {
|
|
|
140
141
|
|
|
141
142
|
var canonicalStackString = this.buildCanonicalStackString(stackInfo)
|
|
142
143
|
|
|
144
|
+
const causeStackString = buildCauseString(err)
|
|
145
|
+
|
|
143
146
|
const params = {
|
|
144
147
|
stackHash: stringHashCode(canonicalStackString),
|
|
145
148
|
exceptionClass: stackInfo.name,
|
|
146
|
-
request_uri: globalScope?.location.pathname
|
|
149
|
+
request_uri: globalScope?.location.pathname,
|
|
150
|
+
...(causeStackString && { cause: causeStackString })
|
|
147
151
|
}
|
|
148
152
|
if (stackInfo.message) params.message = '' + stackInfo.message
|
|
149
153
|
// Notice if filterOutput isn't false|undefined OR our specified object, this func would've returned already (so it's unnecessary to req-check group).
|
|
@@ -25,7 +25,8 @@ export function castError (error) {
|
|
|
25
25
|
error?.filename || error?.sourceURL,
|
|
26
26
|
error?.lineno || error?.line,
|
|
27
27
|
error?.colno || error?.col,
|
|
28
|
-
error?.__newrelic
|
|
28
|
+
error?.__newrelic,
|
|
29
|
+
error?.cause
|
|
29
30
|
)
|
|
30
31
|
}
|
|
31
32
|
|
|
@@ -65,7 +66,7 @@ export function castPromiseRejectionEvent (promiseRejectionEvent) {
|
|
|
65
66
|
*/
|
|
66
67
|
export function castErrorEvent (errorEvent) {
|
|
67
68
|
if (errorEvent.error instanceof SyntaxError && !/:\d+$/.test(errorEvent.error.stack?.trim())) {
|
|
68
|
-
const error = new UncaughtError(errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error.__newrelic)
|
|
69
|
+
const error = new UncaughtError(errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error.__newrelic, errorEvent.cause)
|
|
69
70
|
error.name = SyntaxError.name
|
|
70
71
|
return error
|
|
71
72
|
}
|
|
@@ -10,6 +10,7 @@ import { globalScope } from '../../../common/constants/runtime'
|
|
|
10
10
|
import { setupLogAPI } from '../../../loaders/api/log'
|
|
11
11
|
import { setupWrapLoggerAPI } from '../../../loaders/api/wrapLogger'
|
|
12
12
|
import { setupRegisterAPI } from '../../../loaders/api/register'
|
|
13
|
+
import { isNative } from '../../../common/util/monkey-patched'
|
|
13
14
|
|
|
14
15
|
export class Instrument extends InstrumentBase {
|
|
15
16
|
static featureName = FEATURE_NAME
|
|
@@ -22,12 +23,13 @@ export class Instrument extends InstrumentBase {
|
|
|
22
23
|
setupRegisterAPI(agentRef)
|
|
23
24
|
|
|
24
25
|
const instanceEE = this.ee
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
const globals = ['log', 'error', 'warn', 'info', 'debug', 'trace']
|
|
27
|
+
|
|
28
|
+
globals.forEach((method) => {
|
|
29
|
+
isNative(globalScope.console[method])
|
|
30
|
+
wrapLogger(instanceEE, globalScope.console, method, { level: method === 'log' ? 'info' : method })
|
|
31
|
+
})
|
|
32
|
+
|
|
31
33
|
/** emitted by wrap-logger function */
|
|
32
34
|
this.ee.on('wrap-logger-end', function handleLog ([message]) {
|
|
33
35
|
const { level, customAttributes } = this
|
|
@@ -275,6 +275,21 @@ export class Aggregate extends AggregateBase {
|
|
|
275
275
|
return this.timeKeeper.correctAbsoluteTimestamp(node.timestamp)
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* returns the timestamps for the earliest and latest nodes in the provided array, even if out of order
|
|
280
|
+
* @param {Object[]} [nodes] - the nodes to evaluate
|
|
281
|
+
* @returns {{ firstEvent: Object|undefined, lastEvent: Object|undefined }} - the earliest and latest nodes. Defaults to undefined if no nodes are provided or if no timestamps are found in the nodes.
|
|
282
|
+
*/
|
|
283
|
+
getFirstAndLastNodes (nodes = []) {
|
|
284
|
+
const output = { firstEvent: nodes[0], lastEvent: nodes[nodes.length - 1] }
|
|
285
|
+
nodes.forEach(node => {
|
|
286
|
+
const timestamp = node?.timestamp
|
|
287
|
+
if (!output.firstEvent?.timestamp || (timestamp || Infinity) < output.firstEvent.timestamp) output.firstEvent = node
|
|
288
|
+
if (!output.lastEvent?.timestamp || (timestamp || -Infinity) > output.lastEvent.timestamp) output.lastEvent = node
|
|
289
|
+
})
|
|
290
|
+
return output
|
|
291
|
+
}
|
|
292
|
+
|
|
278
293
|
getHarvestContents (recorderEvents) {
|
|
279
294
|
recorderEvents ??= this.recorder.getEvents()
|
|
280
295
|
let events = recorderEvents.events
|
|
@@ -301,11 +316,10 @@ export class Aggregate extends AggregateBase {
|
|
|
301
316
|
|
|
302
317
|
const relativeNow = now()
|
|
303
318
|
|
|
304
|
-
const
|
|
305
|
-
const lastEventTimestamp = this.getCorrectedTimestamp(events[events.length - 1]) // from rrweb node
|
|
319
|
+
const { firstEvent, lastEvent } = this.getFirstAndLastNodes(events)
|
|
306
320
|
// from rrweb node || from when the harvest cycle started
|
|
307
|
-
const firstTimestamp =
|
|
308
|
-
const lastTimestamp =
|
|
321
|
+
const firstTimestamp = this.getCorrectedTimestamp(firstEvent) || Math.floor(this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp))
|
|
322
|
+
const lastTimestamp = this.getCorrectedTimestamp(lastEvent) || Math.floor(this.timeKeeper.correctRelativeTimestamp(relativeNow))
|
|
309
323
|
|
|
310
324
|
const agentMetadata = agentRuntime.appMetadata?.agents?.[0] || {}
|
|
311
325
|
|