@newrelic/browser-agent 1.232.0 → 1.232.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/url/canonicalize-url.js +32 -0
- package/dist/cjs/common/url/canonicalize-url.test.js +42 -0
- package/dist/cjs/common/url/clean-url.js +10 -3
- package/dist/cjs/common/util/global-scope.js +4 -2
- package/dist/cjs/common/wrap/wrap-fetch.js +1 -3
- package/dist/cjs/common/wrap/wrap-function.js +1 -3
- package/dist/cjs/features/ajax/instrument/index.js +1 -1
- package/dist/cjs/features/jserrors/aggregate/canonical-function-name.js +12 -4
- package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.js +93 -10
- package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +164 -38
- package/dist/cjs/features/jserrors/aggregate/index.js +22 -43
- package/dist/cjs/features/jserrors/instrument/index.js +0 -2
- package/dist/cjs/features/session_trace/aggregate/index.js +1 -3
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/url/canonicalize-url.js +27 -0
- package/dist/esm/common/url/canonicalize-url.test.js +38 -0
- package/dist/esm/common/url/clean-url.js +10 -3
- package/dist/esm/common/util/global-scope.js +1 -0
- package/dist/esm/common/wrap/wrap-fetch.js +1 -2
- package/dist/esm/common/wrap/wrap-function.js +1 -2
- package/dist/esm/features/ajax/instrument/index.js +1 -1
- package/dist/esm/features/jserrors/aggregate/canonical-function-name.js +12 -4
- package/dist/esm/features/jserrors/aggregate/compute-stack-trace.js +93 -10
- package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +149 -25
- package/dist/esm/features/jserrors/aggregate/index.js +23 -43
- package/dist/esm/features/jserrors/instrument/index.js +0 -1
- package/dist/esm/features/session_trace/aggregate/index.js +1 -2
- package/dist/types/common/url/canonicalize-url.d.ts +9 -0
- package/dist/types/common/url/canonicalize-url.d.ts.map +1 -0
- package/dist/types/common/url/clean-url.d.ts +7 -1
- package/dist/types/common/url/clean-url.d.ts.map +1 -1
- package/dist/types/common/util/global-scope.d.ts +1 -0
- package/dist/types/common/util/global-scope.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts +8 -1
- package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts +48 -19
- package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +12 -3
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
- package/dist/types/features/page_action/aggregate/index.d.ts +1 -1
- package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/common/url/canonicalize-url.js +28 -0
- package/src/common/url/canonicalize-url.test.js +34 -0
- package/src/common/url/clean-url.js +10 -3
- package/src/common/util/global-scope.js +2 -0
- package/src/common/wrap/wrap-fetch.js +1 -2
- package/src/common/wrap/wrap-function.js +1 -2
- package/src/features/ajax/instrument/index.js +1 -1
- package/src/features/jserrors/aggregate/canonical-function-name.js +12 -4
- package/src/features/jserrors/aggregate/compute-stack-trace.js +85 -11
- package/src/features/jserrors/aggregate/compute-stack-trace.test.js +141 -24
- package/src/features/jserrors/aggregate/index.js +21 -47
- package/src/features/jserrors/instrument/index.js +0 -1
- package/src/features/session_trace/aggregate/index.js +1 -2
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.canonicalizeUrl = canonicalizeUrl;
|
|
7
|
+
var _globalScope = require("../util/global-scope");
|
|
8
|
+
var _cleanUrl = require("./clean-url");
|
|
9
|
+
/*
|
|
10
|
+
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
11
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Converts a URL to its basic form without a query string or fragment. If the resulting URL is the same as the
|
|
16
|
+
* loader's origin URL, returns '<inline>'.
|
|
17
|
+
* @param {string} url - The URL to be canonicalized.
|
|
18
|
+
* @param {string} loaderOriginUrl - The origin URL of the agent loader, used for inline detection.
|
|
19
|
+
* @returns {string} The canonicalized URL, or '<inline>' if the URL matches the loader origin URL.
|
|
20
|
+
*/
|
|
21
|
+
function canonicalizeUrl(url) {
|
|
22
|
+
if (typeof url !== 'string') return '';
|
|
23
|
+
const cleanedUrl = (0, _cleanUrl.cleanURL)(url);
|
|
24
|
+
const cleanedGlobalScopeUrl = (0, _cleanUrl.cleanURL)(_globalScope.initialLocation);
|
|
25
|
+
|
|
26
|
+
// If the URL matches the origin URL of the loader, we assume it originated within an inline script.
|
|
27
|
+
if (cleanedUrl === cleanedGlobalScopeUrl) {
|
|
28
|
+
return '<inline>';
|
|
29
|
+
} else {
|
|
30
|
+
return cleanedUrl;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
4
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
jest.resetModules();
|
|
7
|
+
});
|
|
8
|
+
test.each([null, undefined, 34])('returns empty string when url argument is %s', async url => {
|
|
9
|
+
const {
|
|
10
|
+
canonicalizeUrl
|
|
11
|
+
} = await Promise.resolve().then(() => _interopRequireWildcard(require('./canonicalize-url')));
|
|
12
|
+
expect(canonicalizeUrl(url)).toEqual('');
|
|
13
|
+
});
|
|
14
|
+
test('strips URLs of query strings and fragments', async () => {
|
|
15
|
+
jest.doMock('../util/global-scope', () => ({
|
|
16
|
+
initialLocation: 'http://different-domain.com/'
|
|
17
|
+
}));
|
|
18
|
+
const {
|
|
19
|
+
canonicalizeUrl
|
|
20
|
+
} = await Promise.resolve().then(() => _interopRequireWildcard(require('./canonicalize-url')));
|
|
21
|
+
expect(canonicalizeUrl('http://example.com/path?query=string#fragment')).toBe('http://example.com/path');
|
|
22
|
+
expect(canonicalizeUrl('https://www.example.com/path/to/file.html?param=value')).toBe('https://www.example.com/path/to/file.html');
|
|
23
|
+
expect(canonicalizeUrl('https://www.example.com/?param=value#fragment')).toBe('https://www.example.com/');
|
|
24
|
+
});
|
|
25
|
+
test('returns <inline> when matching the page URL of the loader', async () => {
|
|
26
|
+
jest.doMock('../util/global-scope', () => ({
|
|
27
|
+
initialLocation: 'http://example.com/'
|
|
28
|
+
}));
|
|
29
|
+
const {
|
|
30
|
+
canonicalizeUrl
|
|
31
|
+
} = await Promise.resolve().then(() => _interopRequireWildcard(require('./canonicalize-url')));
|
|
32
|
+
expect(canonicalizeUrl('http://example.com/')).toEqual('<inline>');
|
|
33
|
+
});
|
|
34
|
+
test('does not identify sub-paths of the loader origin as <inline>', async () => {
|
|
35
|
+
jest.doMock('../util/global-scope', () => ({
|
|
36
|
+
initialLocation: 'http://example.com/'
|
|
37
|
+
}));
|
|
38
|
+
const {
|
|
39
|
+
canonicalizeUrl
|
|
40
|
+
} = await Promise.resolve().then(() => _interopRequireWildcard(require('./canonicalize-url')));
|
|
41
|
+
expect(canonicalizeUrl('http://example.com/path/to/script.js')).not.toEqual('<inline>');
|
|
42
|
+
});
|
|
@@ -9,8 +9,15 @@ exports.cleanURL = cleanURL;
|
|
|
9
9
|
* SPDX-License-Identifier: Apache-2.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
var
|
|
13
|
-
var
|
|
12
|
+
var patternWithHash = /([^?#]*)[^#]*(#[^?]*|$).*/;
|
|
13
|
+
var patternWithoutHash = /([^?#]*)().*/;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Cleans a URL by removing the query string and fragment (hash portion).
|
|
17
|
+
* @param {string} url - The original URL to be cleaned.
|
|
18
|
+
* @param {boolean} [keepHash=false] - Whether to preserve the hash portion of the URL.
|
|
19
|
+
* @returns {string} The cleaned URL.
|
|
20
|
+
*/
|
|
14
21
|
function cleanURL(url, keepHash) {
|
|
15
|
-
return url.replace(keepHash ?
|
|
22
|
+
return url.replace(keepHash ? patternWithHash : patternWithoutHash, '$1$2');
|
|
16
23
|
}
|
|
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.getGlobalScope = getGlobalScope;
|
|
7
|
-
exports.isWorkerScope = exports.isBrowserScope = exports.globalScope = void 0;
|
|
7
|
+
exports.isWorkerScope = exports.isBrowserScope = exports.initialLocation = exports.globalScope = void 0;
|
|
8
8
|
exports.resetScope = resetScope;
|
|
9
9
|
exports.setScope = setScope;
|
|
10
10
|
/* global globalThis, WorkerGlobalScope, WorkerNavigator */
|
|
@@ -25,6 +25,8 @@ let globalScope = (() => {
|
|
|
25
25
|
}
|
|
26
26
|
throw new Error('New Relic browser agent shutting down due to error: Unable to locate global scope. This is possibly due to code redefining browser global variables like "self" and "window".');
|
|
27
27
|
})();
|
|
28
|
+
exports.globalScope = globalScope;
|
|
29
|
+
const initialLocation = '' + globalScope.location;
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* The below methods are only used for testing and should be removed once the
|
|
@@ -32,7 +34,7 @@ let globalScope = (() => {
|
|
|
32
34
|
* tests/browser/protocol.browser.js
|
|
33
35
|
* tests/browser/obfuscate.browser.js
|
|
34
36
|
*/
|
|
35
|
-
exports.
|
|
37
|
+
exports.initialLocation = initialLocation;
|
|
36
38
|
function setScope(obj) {
|
|
37
39
|
exports.globalScope = globalScope = {
|
|
38
40
|
...obj
|
|
@@ -6,10 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.scopedEE = scopedEE;
|
|
7
7
|
exports.wrapFetch = wrapFetch;
|
|
8
8
|
var _contextualEe = require("../event-emitter/contextual-ee");
|
|
9
|
-
var _lodash = _interopRequireDefault(require("lodash._slice"));
|
|
10
9
|
var _globalScope = require("../util/global-scope");
|
|
11
10
|
var _wrapFunction = require("./wrap-function");
|
|
12
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
11
|
/*
|
|
14
12
|
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
15
13
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -77,7 +75,7 @@ function wrapFetch(sharedEE) {
|
|
|
77
75
|
var fn = target[name];
|
|
78
76
|
if (typeof fn === 'function') {
|
|
79
77
|
target[name] = function () {
|
|
80
|
-
var args =
|
|
78
|
+
var args = Array.from(arguments);
|
|
81
79
|
var ctx = {};
|
|
82
80
|
// we are wrapping args in an array so we can preserve the reference
|
|
83
81
|
ee.emit(prefix + 'before-start', [args], ctx);
|
|
@@ -8,8 +8,6 @@ exports.flag = exports.default = void 0;
|
|
|
8
8
|
exports.wrapFunction = wrapFunction;
|
|
9
9
|
exports.wrapInPlace = wrapInPlace;
|
|
10
10
|
var _contextualEe = require("../event-emitter/contextual-ee");
|
|
11
|
-
var _lodash = _interopRequireDefault(require("lodash._slice"));
|
|
12
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
11
|
/*
|
|
14
12
|
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
15
13
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -83,7 +81,7 @@ function createWrapperWithEmitter(emitter, always) {
|
|
|
83
81
|
var result;
|
|
84
82
|
try {
|
|
85
83
|
originalThis = this;
|
|
86
|
-
args =
|
|
84
|
+
args = Array.from(arguments);
|
|
87
85
|
if (typeof getContext === 'function') {
|
|
88
86
|
ctx = getContext(args, originalThis);
|
|
89
87
|
} else {
|
|
@@ -99,7 +99,7 @@ function subscribeToEvents(agentIdentifier, ee, handler, dt) {
|
|
|
99
99
|
}
|
|
100
100
|
function onOpenXhrEnd(args, xhr) {
|
|
101
101
|
var loader_config = (0, _config.getLoaderConfig)(agentIdentifier);
|
|
102
|
-
if (
|
|
102
|
+
if (loader_config.xpid && this.sameOrigin) {
|
|
103
103
|
xhr.setRequestHeader('X-NewRelic-ID', loader_config.xpid);
|
|
104
104
|
}
|
|
105
105
|
var payload = dt.generateTracePayload(this.parsedOrigin);
|
|
@@ -9,10 +9,18 @@ exports.canonicalFunctionName = canonicalFunctionName;
|
|
|
9
9
|
* SPDX-License-Identifier: Apache-2.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
const canonicalFunctionNameRe = /([a-z0-9]+)$/i;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Given a function name string, extracts only an alphanumeric segment at the end of the string (if one exists).
|
|
16
|
+
* This is useful for stack traces, where functions might not be named (e.g., anonymous, computed).
|
|
17
|
+
*
|
|
18
|
+
* @param {string} functionNameString - The original function name string.
|
|
19
|
+
* @returns {string|undefined} The canonical function name, or undefined if the input is falsy or no alphanumeric segments are found.
|
|
20
|
+
*/
|
|
21
|
+
function canonicalFunctionName(functionNameString) {
|
|
22
|
+
if (!functionNameString) return;
|
|
23
|
+
const match = functionNameString.match(canonicalFunctionNameRe);
|
|
16
24
|
if (match) return match[1];
|
|
17
25
|
return;
|
|
18
26
|
}
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.computeStackTrace = computeStackTrace;
|
|
7
7
|
var _formatStackTrace = require("./format-stack-trace");
|
|
8
|
+
var _canonicalizeUrl = require("../../../common/url/canonicalize-url");
|
|
8
9
|
/*
|
|
9
10
|
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
10
11
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -70,6 +71,24 @@ var chrome = /^\s*at (?:((?:\[object object\])?(?:[^(]*\([^)]*\))*[^()]*(?: \[as
|
|
|
70
71
|
var gecko = /^\s*(?:(\S*|global code)(?:\(.*?\))?@)?((?:file|http|https|chrome|safari-extension).*?):(\d+)(?::(\d+))?\s*$/i;
|
|
71
72
|
var chrome_eval = /^\s*at .+ \(eval at \S+ \((?:(?:file|http|https):[^)]+)?\)(?:, [^:]*:\d+:\d+)?\)$/i;
|
|
72
73
|
var ie_eval = /^\s*at Function code \(Function code:\d+:\d+\)\s*/i;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Represents an error with a stack trace.
|
|
77
|
+
* @typedef {Object} StackInfo
|
|
78
|
+
* @property {string} name - The name of the error (e.g. 'TypeError').
|
|
79
|
+
* @property {string} message - The error message.
|
|
80
|
+
* @property {string} stackString - The stack trace as a string.
|
|
81
|
+
* @property {Array<Object>} frames - An array of frames in the stack trace.
|
|
82
|
+
* @property {string} frames.url - The URL of the file containing the code for the frame.
|
|
83
|
+
* @property {string} frames.func - The name of the function associated with the frame.
|
|
84
|
+
* @property {number} frames.line - The line number of the code in the frame.
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Attempts to compute a stack trace for the given exception.
|
|
89
|
+
* @param {Error} ex - The exception for which to compute the stack trace.
|
|
90
|
+
* @returns {StackInfo} A stack trace object containing information about the frames on the stack.
|
|
91
|
+
*/
|
|
73
92
|
function computeStackTrace(ex) {
|
|
74
93
|
var stack = null;
|
|
75
94
|
try {
|
|
@@ -110,9 +129,9 @@ function computeStackTrace(ex) {
|
|
|
110
129
|
}
|
|
111
130
|
|
|
112
131
|
/**
|
|
113
|
-
* Computes stack trace information from the stack property.
|
|
114
|
-
*
|
|
115
|
-
* @param {Error} ex
|
|
132
|
+
* Computes stack trace information from the stack property. Chrome and Gecko use this property.
|
|
133
|
+
*
|
|
134
|
+
* @param {Error} ex - The error object to compute the stack trace for.
|
|
116
135
|
* @return {?Object.<string, *>} Stack trace information.
|
|
117
136
|
*/
|
|
118
137
|
function computeStackTraceFromStackProp(ex) {
|
|
@@ -133,17 +152,48 @@ function computeStackTraceFromStackProp(ex) {
|
|
|
133
152
|
frames: errorInfo.frames
|
|
134
153
|
};
|
|
135
154
|
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Parses a line from a JavaScript error stack trace and adds it to the given `info` object.
|
|
158
|
+
* Ignores all stack entries thrown from one of our wrapper functions.
|
|
159
|
+
*
|
|
160
|
+
* @param {object} info - The `info` object to add the parsed line to.
|
|
161
|
+
* @param {string} line - The line to parse.
|
|
162
|
+
* @returns {object} The `info` object with the parsed line added.
|
|
163
|
+
*/
|
|
136
164
|
function parseStackProp(info, line) {
|
|
137
|
-
|
|
165
|
+
let element = getStackElement(line);
|
|
166
|
+
|
|
167
|
+
// This catches lines that aren't frames (like the first line stating the error).
|
|
138
168
|
if (!element) {
|
|
139
169
|
info.stackLines.push(line);
|
|
140
170
|
return info;
|
|
141
171
|
}
|
|
142
|
-
|
|
143
|
-
|
|
172
|
+
|
|
173
|
+
// Once we've seen a wrapper, ignore all subsequent stack entries.
|
|
174
|
+
if (isNrWrapper(element.func)) info.wrapperSeen = true;
|
|
175
|
+
if (!info.wrapperSeen) {
|
|
176
|
+
// Query strings and fragments should be removed, and URLs matching the loader's origin should be "<inline>".
|
|
177
|
+
let canonicalUrl = (0, _canonicalizeUrl.canonicalizeUrl)(element.url);
|
|
178
|
+
if (canonicalUrl !== element.url) {
|
|
179
|
+
line = line.replace(element.url, canonicalUrl);
|
|
180
|
+
element.url = canonicalUrl;
|
|
181
|
+
}
|
|
182
|
+
info.stackLines.push(line);
|
|
183
|
+
info.frames.push(element);
|
|
184
|
+
}
|
|
144
185
|
return info;
|
|
145
186
|
}
|
|
146
|
-
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Parses a line from a JavaScript error stack trace to extract information about a stack trace element, such as the
|
|
190
|
+
* URL, function name, line number, and column number.
|
|
191
|
+
*
|
|
192
|
+
* @param {string} line - A single line from a JavaScript error stack trace.
|
|
193
|
+
* @returns {object} An object containing information about the stack trace element, including the URL, function
|
|
194
|
+
* name, line number, and column number (if available).
|
|
195
|
+
*/
|
|
196
|
+
function getStackElement(line) {
|
|
147
197
|
var parts = line.match(gecko);
|
|
148
198
|
if (!parts) parts = line.match(chrome);
|
|
149
199
|
if (parts) {
|
|
@@ -160,6 +210,15 @@ function getElement(line) {
|
|
|
160
210
|
};
|
|
161
211
|
}
|
|
162
212
|
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Computes a stack trace object from an error object, by extracting the source and line number from the error object,
|
|
216
|
+
* and using them to create a single stack frame.
|
|
217
|
+
*
|
|
218
|
+
* @param {Error} ex - The error object to compute the stack trace for.
|
|
219
|
+
* @returns {Object|null} - An object representing the computed stack trace, or null if the
|
|
220
|
+
* input error object does not contain a line number.
|
|
221
|
+
*/
|
|
163
222
|
function computeStackTraceBySourceAndLine(ex) {
|
|
164
223
|
if (!('line' in ex)) return null;
|
|
165
224
|
var className = ex.name || getClassName(ex);
|
|
@@ -176,7 +235,10 @@ function computeStackTraceBySourceAndLine(ex) {
|
|
|
176
235
|
}]
|
|
177
236
|
};
|
|
178
237
|
}
|
|
179
|
-
|
|
238
|
+
|
|
239
|
+
// Remove any query string and fragment
|
|
240
|
+
var canonicalUrl = (0, _canonicalizeUrl.canonicalizeUrl)(ex.sourceURL);
|
|
241
|
+
var stackString = className + ': ' + ex.message + '\n at ' + canonicalUrl;
|
|
180
242
|
if (ex.line) {
|
|
181
243
|
stackString += ':' + ex.line;
|
|
182
244
|
if (ex.column) {
|
|
@@ -189,12 +251,19 @@ function computeStackTraceBySourceAndLine(ex) {
|
|
|
189
251
|
message: ex.message,
|
|
190
252
|
stackString: stackString,
|
|
191
253
|
frames: [{
|
|
192
|
-
url:
|
|
254
|
+
url: canonicalUrl,
|
|
193
255
|
line: ex.line,
|
|
194
256
|
column: ex.column
|
|
195
257
|
}]
|
|
196
258
|
};
|
|
197
259
|
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* For exceptions with no stack and only a message, derives a stack trace by extracting the class name and message.
|
|
263
|
+
*
|
|
264
|
+
* @param {Error} ex - The exception for which to compute the stack trace.
|
|
265
|
+
* @returns {StackTrace} A stack trace object containing the name and message of the exception.
|
|
266
|
+
*/
|
|
198
267
|
function computeStackTraceWithMessageOnly(ex) {
|
|
199
268
|
var className = ex.name || getClassName(ex);
|
|
200
269
|
if (!className) return null;
|
|
@@ -206,10 +275,24 @@ function computeStackTraceWithMessageOnly(ex) {
|
|
|
206
275
|
frames: []
|
|
207
276
|
};
|
|
208
277
|
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Attempts to extract the name of the constructor function (the class) of the given object.
|
|
281
|
+
*
|
|
282
|
+
* @param {Object} obj - The object for which to extract the constructor function name.
|
|
283
|
+
* @returns {string} The name of the constructor function, or 'unknown' if the name cannot be determined.
|
|
284
|
+
*/
|
|
209
285
|
function getClassName(obj) {
|
|
210
286
|
var results = classNameRegex.exec(String(obj.constructor));
|
|
211
287
|
return results && results.length > 1 ? results[1] : 'unknown';
|
|
212
288
|
}
|
|
213
|
-
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Checks whether the given function name is a New Relic wrapper function.
|
|
292
|
+
*
|
|
293
|
+
* @param {string} functionName - The name of the function to check.
|
|
294
|
+
* @returns {boolean} True if the function name includes the string 'nrWrapper', false otherwise.
|
|
295
|
+
*/
|
|
296
|
+
function isNrWrapper(functionName) {
|
|
214
297
|
return functionName && functionName.indexOf('nrWrapper') >= 0;
|
|
215
298
|
}
|