@newrelic/browser-agent 1.309.0-rc.1 → 1.309.0-rc.2
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/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/util/browser-stack-matchers.js +15 -0
- package/dist/cjs/common/util/script-tracker.js +81 -0
- package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.js +6 -10
- package/dist/cjs/interfaces/registered-entity.js +1 -0
- package/dist/cjs/loaders/api/register-api-types.js +6 -0
- package/dist/cjs/loaders/api/register.js +36 -2
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/util/browser-stack-matchers.js +9 -0
- package/dist/esm/common/util/script-tracker.js +76 -0
- package/dist/esm/features/jserrors/aggregate/compute-stack-trace.js +2 -6
- package/dist/esm/interfaces/registered-entity.js +1 -0
- package/dist/esm/loaders/api/register-api-types.js +6 -0
- package/dist/esm/loaders/api/register.js +36 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/util/browser-stack-matchers.d.ts +10 -0
- package/dist/types/common/util/browser-stack-matchers.d.ts.map +1 -0
- package/dist/types/common/util/script-tracker.d.ts +10 -0
- package/dist/types/common/util/script-tracker.d.ts.map +1 -0
- package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts.map +1 -1
- package/dist/types/interfaces/registered-entity.d.ts.map +1 -1
- package/dist/types/loaders/api/register-api-types.d.ts +10 -0
- package/dist/types/loaders/api/register-api-types.d.ts.map +1 -1
- package/dist/types/loaders/api/register.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/common/util/browser-stack-matchers.js +9 -0
- package/src/common/util/script-tracker.js +77 -0
- package/src/features/jserrors/aggregate/compute-stack-trace.js +2 -7
- package/src/interfaces/registered-entity.js +1 -0
- package/src/loaders/api/register-api-types.js +6 -0
- package/src/loaders/api/register.js +33 -2
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.309.0-rc.
|
|
20
|
+
const VERSION = exports.VERSION = "1.309.0-rc.2";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
|
|
|
17
17
|
/**
|
|
18
18
|
* Exposes the version of the agent
|
|
19
19
|
*/
|
|
20
|
-
const VERSION = exports.VERSION = "1.309.0-rc.
|
|
20
|
+
const VERSION = exports.VERSION = "1.309.0-rc.2";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes the build type of the agent
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ieEval = exports.gecko = exports.classNameRegex = exports.chromeEval = exports.chrome = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
9
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
10
|
+
*/
|
|
11
|
+
const classNameRegex = exports.classNameRegex = /function (.+?)\s*\(/;
|
|
12
|
+
const chromeEval = exports.chromeEval = /^\s*at .+ \(eval at \S+ \((?:(?:file|http|https):[^)]+)?\)(?:, [^:]*:\d+:\d+)?\)$/i;
|
|
13
|
+
const ieEval = exports.ieEval = /^\s*at Function code \(Function code:\d+:\d+\)\s*/i;
|
|
14
|
+
const chrome = exports.chrome = /^\s*at (?:((?:\[object object\])?(?:[^(]*\([^)]*\))*[^()]*(?: \[as \S+\])?) )?\(?((?:file|http|https|chrome-extension):.*?)?:(\d+)(?::(\d+))?\)?\s*$/i;
|
|
15
|
+
const gecko = exports.gecko = /^\s*(?:([^@]*)(?:\(.*?\))?@)?((?:file|http|https|chrome|safari-extension).*?):(\d+)(?::(\d+))?\s*$/i;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.findScriptTimings = findScriptTimings;
|
|
7
|
+
var _runtime = require("../constants/runtime");
|
|
8
|
+
var _cleanUrl = require("../url/clean-url");
|
|
9
|
+
var _browserStackMatchers = require("./browser-stack-matchers");
|
|
10
|
+
/**
|
|
11
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
12
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Extracts URLs from stack traces using the same logic as compute-stack-trace.js
|
|
17
|
+
* @param {string} stack The error stack trace
|
|
18
|
+
* @returns {string[]} Array of cleaned URLs found in the stack trace
|
|
19
|
+
*/
|
|
20
|
+
function extractUrlsFromStack(stack) {
|
|
21
|
+
if (!stack || typeof stack !== 'string') return [];
|
|
22
|
+
const urls = new Set();
|
|
23
|
+
const lines = stack.split('\n');
|
|
24
|
+
for (const line of lines) {
|
|
25
|
+
// Try gecko format first, then chrome
|
|
26
|
+
const parts = line.match(_browserStackMatchers.gecko) || line.match(_browserStackMatchers.chrome);
|
|
27
|
+
if (parts && parts[2]) {
|
|
28
|
+
urls.add((0, _cleanUrl.cleanURL)(parts[2]));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return [...urls];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns a deep stack trace by temporarily increasing the stack trace limit.
|
|
36
|
+
* @returns {Error.stack | undefined}
|
|
37
|
+
*/
|
|
38
|
+
function getDeepStackTrace() {
|
|
39
|
+
let stack;
|
|
40
|
+
try {
|
|
41
|
+
const originalStackLimit = Error.stackTraceLimit;
|
|
42
|
+
Error.stackTraceLimit = 50;
|
|
43
|
+
stack = new Error().stack;
|
|
44
|
+
Error.stackTraceLimit = originalStackLimit;
|
|
45
|
+
} catch (e) {
|
|
46
|
+
stack = new Error().stack;
|
|
47
|
+
}
|
|
48
|
+
return stack;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Uses the stack of the initiator function, returns script timing information if a script can be found with the resource timing API matching the URL found in the stack.
|
|
53
|
+
* @returns {{fetchStart: number, fetchEnd: number, asset: string|undefined}} Object containing script fetch start and end times, and the asset URL if found
|
|
54
|
+
*/
|
|
55
|
+
function findScriptTimings() {
|
|
56
|
+
const stack = getDeepStackTrace();
|
|
57
|
+
const timings = {
|
|
58
|
+
fetchStart: 0,
|
|
59
|
+
fetchEnd: 0,
|
|
60
|
+
asset: undefined
|
|
61
|
+
};
|
|
62
|
+
const scripts = _runtime.globalScope.performance?.getEntriesByType('resource').filter(entry => entry.initiatorType === 'script') || [];
|
|
63
|
+
if (scripts.length < 1 || !stack) return timings;
|
|
64
|
+
try {
|
|
65
|
+
const mfeScriptUrl = extractUrlsFromStack(stack).at(-1); // array of URLs from the stack of the register API caller, the MFE script should be at the bottom
|
|
66
|
+
if (!mfeScriptUrl) return timings;
|
|
67
|
+
const match = scripts.find(script => {
|
|
68
|
+
const scriptUrl = (0, _cleanUrl.cleanURL)(script.name);
|
|
69
|
+
// Try exact match, then partial matches for different URL formats
|
|
70
|
+
return mfeScriptUrl === scriptUrl || mfeScriptUrl.endsWith(scriptUrl) || scriptUrl.endsWith(mfeScriptUrl);
|
|
71
|
+
});
|
|
72
|
+
if (match) {
|
|
73
|
+
timings.fetchStart = Math.floor(match.startTime);
|
|
74
|
+
timings.fetchEnd = Math.floor(match.responseEnd);
|
|
75
|
+
timings.asset = match.name;
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
// Don't let stack parsing errors break anything
|
|
79
|
+
}
|
|
80
|
+
return timings;
|
|
81
|
+
}
|
|
@@ -6,8 +6,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.computeStackTrace = computeStackTrace;
|
|
7
7
|
var _formatStackTrace = require("./format-stack-trace");
|
|
8
8
|
var _canonicalizeUrl = require("../../../common/url/canonicalize-url");
|
|
9
|
+
var _browserStackMatchers = require("../../../common/util/browser-stack-matchers");
|
|
9
10
|
/**
|
|
10
|
-
* Copyright 2020-
|
|
11
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
11
12
|
* SPDX-License-Identifier: Apache-2.0
|
|
12
13
|
*/
|
|
13
14
|
|
|
@@ -66,11 +67,6 @@ var _canonicalizeUrl = require("../../../common/url/canonicalize-url");
|
|
|
66
67
|
// ex.name = ReferenceError
|
|
67
68
|
|
|
68
69
|
var debug = false;
|
|
69
|
-
var classNameRegex = /function (.+?)\s*\(/;
|
|
70
|
-
var chrome = /^\s*at (?:((?:\[object object\])?(?:[^(]*\([^)]*\))*[^()]*(?: \[as \S+\])?) )?\(?((?:file|http|https|chrome-extension):.*?)?:(\d+)(?::(\d+))?\)?\s*$/i;
|
|
71
|
-
var gecko = /^\s*(?:(\S*|global code)(?:\(.*?\))?@)?((?:file|http|https|chrome|safari-extension).*?):(\d+)(?::(\d+))?\s*$/i;
|
|
72
|
-
var chromeEval = /^\s*at .+ \(eval at \S+ \((?:(?:file|http|https):[^)]+)?\)(?:, [^:]*:\d+:\d+)?\)$/i;
|
|
73
|
-
var ieEval = /^\s*at Function code \(Function code:\d+:\d+\)\s*/i;
|
|
74
70
|
|
|
75
71
|
/**
|
|
76
72
|
* Represents an error with a stack trace.
|
|
@@ -194,8 +190,8 @@ function parseStackProp(info, line) {
|
|
|
194
190
|
* name, line number, and column number (if available).
|
|
195
191
|
*/
|
|
196
192
|
function getStackElement(line) {
|
|
197
|
-
var parts = line.match(gecko);
|
|
198
|
-
if (!parts) parts = line.match(chrome);
|
|
193
|
+
var parts = line.match(_browserStackMatchers.gecko);
|
|
194
|
+
if (!parts) parts = line.match(_browserStackMatchers.chrome);
|
|
199
195
|
if (parts) {
|
|
200
196
|
return {
|
|
201
197
|
url: parts[2],
|
|
@@ -204,7 +200,7 @@ function getStackElement(line) {
|
|
|
204
200
|
column: parts[4] ? +parts[4] : null
|
|
205
201
|
};
|
|
206
202
|
}
|
|
207
|
-
if (line.match(chromeEval) || line.match(ieEval) || line === 'anonymous') {
|
|
203
|
+
if (line.match(_browserStackMatchers.chromeEval) || line.match(_browserStackMatchers.ieEval) || line === 'anonymous') {
|
|
208
204
|
return {
|
|
209
205
|
func: 'evaluated code'
|
|
210
206
|
};
|
|
@@ -283,7 +279,7 @@ function computeStackTraceWithMessageOnly(ex) {
|
|
|
283
279
|
* @returns {string} The name of the constructor function, or 'unknown' if the name cannot be determined.
|
|
284
280
|
*/
|
|
285
281
|
function getClassName(obj) {
|
|
286
|
-
var results = classNameRegex.exec(String(obj.constructor));
|
|
282
|
+
var results = _browserStackMatchers.classNameRegex.exec(String(obj.constructor));
|
|
287
283
|
return results && results.length > 1 ? results[1] : 'unknown';
|
|
288
284
|
}
|
|
289
285
|
|
|
@@ -33,6 +33,12 @@ exports.default = void 0;
|
|
|
33
33
|
/**
|
|
34
34
|
* @typedef {Object} RegisterAPIMetadata
|
|
35
35
|
* @property {Object} customAttributes - The custom attributes for the registered entity.
|
|
36
|
+
* @property {Object} timings - The timing metrics for the registered entity.
|
|
37
|
+
* @property {number} timings.registeredAt - The timestamp when the registered entity was created.
|
|
38
|
+
* @property {number} [timings.reportedAt] - The timestamp when the registered entity was deregistered.
|
|
39
|
+
* @property {number} timings.fetchStart - The timestamp when the registered entity began fetching.
|
|
40
|
+
* @property {number} timings.fetchEnd - The timestamp when the registered entity finished fetching.
|
|
41
|
+
* @property {Object} [timings.asset] - The asset path (if found) for the registered entity.
|
|
36
42
|
* @property {Object} target - The options for the registered entity.
|
|
37
43
|
* @property {string} [target.licenseKey] - The license key for the registered entity. If none was supplied, it will assume the license key from the main agent.
|
|
38
44
|
* @property {string} target.id - The ID for the registered entity.
|
|
@@ -18,6 +18,8 @@ var _noticeError = require("./noticeError");
|
|
|
18
18
|
var _invoke = require("../../common/util/invoke");
|
|
19
19
|
var _measure = require("./measure");
|
|
20
20
|
var _recordCustomEvent = require("./recordCustomEvent");
|
|
21
|
+
var _pageVisibility = require("../../common/window/page-visibility");
|
|
22
|
+
var _scriptTracker = require("../../common/util/script-tracker");
|
|
21
23
|
/**
|
|
22
24
|
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
23
25
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -56,6 +58,11 @@ function register(agentRef, target, parent) {
|
|
|
56
58
|
target.blocked = false;
|
|
57
59
|
target.parent = parent || {};
|
|
58
60
|
if (typeof target.tags !== 'object' || target.tags === null || Array.isArray(target.tags)) target.tags = {};
|
|
61
|
+
const timings = {
|
|
62
|
+
registeredAt: (0, _now.now)(),
|
|
63
|
+
reportedAt: undefined,
|
|
64
|
+
...(0, _scriptTracker.findScriptTimings)()
|
|
65
|
+
};
|
|
59
66
|
const attrs = {};
|
|
60
67
|
|
|
61
68
|
// Process tags object and add to attrs, excluding protected keys
|
|
@@ -106,6 +113,7 @@ function register(agentRef, target, parent) {
|
|
|
106
113
|
}, agentRef], target),
|
|
107
114
|
deregister: () => {
|
|
108
115
|
/** note: blocking this instance will disable access for all entities sharing the instance, and will invalidate it from the v2 checks */
|
|
116
|
+
reportTimings();
|
|
109
117
|
block((0, _invoke.single)(() => (0, _console.warn)(68)));
|
|
110
118
|
},
|
|
111
119
|
log: (message, options = {}) => report(_log.log, [message, {
|
|
@@ -137,7 +145,8 @@ function register(agentRef, target, parent) {
|
|
|
137
145
|
/** metadata */
|
|
138
146
|
metadata: {
|
|
139
147
|
customAttributes: attrs,
|
|
140
|
-
target
|
|
148
|
+
target,
|
|
149
|
+
timings
|
|
141
150
|
}
|
|
142
151
|
};
|
|
143
152
|
|
|
@@ -151,7 +160,32 @@ function register(agentRef, target, parent) {
|
|
|
151
160
|
};
|
|
152
161
|
|
|
153
162
|
/** only allow registered APIs to be tracked in the agent runtime */
|
|
154
|
-
if (!isBlocked())
|
|
163
|
+
if (!isBlocked()) {
|
|
164
|
+
registeredEntities.push(api);
|
|
165
|
+
(0, _pageVisibility.subscribeToPageUnload)(reportTimings);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Reports the gathered timings for the registered entity through a custom event to the container agent. Only reports once
|
|
170
|
+
* by checking for the presence of the reportedAt timing.
|
|
171
|
+
* @returns {void}
|
|
172
|
+
*/
|
|
173
|
+
function reportTimings() {
|
|
174
|
+
// only ever report the timings the first time this is called
|
|
175
|
+
if (timings.reportedAt) return;
|
|
176
|
+
timings.reportedAt = (0, _now.now)();
|
|
177
|
+
api.recordCustomEvent('MicroFrontEndTiming', {
|
|
178
|
+
timeToLoad: timings.registeredAt - timings.fetchStart,
|
|
179
|
+
// fetchStart to registeredAt
|
|
180
|
+
timeToBeRequested: timings.fetchStart,
|
|
181
|
+
// origin to fetchStart
|
|
182
|
+
timeToFetch: timings.fetchEnd - timings.fetchStart,
|
|
183
|
+
// fetchStart to fetchEnd
|
|
184
|
+
timeToRegister: timings.registeredAt - timings.fetchEnd,
|
|
185
|
+
// fetchEnd to registeredAt
|
|
186
|
+
timeAlive: timings.reportedAt - timings.registeredAt // registeredAt to reportedAt
|
|
187
|
+
});
|
|
188
|
+
}
|
|
155
189
|
|
|
156
190
|
/**
|
|
157
191
|
* Sets a value local to the registered API attrs. Will do nothing if APIs are deregistered.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
export const classNameRegex = /function (.+?)\s*\(/;
|
|
6
|
+
export const chromeEval = /^\s*at .+ \(eval at \S+ \((?:(?:file|http|https):[^)]+)?\)(?:, [^:]*:\d+:\d+)?\)$/i;
|
|
7
|
+
export const ieEval = /^\s*at Function code \(Function code:\d+:\d+\)\s*/i;
|
|
8
|
+
export const chrome = /^\s*at (?:((?:\[object object\])?(?:[^(]*\([^)]*\))*[^()]*(?: \[as \S+\])?) )?\(?((?:file|http|https|chrome-extension):.*?)?:(\d+)(?::(\d+))?\)?\s*$/i;
|
|
9
|
+
export const gecko = /^\s*(?:([^@]*)(?:\(.*?\))?@)?((?:file|http|https|chrome|safari-extension).*?):(\d+)(?::(\d+))?\s*$/i;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { globalScope } from '../constants/runtime';
|
|
7
|
+
import { cleanURL } from '../url/clean-url';
|
|
8
|
+
import { chrome, gecko } from './browser-stack-matchers';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extracts URLs from stack traces using the same logic as compute-stack-trace.js
|
|
12
|
+
* @param {string} stack The error stack trace
|
|
13
|
+
* @returns {string[]} Array of cleaned URLs found in the stack trace
|
|
14
|
+
*/
|
|
15
|
+
function extractUrlsFromStack(stack) {
|
|
16
|
+
if (!stack || typeof stack !== 'string') return [];
|
|
17
|
+
const urls = new Set();
|
|
18
|
+
const lines = stack.split('\n');
|
|
19
|
+
for (const line of lines) {
|
|
20
|
+
// Try gecko format first, then chrome
|
|
21
|
+
const parts = line.match(gecko) || line.match(chrome);
|
|
22
|
+
if (parts && parts[2]) {
|
|
23
|
+
urls.add(cleanURL(parts[2]));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return [...urls];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns a deep stack trace by temporarily increasing the stack trace limit.
|
|
31
|
+
* @returns {Error.stack | undefined}
|
|
32
|
+
*/
|
|
33
|
+
function getDeepStackTrace() {
|
|
34
|
+
let stack;
|
|
35
|
+
try {
|
|
36
|
+
const originalStackLimit = Error.stackTraceLimit;
|
|
37
|
+
Error.stackTraceLimit = 50;
|
|
38
|
+
stack = new Error().stack;
|
|
39
|
+
Error.stackTraceLimit = originalStackLimit;
|
|
40
|
+
} catch (e) {
|
|
41
|
+
stack = new Error().stack;
|
|
42
|
+
}
|
|
43
|
+
return stack;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Uses the stack of the initiator function, returns script timing information if a script can be found with the resource timing API matching the URL found in the stack.
|
|
48
|
+
* @returns {{fetchStart: number, fetchEnd: number, asset: string|undefined}} Object containing script fetch start and end times, and the asset URL if found
|
|
49
|
+
*/
|
|
50
|
+
export function findScriptTimings() {
|
|
51
|
+
const stack = getDeepStackTrace();
|
|
52
|
+
const timings = {
|
|
53
|
+
fetchStart: 0,
|
|
54
|
+
fetchEnd: 0,
|
|
55
|
+
asset: undefined
|
|
56
|
+
};
|
|
57
|
+
const scripts = globalScope.performance?.getEntriesByType('resource').filter(entry => entry.initiatorType === 'script') || [];
|
|
58
|
+
if (scripts.length < 1 || !stack) return timings;
|
|
59
|
+
try {
|
|
60
|
+
const mfeScriptUrl = extractUrlsFromStack(stack).at(-1); // array of URLs from the stack of the register API caller, the MFE script should be at the bottom
|
|
61
|
+
if (!mfeScriptUrl) return timings;
|
|
62
|
+
const match = scripts.find(script => {
|
|
63
|
+
const scriptUrl = cleanURL(script.name);
|
|
64
|
+
// Try exact match, then partial matches for different URL formats
|
|
65
|
+
return mfeScriptUrl === scriptUrl || mfeScriptUrl.endsWith(scriptUrl) || scriptUrl.endsWith(mfeScriptUrl);
|
|
66
|
+
});
|
|
67
|
+
if (match) {
|
|
68
|
+
timings.fetchStart = Math.floor(match.startTime);
|
|
69
|
+
timings.fetchEnd = Math.floor(match.responseEnd);
|
|
70
|
+
timings.asset = match.name;
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
// Don't let stack parsing errors break anything
|
|
74
|
+
}
|
|
75
|
+
return timings;
|
|
76
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -58,12 +58,8 @@
|
|
|
58
58
|
// ex.name = ReferenceError
|
|
59
59
|
import { formatStackTrace } from './format-stack-trace';
|
|
60
60
|
import { canonicalizeUrl } from '../../../common/url/canonicalize-url';
|
|
61
|
+
import { chrome, chromeEval, classNameRegex, gecko, ieEval } from '../../../common/util/browser-stack-matchers';
|
|
61
62
|
var debug = false;
|
|
62
|
-
var classNameRegex = /function (.+?)\s*\(/;
|
|
63
|
-
var chrome = /^\s*at (?:((?:\[object object\])?(?:[^(]*\([^)]*\))*[^()]*(?: \[as \S+\])?) )?\(?((?:file|http|https|chrome-extension):.*?)?:(\d+)(?::(\d+))?\)?\s*$/i;
|
|
64
|
-
var gecko = /^\s*(?:(\S*|global code)(?:\(.*?\))?@)?((?:file|http|https|chrome|safari-extension).*?):(\d+)(?::(\d+))?\s*$/i;
|
|
65
|
-
var chromeEval = /^\s*at .+ \(eval at \S+ \((?:(?:file|http|https):[^)]+)?\)(?:, [^:]*:\d+:\d+)?\)$/i;
|
|
66
|
-
var ieEval = /^\s*at Function code \(Function code:\d+:\d+\)\s*/i;
|
|
67
63
|
|
|
68
64
|
/**
|
|
69
65
|
* Represents an error with a stack trace.
|
|
@@ -30,6 +30,12 @@
|
|
|
30
30
|
/**
|
|
31
31
|
* @typedef {Object} RegisterAPIMetadata
|
|
32
32
|
* @property {Object} customAttributes - The custom attributes for the registered entity.
|
|
33
|
+
* @property {Object} timings - The timing metrics for the registered entity.
|
|
34
|
+
* @property {number} timings.registeredAt - The timestamp when the registered entity was created.
|
|
35
|
+
* @property {number} [timings.reportedAt] - The timestamp when the registered entity was deregistered.
|
|
36
|
+
* @property {number} timings.fetchStart - The timestamp when the registered entity began fetching.
|
|
37
|
+
* @property {number} timings.fetchEnd - The timestamp when the registered entity finished fetching.
|
|
38
|
+
* @property {Object} [timings.asset] - The asset path (if found) for the registered entity.
|
|
33
39
|
* @property {Object} target - The options for the registered entity.
|
|
34
40
|
* @property {string} [target.licenseKey] - The license key for the registered entity. If none was supplied, it will assume the license key from the main agent.
|
|
35
41
|
* @property {string} target.id - The ID for the registered entity.
|
|
@@ -16,6 +16,8 @@ import { noticeError } from './noticeError';
|
|
|
16
16
|
import { single } from '../../common/util/invoke';
|
|
17
17
|
import { measure } from './measure';
|
|
18
18
|
import { recordCustomEvent } from './recordCustomEvent';
|
|
19
|
+
import { subscribeToPageUnload } from '../../common/window/page-visibility';
|
|
20
|
+
import { findScriptTimings } from '../../common/util/script-tracker';
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* @typedef {import('./register-api-types').RegisterAPI} RegisterAPI
|
|
@@ -50,6 +52,11 @@ function register(agentRef, target, parent) {
|
|
|
50
52
|
target.blocked = false;
|
|
51
53
|
target.parent = parent || {};
|
|
52
54
|
if (typeof target.tags !== 'object' || target.tags === null || Array.isArray(target.tags)) target.tags = {};
|
|
55
|
+
const timings = {
|
|
56
|
+
registeredAt: now(),
|
|
57
|
+
reportedAt: undefined,
|
|
58
|
+
...findScriptTimings()
|
|
59
|
+
};
|
|
53
60
|
const attrs = {};
|
|
54
61
|
|
|
55
62
|
// Process tags object and add to attrs, excluding protected keys
|
|
@@ -100,6 +107,7 @@ function register(agentRef, target, parent) {
|
|
|
100
107
|
}, agentRef], target),
|
|
101
108
|
deregister: () => {
|
|
102
109
|
/** note: blocking this instance will disable access for all entities sharing the instance, and will invalidate it from the v2 checks */
|
|
110
|
+
reportTimings();
|
|
103
111
|
block(single(() => warn(68)));
|
|
104
112
|
},
|
|
105
113
|
log: (message, options = {}) => report(log, [message, {
|
|
@@ -131,7 +139,8 @@ function register(agentRef, target, parent) {
|
|
|
131
139
|
/** metadata */
|
|
132
140
|
metadata: {
|
|
133
141
|
customAttributes: attrs,
|
|
134
|
-
target
|
|
142
|
+
target,
|
|
143
|
+
timings
|
|
135
144
|
}
|
|
136
145
|
};
|
|
137
146
|
|
|
@@ -145,7 +154,32 @@ function register(agentRef, target, parent) {
|
|
|
145
154
|
};
|
|
146
155
|
|
|
147
156
|
/** only allow registered APIs to be tracked in the agent runtime */
|
|
148
|
-
if (!isBlocked())
|
|
157
|
+
if (!isBlocked()) {
|
|
158
|
+
registeredEntities.push(api);
|
|
159
|
+
subscribeToPageUnload(reportTimings);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Reports the gathered timings for the registered entity through a custom event to the container agent. Only reports once
|
|
164
|
+
* by checking for the presence of the reportedAt timing.
|
|
165
|
+
* @returns {void}
|
|
166
|
+
*/
|
|
167
|
+
function reportTimings() {
|
|
168
|
+
// only ever report the timings the first time this is called
|
|
169
|
+
if (timings.reportedAt) return;
|
|
170
|
+
timings.reportedAt = now();
|
|
171
|
+
api.recordCustomEvent('MicroFrontEndTiming', {
|
|
172
|
+
timeToLoad: timings.registeredAt - timings.fetchStart,
|
|
173
|
+
// fetchStart to registeredAt
|
|
174
|
+
timeToBeRequested: timings.fetchStart,
|
|
175
|
+
// origin to fetchStart
|
|
176
|
+
timeToFetch: timings.fetchEnd - timings.fetchStart,
|
|
177
|
+
// fetchStart to fetchEnd
|
|
178
|
+
timeToRegister: timings.registeredAt - timings.fetchEnd,
|
|
179
|
+
// fetchEnd to registeredAt
|
|
180
|
+
timeAlive: timings.reportedAt - timings.registeredAt // registeredAt to reportedAt
|
|
181
|
+
});
|
|
182
|
+
}
|
|
149
183
|
|
|
150
184
|
/**
|
|
151
185
|
* Sets a value local to the registered API attrs. Will do nothing if APIs are deregistered.
|
|
@@ -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/extract-url.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/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/util/v2.js","../src/common/util/webdriver-detection.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/load-time.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/harvest-metadata.js","../src/features/metrics/aggregate/index.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/aggregate/trace/utils.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/event-buffer.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/consent.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.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.9.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/extract-url.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/browser-stack-matchers.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/script-tracker.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/util/v2.js","../src/common/util/webdriver-detection.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/load-time.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/harvest-metadata.js","../src/features/metrics/aggregate/index.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/aggregate/trace/utils.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/event-buffer.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/consent.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.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.9.3"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
export const classNameRegex: RegExp;
|
|
6
|
+
export const chromeEval: RegExp;
|
|
7
|
+
export const ieEval: RegExp;
|
|
8
|
+
export const chrome: RegExp;
|
|
9
|
+
export const gecko: RegExp;
|
|
10
|
+
//# sourceMappingURL=browser-stack-matchers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-stack-matchers.d.ts","sourceRoot":"","sources":["../../../../src/common/util/browser-stack-matchers.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH,oCAAmD;AACnD,gCAA8G;AAC9G,4BAA0E;AAC1E,4BAA6K;AAC7K,2BAA0H"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uses the stack of the initiator function, returns script timing information if a script can be found with the resource timing API matching the URL found in the stack.
|
|
3
|
+
* @returns {{fetchStart: number, fetchEnd: number, asset: string|undefined}} Object containing script fetch start and end times, and the asset URL if found
|
|
4
|
+
*/
|
|
5
|
+
export function findScriptTimings(): {
|
|
6
|
+
fetchStart: number;
|
|
7
|
+
fetchEnd: number;
|
|
8
|
+
asset: string | undefined;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=script-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script-tracker.d.ts","sourceRoot":"","sources":["../../../../src/common/util/script-tracker.js"],"names":[],"mappings":"AA+CA;;;GAGG;AACH,qCAFa;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAC,SAAS,CAAA;CAAC,CA2B3E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compute-stack-trace.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/compute-stack-trace.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compute-stack-trace.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/compute-stack-trace.js"],"names":[],"mappings":"AAgEA;;;;;;;;;;GAUG;AAEH;;;;GAIG;AACH,sCAHW,KAAK,GACH,SAAS,CA2CrB;;;;;;;;UAvDa,MAAM;;;;aACN,MAAM;;;;iBACN,MAAM;;;;YACN,KAAK,CAAC,MAAM,CAAC;;;;SACb,MAAM;;;;UACN,MAAM;;;;UACN,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registered-entity.d.ts","sourceRoot":"","sources":["../../../src/interfaces/registered-entity.js"],"names":[],"mappings":"AAMA;;;;GAIG;AAEH;;;;;;GAMG;AACH;
|
|
1
|
+
{"version":3,"file":"registered-entity.d.ts","sourceRoot":"","sources":["../../../src/interfaces/registered-entity.js"],"names":[],"mappings":"AAMA;;;;GAIG;AAEH;;;;;;GAMG;AACH;IAQE;;;OAGG;IACH,kBAFW,sBAAsB,EAShC;IAlBD,kCAAkC;IAClC,UADW,mBAAmB,CAK7B;IAeD;;;;;OAKG;IACH,oBAHW,MAAM,eACN,MAAM,QAKhB;IAED;;;;;;;;OAQG;IACH,iBAHW,OAAO,mCAAmC,EAAE,sBAAsB,GACjE,OAAO,mCAAmC,EAAE,WAAW,CAIlE;IAED;;;;;;;OAOG;IACH,cAFa,IAAI,CAIhB;IAED;;;;;SAKK;IACL,6BAHa,MAAM,eACN,MAAM,QAIlB;IAED;;;;;;OAMG;IACH,cAJW,MAAM,YACN;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAC,GACtE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAC,CAIpF;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,OAAO,GAAC,IAAI,YAC1B,OAAO,QAKjB;IAED;;;;;OAKG;IACH,mBAHW,KAAK,GAAC,MAAM,qBACZ,MAAM,QAKhB;IAED;;;;;OAKG;IACH,iBAHW,MAAM,GAAC,IAAI,iBACX,OAAO,QAKjB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,IAAI,QAOrB;IAED;;;;;MAKE;IACF,aAHW,MAAM,YACN;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,MAAM,GAAC,MAAM,CAAA;KAAC,QAKpF;CACF;0BAnJY,OAAO,mCAAmC,EAAE,WAAW;kCACvD,OAAO,mCAAmC,EAAE,mBAAmB;qCAC/D,OAAO,mCAAmC,EAAE,sBAAsB"}
|
|
@@ -88,6 +88,16 @@ export type RegisterAPIMetadata = {
|
|
|
88
88
|
* - The custom attributes for the registered entity.
|
|
89
89
|
*/
|
|
90
90
|
customAttributes: Object;
|
|
91
|
+
/**
|
|
92
|
+
* - The timing metrics for the registered entity.
|
|
93
|
+
*/
|
|
94
|
+
timings: {
|
|
95
|
+
registeredAt: number;
|
|
96
|
+
reportedAt?: number | undefined;
|
|
97
|
+
fetchStart: number;
|
|
98
|
+
fetchEnd: number;
|
|
99
|
+
asset?: Object | undefined;
|
|
100
|
+
};
|
|
91
101
|
/**
|
|
92
102
|
* - The options for the registered entity.
|
|
93
103
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-api-types.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/register-api-types.js"],"names":[],"mappings":";;;;;;mBAOc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI;;;;SAC3C,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;KAAC,KAAK,IAAI;;;;iBACxH,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,KAAK,IAAI;;;;cAC1D,CAAC,MAAM,EAAE,sBAAsB,KAAK,WAAW;;;;gBAC/C,MAAM,IAAI;;;;uBACV,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI;;;;aAChD,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAC,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAC,CAAC;;;;2BACrL,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI;;;;wBAC9B,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI;;;;eAClF,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,IAAI;;;;cACtD,mBAAmB;;;;;;QAKnB,MAAM,GAAC,MAAM;;;;UACb,MAAM;;;;;;;;;;;;;;;;;;;;sBAQN,MAAM;;;;
|
|
1
|
+
{"version":3,"file":"register-api-types.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/register-api-types.js"],"names":[],"mappings":";;;;;;mBAOc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI;;;;SAC3C,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;KAAC,KAAK,IAAI;;;;iBACxH,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,KAAK,IAAI;;;;cAC1D,CAAC,MAAM,EAAE,sBAAsB,KAAK,WAAW;;;;gBAC/C,MAAM,IAAI;;;;uBACV,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI;;;;aAChD,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAC,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAC,CAAC;;;;2BACrL,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI;;;;wBAC9B,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI;;;;eAClF,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,IAAI;;;;cACtD,mBAAmB;;;;;;QAKnB,MAAM,GAAC,MAAM;;;;UACb,MAAM;;;;;;;;;;;;;;;;;;;;sBAQN,MAAM;;;;aAEjB;QAA2B,YAAY,EAA5B,MAAM;QACW,UAAU;QACX,UAAU,EAA1B,MAAM;QACU,QAAQ,EAAxB,MAAM;QACW,KAAK;KACjC;;;;YACA;QAA2B,UAAU;QACX,EAAE,EAAjB,MAAM;QACS,IAAI,EAAnB,MAAM;QACwB,IAAI;;;QAClB,QAAQ;QACP,QAAQ;KACtC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/register.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/loaders/api/register.js"],"names":[],"mappings":"AA2BA;;;;GAIG;AACH,mDAIC;0BAdY,OAAO,sBAAsB,EAAE,WAAW"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
export const classNameRegex = /function (.+?)\s*\(/
|
|
6
|
+
export const chromeEval = /^\s*at .+ \(eval at \S+ \((?:(?:file|http|https):[^)]+)?\)(?:, [^:]*:\d+:\d+)?\)$/i
|
|
7
|
+
export const ieEval = /^\s*at Function code \(Function code:\d+:\d+\)\s*/i
|
|
8
|
+
export const chrome = /^\s*at (?:((?:\[object object\])?(?:[^(]*\([^)]*\))*[^()]*(?: \[as \S+\])?) )?\(?((?:file|http|https|chrome-extension):.*?)?:(\d+)(?::(\d+))?\)?\s*$/i
|
|
9
|
+
export const gecko = /^\s*(?:([^@]*)(?:\(.*?\))?@)?((?:file|http|https|chrome|safari-extension).*?):(\d+)(?::(\d+))?\s*$/i
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { globalScope } from '../constants/runtime'
|
|
7
|
+
import { cleanURL } from '../url/clean-url'
|
|
8
|
+
import { chrome, gecko } from './browser-stack-matchers'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extracts URLs from stack traces using the same logic as compute-stack-trace.js
|
|
12
|
+
* @param {string} stack The error stack trace
|
|
13
|
+
* @returns {string[]} Array of cleaned URLs found in the stack trace
|
|
14
|
+
*/
|
|
15
|
+
function extractUrlsFromStack (stack) {
|
|
16
|
+
if (!stack || typeof stack !== 'string') return []
|
|
17
|
+
|
|
18
|
+
const urls = new Set()
|
|
19
|
+
const lines = stack.split('\n')
|
|
20
|
+
|
|
21
|
+
for (const line of lines) {
|
|
22
|
+
// Try gecko format first, then chrome
|
|
23
|
+
const parts = line.match(gecko) || line.match(chrome)
|
|
24
|
+
if (parts && parts[2]) {
|
|
25
|
+
urls.add(cleanURL(parts[2]))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return [...urls]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns a deep stack trace by temporarily increasing the stack trace limit.
|
|
33
|
+
* @returns {Error.stack | undefined}
|
|
34
|
+
*/
|
|
35
|
+
function getDeepStackTrace () {
|
|
36
|
+
let stack
|
|
37
|
+
try {
|
|
38
|
+
const originalStackLimit = Error.stackTraceLimit
|
|
39
|
+
Error.stackTraceLimit = 50
|
|
40
|
+
stack = new Error().stack
|
|
41
|
+
Error.stackTraceLimit = originalStackLimit
|
|
42
|
+
} catch (e) {
|
|
43
|
+
stack = new Error().stack
|
|
44
|
+
}
|
|
45
|
+
return stack
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Uses the stack of the initiator function, returns script timing information if a script can be found with the resource timing API matching the URL found in the stack.
|
|
50
|
+
* @returns {{fetchStart: number, fetchEnd: number, asset: string|undefined}} Object containing script fetch start and end times, and the asset URL if found
|
|
51
|
+
*/
|
|
52
|
+
export function findScriptTimings () {
|
|
53
|
+
const stack = getDeepStackTrace()
|
|
54
|
+
const timings = { fetchStart: 0, fetchEnd: 0, asset: undefined }
|
|
55
|
+
const scripts = globalScope.performance?.getEntriesByType('resource').filter(entry => entry.initiatorType === 'script') || []
|
|
56
|
+
if (scripts.length < 1 || !stack) return timings
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const mfeScriptUrl = extractUrlsFromStack(stack).at(-1) // array of URLs from the stack of the register API caller, the MFE script should be at the bottom
|
|
60
|
+
if (!mfeScriptUrl) return timings
|
|
61
|
+
const match = scripts.find(script => {
|
|
62
|
+
const scriptUrl = cleanURL(script.name)
|
|
63
|
+
// Try exact match, then partial matches for different URL formats
|
|
64
|
+
return mfeScriptUrl === scriptUrl || mfeScriptUrl.endsWith(scriptUrl) || scriptUrl.endsWith(mfeScriptUrl)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
if (match) {
|
|
68
|
+
timings.fetchStart = Math.floor(match.startTime)
|
|
69
|
+
timings.fetchEnd = Math.floor(match.responseEnd)
|
|
70
|
+
timings.asset = match.name
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
// Don't let stack parsing errors break anything
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return timings
|
|
77
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -58,15 +58,10 @@
|
|
|
58
58
|
// ex.name = ReferenceError
|
|
59
59
|
import { formatStackTrace } from './format-stack-trace'
|
|
60
60
|
import { canonicalizeUrl } from '../../../common/url/canonicalize-url'
|
|
61
|
+
import { chrome, chromeEval, classNameRegex, gecko, ieEval } from '../../../common/util/browser-stack-matchers'
|
|
61
62
|
|
|
62
63
|
var debug = false
|
|
63
64
|
|
|
64
|
-
var classNameRegex = /function (.+?)\s*\(/
|
|
65
|
-
var chrome = /^\s*at (?:((?:\[object object\])?(?:[^(]*\([^)]*\))*[^()]*(?: \[as \S+\])?) )?\(?((?:file|http|https|chrome-extension):.*?)?:(\d+)(?::(\d+))?\)?\s*$/i
|
|
66
|
-
var gecko = /^\s*(?:(\S*|global code)(?:\(.*?\))?@)?((?:file|http|https|chrome|safari-extension).*?):(\d+)(?::(\d+))?\s*$/i
|
|
67
|
-
var chromeEval = /^\s*at .+ \(eval at \S+ \((?:(?:file|http|https):[^)]+)?\)(?:, [^:]*:\d+:\d+)?\)$/i
|
|
68
|
-
var ieEval = /^\s*at Function code \(Function code:\d+:\d+\)\s*/i
|
|
69
|
-
|
|
70
65
|
/**
|
|
71
66
|
* Represents an error with a stack trace.
|
|
72
67
|
* @typedef {Object} StackInfo
|
|
@@ -30,6 +30,12 @@
|
|
|
30
30
|
/**
|
|
31
31
|
* @typedef {Object} RegisterAPIMetadata
|
|
32
32
|
* @property {Object} customAttributes - The custom attributes for the registered entity.
|
|
33
|
+
* @property {Object} timings - The timing metrics for the registered entity.
|
|
34
|
+
* @property {number} timings.registeredAt - The timestamp when the registered entity was created.
|
|
35
|
+
* @property {number} [timings.reportedAt] - The timestamp when the registered entity was deregistered.
|
|
36
|
+
* @property {number} timings.fetchStart - The timestamp when the registered entity began fetching.
|
|
37
|
+
* @property {number} timings.fetchEnd - The timestamp when the registered entity finished fetching.
|
|
38
|
+
* @property {Object} [timings.asset] - The asset path (if found) for the registered entity.
|
|
33
39
|
* @property {Object} target - The options for the registered entity.
|
|
34
40
|
* @property {string} [target.licenseKey] - The license key for the registered entity. If none was supplied, it will assume the license key from the main agent.
|
|
35
41
|
* @property {string} target.id - The ID for the registered entity.
|
|
@@ -16,6 +16,8 @@ import { noticeError } from './noticeError'
|
|
|
16
16
|
import { single } from '../../common/util/invoke'
|
|
17
17
|
import { measure } from './measure'
|
|
18
18
|
import { recordCustomEvent } from './recordCustomEvent'
|
|
19
|
+
import { subscribeToPageUnload } from '../../common/window/page-visibility'
|
|
20
|
+
import { findScriptTimings } from '../../common/util/script-tracker'
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* @typedef {import('./register-api-types').RegisterAPI} RegisterAPI
|
|
@@ -52,6 +54,12 @@ function register (agentRef, target, parent) {
|
|
|
52
54
|
target.parent = parent || {}
|
|
53
55
|
if (typeof target.tags !== 'object' || target.tags === null || Array.isArray(target.tags)) target.tags = {}
|
|
54
56
|
|
|
57
|
+
const timings = {
|
|
58
|
+
registeredAt: now(),
|
|
59
|
+
reportedAt: undefined,
|
|
60
|
+
...findScriptTimings()
|
|
61
|
+
}
|
|
62
|
+
|
|
55
63
|
const attrs = {}
|
|
56
64
|
|
|
57
65
|
// Process tags object and add to attrs, excluding protected keys
|
|
@@ -96,6 +104,7 @@ function register (agentRef, target, parent) {
|
|
|
96
104
|
addPageAction: (name, attributes = {}) => report(addPageAction, [name, { ...attrs, ...attributes }, agentRef], target),
|
|
97
105
|
deregister: () => {
|
|
98
106
|
/** note: blocking this instance will disable access for all entities sharing the instance, and will invalidate it from the v2 checks */
|
|
107
|
+
reportTimings()
|
|
99
108
|
block(single(() => warn(68)))
|
|
100
109
|
},
|
|
101
110
|
log: (message, options = {}) => report(log, [message, { ...options, customAttributes: { ...attrs, ...(options.customAttributes || {}) } }, agentRef], target),
|
|
@@ -109,7 +118,8 @@ function register (agentRef, target, parent) {
|
|
|
109
118
|
/** metadata */
|
|
110
119
|
metadata: {
|
|
111
120
|
customAttributes: attrs,
|
|
112
|
-
target
|
|
121
|
+
target,
|
|
122
|
+
timings
|
|
113
123
|
}
|
|
114
124
|
}
|
|
115
125
|
|
|
@@ -123,7 +133,28 @@ function register (agentRef, target, parent) {
|
|
|
123
133
|
}
|
|
124
134
|
|
|
125
135
|
/** only allow registered APIs to be tracked in the agent runtime */
|
|
126
|
-
if (!isBlocked())
|
|
136
|
+
if (!isBlocked()) {
|
|
137
|
+
registeredEntities.push(api)
|
|
138
|
+
subscribeToPageUnload(reportTimings)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Reports the gathered timings for the registered entity through a custom event to the container agent. Only reports once
|
|
143
|
+
* by checking for the presence of the reportedAt timing.
|
|
144
|
+
* @returns {void}
|
|
145
|
+
*/
|
|
146
|
+
function reportTimings () {
|
|
147
|
+
// only ever report the timings the first time this is called
|
|
148
|
+
if (timings.reportedAt) return
|
|
149
|
+
timings.reportedAt = now()
|
|
150
|
+
api.recordCustomEvent('MicroFrontEndTiming', {
|
|
151
|
+
timeToLoad: timings.registeredAt - timings.fetchStart, // fetchStart to registeredAt
|
|
152
|
+
timeToBeRequested: timings.fetchStart, // origin to fetchStart
|
|
153
|
+
timeToFetch: timings.fetchEnd - timings.fetchStart, // fetchStart to fetchEnd
|
|
154
|
+
timeToRegister: timings.registeredAt - timings.fetchEnd, // fetchEnd to registeredAt
|
|
155
|
+
timeAlive: timings.reportedAt - timings.registeredAt // registeredAt to reportedAt
|
|
156
|
+
})
|
|
157
|
+
}
|
|
127
158
|
|
|
128
159
|
/**
|
|
129
160
|
* Sets a value local to the registered API attrs. Will do nothing if APIs are deregistered.
|