@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.
Files changed (62) hide show
  1. package/dist/cjs/common/constants/env.cdn.js +1 -1
  2. package/dist/cjs/common/constants/env.npm.js +1 -1
  3. package/dist/cjs/common/url/canonicalize-url.js +32 -0
  4. package/dist/cjs/common/url/canonicalize-url.test.js +42 -0
  5. package/dist/cjs/common/url/clean-url.js +10 -3
  6. package/dist/cjs/common/util/global-scope.js +4 -2
  7. package/dist/cjs/common/wrap/wrap-fetch.js +1 -3
  8. package/dist/cjs/common/wrap/wrap-function.js +1 -3
  9. package/dist/cjs/features/ajax/instrument/index.js +1 -1
  10. package/dist/cjs/features/jserrors/aggregate/canonical-function-name.js +12 -4
  11. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.js +93 -10
  12. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +164 -38
  13. package/dist/cjs/features/jserrors/aggregate/index.js +22 -43
  14. package/dist/cjs/features/jserrors/instrument/index.js +0 -2
  15. package/dist/cjs/features/session_trace/aggregate/index.js +1 -3
  16. package/dist/esm/common/constants/env.cdn.js +1 -1
  17. package/dist/esm/common/constants/env.npm.js +1 -1
  18. package/dist/esm/common/url/canonicalize-url.js +27 -0
  19. package/dist/esm/common/url/canonicalize-url.test.js +38 -0
  20. package/dist/esm/common/url/clean-url.js +10 -3
  21. package/dist/esm/common/util/global-scope.js +1 -0
  22. package/dist/esm/common/wrap/wrap-fetch.js +1 -2
  23. package/dist/esm/common/wrap/wrap-function.js +1 -2
  24. package/dist/esm/features/ajax/instrument/index.js +1 -1
  25. package/dist/esm/features/jserrors/aggregate/canonical-function-name.js +12 -4
  26. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.js +93 -10
  27. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +149 -25
  28. package/dist/esm/features/jserrors/aggregate/index.js +23 -43
  29. package/dist/esm/features/jserrors/instrument/index.js +0 -1
  30. package/dist/esm/features/session_trace/aggregate/index.js +1 -2
  31. package/dist/types/common/url/canonicalize-url.d.ts +9 -0
  32. package/dist/types/common/url/canonicalize-url.d.ts.map +1 -0
  33. package/dist/types/common/url/clean-url.d.ts +7 -1
  34. package/dist/types/common/url/clean-url.d.ts.map +1 -1
  35. package/dist/types/common/util/global-scope.d.ts +1 -0
  36. package/dist/types/common/util/global-scope.d.ts.map +1 -1
  37. package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
  38. package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
  39. package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts +8 -1
  40. package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts.map +1 -1
  41. package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts +48 -19
  42. package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts.map +1 -1
  43. package/dist/types/features/jserrors/aggregate/index.d.ts +12 -3
  44. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  45. package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
  46. package/dist/types/features/page_action/aggregate/index.d.ts +1 -1
  47. package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
  48. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  49. package/package.json +4 -4
  50. package/src/common/url/canonicalize-url.js +28 -0
  51. package/src/common/url/canonicalize-url.test.js +34 -0
  52. package/src/common/url/clean-url.js +10 -3
  53. package/src/common/util/global-scope.js +2 -0
  54. package/src/common/wrap/wrap-fetch.js +1 -2
  55. package/src/common/wrap/wrap-function.js +1 -2
  56. package/src/features/ajax/instrument/index.js +1 -1
  57. package/src/features/jserrors/aggregate/canonical-function-name.js +12 -4
  58. package/src/features/jserrors/aggregate/compute-stack-trace.js +85 -11
  59. package/src/features/jserrors/aggregate/compute-stack-trace.test.js +141 -24
  60. package/src/features/jserrors/aggregate/index.js +21 -47
  61. package/src/features/jserrors/instrument/index.js +0 -1
  62. package/src/features/session_trace/aggregate/index.js +1 -2
@@ -1,16 +1,34 @@
1
1
  import { faker } from '@faker-js/faker'
2
2
  import { browserErrorUtils } from '../../../../tools/testing-utils'
3
- import { computeStackTrace } from './compute-stack-trace'
3
+
4
+ const globalScopeLocation = 'https://example.com/'
5
+
6
+ const mockGlobalScopeLocation = (url) => {
7
+ jest.doMock('../../../common/util/global-scope', () => ({
8
+ initialLocation: url || globalScopeLocation
9
+ }))
10
+ }
11
+
12
+ afterEach(() => {
13
+ jest.resetModules()
14
+ jest.clearAllMocks()
15
+ })
4
16
 
5
17
  const baseMockError = {
6
18
  toString: 'RangeError: Invalid array length',
7
19
  name: 'RangeError',
8
20
  constructor: 'function RangeError() { [native code] }',
9
21
  message: 'Invalid array length',
10
- stack: 'RangeError: Invalid array length\n at errorTest (http://bam-test-1.nr-local.net:3334/tests/assets/instrumented.html?loader=spa:74:16)\n at captureError (http://bam-test-1.nr-local.net:3334/tests/assets/instrumented.html?loader=spa:17:9)\n at onload (http://bam-test-1.nr-local.net:3334/tests/assets/instrumented.html?loader=spa:70:5)'
22
+ stack:
23
+ 'RangeError: Invalid array length\n' +
24
+ ' at errorTest (' + globalScopeLocation + '?loader=spa#hello:74:16)\n' +
25
+ ' at captureError (' + globalScopeLocation + 'js/script.js?loader=spa:17:9)\n' +
26
+ ' at onload (' + globalScopeLocation + 'js/script.js?loader=spa:70:5)'
11
27
  }
12
28
 
13
- test('parsing should return a failure for a null error object', () => {
29
+ test('parsing should return a failure for a null error object', async () => {
30
+ mockGlobalScopeLocation()
31
+ const { computeStackTrace } = await import('./compute-stack-trace')
14
32
  const result = computeStackTrace(null)
15
33
 
16
34
  expect(result).toEqual(expect.objectContaining({
@@ -21,29 +39,49 @@ test('parsing should return a failure for a null error object', () => {
21
39
  })
22
40
 
23
41
  describe('errors with stack property', () => {
24
- test('parsed name should be unknown when name and constructor are missing', () => {
42
+ test('should show <inline> for same-page stack string URLs but not sub-paths', async () => {
43
+ const mockError = browserErrorUtils.constructError({
44
+ ...baseMockError
45
+ })
46
+
47
+ mockGlobalScopeLocation()
48
+ const { computeStackTrace } = await import('./compute-stack-trace')
49
+ const result = computeStackTrace(mockError)
50
+
51
+ expect(result).toEqual(expect.objectContaining({
52
+ stackString: // canonicalized
53
+ 'RangeError: Invalid array length\n' +
54
+ ' at errorTest (<inline>:74:16)\n' +
55
+ ' at captureError (' + globalScopeLocation + 'js/script.js:17:9)\n' +
56
+ ' at onload (' + globalScopeLocation + 'js/script.js:70:5)'
57
+ }))
58
+ })
59
+
60
+ test('parsed name should be unknown when name and constructor are missing', async () => {
25
61
  const mockError = browserErrorUtils.constructError({
26
62
  ...baseMockError,
27
63
  name: null,
28
64
  constructor: null
29
65
  })
30
66
 
67
+ mockGlobalScopeLocation()
68
+ const { computeStackTrace } = await import('./compute-stack-trace')
31
69
  const result = computeStackTrace(mockError)
32
70
 
33
71
  expect(result).toEqual(expect.objectContaining({
34
72
  mode: 'stack',
35
- name: 'unknown',
36
- message: mockError.message,
37
- stackString: mockError.stack
73
+ name: 'unknown'
38
74
  }))
39
75
  })
40
76
 
41
- test('parsed stack should not contain nrWrapper', () => {
77
+ test('parsed stack should not contain nrWrapper', async () => {
42
78
  const alteredError = baseMockError
43
79
  alteredError.stack +=
44
- '\n at nrWrapper (http://bam-test-1.nr-local.net:3334/tests/assets/instrumented.html?loader=spa:60:17)'
80
+ '\n at nrWrapper (' + globalScopeLocation + '?loader=spa:60:17)'
45
81
  const mockError = browserErrorUtils.constructError(alteredError)
46
82
 
83
+ mockGlobalScopeLocation()
84
+ const { computeStackTrace } = await import('./compute-stack-trace')
47
85
  const result = computeStackTrace(mockError)
48
86
 
49
87
  expect(result).toEqual(expect.objectContaining({
@@ -57,20 +95,31 @@ describe('errors with stack property', () => {
57
95
  }))
58
96
  })
59
97
 
60
- test('stack should still parse when column numbers are missing', () => {
98
+ test('stack should still parse when column numbers are missing', async () => {
61
99
  const mockError = browserErrorUtils.constructError({
62
100
  ...baseMockError,
63
101
  stack:
64
- 'Error: Blocked a frame with origin "http://bam-test-1.nr-local.net:3334" from accessing a cross-origin frame.\n at errorTest (http://bam-test-1.nr-local.net:3334/tests/assets/instrumented.html?loader=spa:60)\n at captureError (http://bam-test-1.nr-local.net:3334/tests/assets/instrumented.html?loader=spa:17)\n at onload (http://bam-test-1.nr-local.net:3334/tests/assets/instrumented.html?loader=spa:57)'
102
+ 'RangeError: Invalid array length\n' +
103
+ 'Error: Blocked a frame with origin "http://bam-test-1.nr-local.net:3334" from accessing a cross-origin frame.\n' +
104
+ ' at errorTest (' + globalScopeLocation + '?loader=spa:60)\n' +
105
+ ' at captureError (' + globalScopeLocation + '?loader=spa:17)\n' +
106
+ ' at onload (' + globalScopeLocation + '?loader=spa:57)'
65
107
  })
66
108
 
109
+ mockGlobalScopeLocation()
110
+ const { computeStackTrace } = await import('./compute-stack-trace')
67
111
  const result = computeStackTrace(mockError)
68
112
 
69
113
  expect(result).toEqual(expect.objectContaining({
70
114
  mode: 'stack',
71
115
  name: mockError.name,
72
116
  message: mockError.message,
73
- stackString: mockError.stack
117
+ stackString:
118
+ 'RangeError: Invalid array length\n' +
119
+ 'Error: Blocked a frame with origin "http://bam-test-1.nr-local.net:3334" from accessing a cross-origin frame.\n' +
120
+ ' at errorTest (<inline>:60)\n' +
121
+ ' at captureError (<inline>:17)\n' +
122
+ ' at onload (<inline>:57)'
74
123
  }))
75
124
  expect(result.frames.length).toEqual(3)
76
125
  expect(result.frames).toContainEqual(expect.objectContaining({
@@ -87,13 +136,15 @@ describe('errors with stack property', () => {
87
136
  }))
88
137
  })
89
138
 
90
- test('parser can handle chrome eval stack', () => {
139
+ test('parser can handle chrome eval stack', async () => {
91
140
  const mockError = browserErrorUtils.constructError({
92
141
  ...baseMockError,
93
142
  stack:
94
- ' at foobar (eval at foobar (http://bam-test-1.nr-local.net:3334/tests/assets/instrumented.html))'
143
+ ' at foobar (eval at foobar (' + globalScopeLocation + '))'
95
144
  })
96
145
 
146
+ mockGlobalScopeLocation()
147
+ const { computeStackTrace } = await import('./compute-stack-trace')
97
148
  const result = computeStackTrace(mockError)
98
149
 
99
150
  expect(result).toEqual(expect.objectContaining({
@@ -108,7 +159,7 @@ describe('errors with stack property', () => {
108
159
  }))
109
160
  })
110
161
 
111
- test('parser can handle ie eval stack', () => {
162
+ test('parser can handle ie eval stack', async () => {
112
163
  const mockError = browserErrorUtils.constructError({
113
164
  toString: 'TypeError: Permission denied',
114
165
  name: 'TypeError',
@@ -118,6 +169,8 @@ describe('errors with stack property', () => {
118
169
  ' at Function code (Function code:23:23)'
119
170
  })
120
171
 
172
+ mockGlobalScopeLocation()
173
+ const { computeStackTrace } = await import('./compute-stack-trace')
121
174
  const result = computeStackTrace(mockError)
122
175
 
123
176
  expect(result).toEqual(expect.objectContaining({
@@ -132,13 +185,15 @@ describe('errors with stack property', () => {
132
185
  }))
133
186
  })
134
187
 
135
- test('parser can handle stack with anonymous function', () => {
188
+ test('parser can handle stack with anonymous function', async () => {
136
189
  const mockError = browserErrorUtils.constructError({
137
190
  ...baseMockError,
138
191
  stack:
139
192
  'anonymous'
140
193
  })
141
194
 
195
+ mockGlobalScopeLocation()
196
+ const { computeStackTrace } = await import('./compute-stack-trace')
142
197
  const result = computeStackTrace(mockError)
143
198
 
144
199
  expect(result).toEqual(expect.objectContaining({
@@ -158,7 +213,7 @@ describe('errors without stack property and with line property', () => {
158
213
  /**
159
214
  * @deprecated sourceURL is no longer present in errors for any browsers we support
160
215
  */
161
- test('parsed stack should contain sourceURL and line number', () => {
216
+ test('parsed stack should contain sourceURL and line number', async () => {
162
217
  const sourceURL = faker.internet.url()
163
218
  const mockError = browserErrorUtils.constructError({
164
219
  ...baseMockError,
@@ -167,6 +222,8 @@ describe('errors without stack property and with line property', () => {
167
222
  sourceURL
168
223
  })
169
224
 
225
+ mockGlobalScopeLocation()
226
+ const { computeStackTrace } = await import('./compute-stack-trace')
170
227
  const result = computeStackTrace(mockError)
171
228
 
172
229
  expect(result).toEqual(expect.objectContaining({
@@ -185,7 +242,7 @@ describe('errors without stack property and with line property', () => {
185
242
  /**
186
243
  * @deprecated sourceURL is no longer present in errors for any browsers we support
187
244
  */
188
- test('parsed stack should contain sourceURL, line number, and column number', () => {
245
+ test('parsed stack should contain sourceURL, line number, and column number', async () => {
189
246
  const sourceURL = faker.internet.url()
190
247
  const mockError = browserErrorUtils.constructError({
191
248
  ...baseMockError,
@@ -195,6 +252,8 @@ describe('errors without stack property and with line property', () => {
195
252
  sourceURL
196
253
  })
197
254
 
255
+ mockGlobalScopeLocation()
256
+ const { computeStackTrace } = await import('./compute-stack-trace')
198
257
  const result = computeStackTrace(mockError)
199
258
 
200
259
  expect(result).toEqual(expect.objectContaining({
@@ -211,7 +270,7 @@ describe('errors without stack property and with line property', () => {
211
270
  }))
212
271
  })
213
272
 
214
- test('parsed stack should contain "evaluated code" if sourceURL property is not present', () => {
273
+ test('parsed stack should contain "evaluated code" if sourceURL property is not present', async () => {
215
274
  const mockError = browserErrorUtils.constructError({
216
275
  ...baseMockError,
217
276
  line: 100,
@@ -219,6 +278,8 @@ describe('errors without stack property and with line property', () => {
219
278
  stack: undefined
220
279
  })
221
280
 
281
+ mockGlobalScopeLocation()
282
+ const { computeStackTrace } = await import('./compute-stack-trace')
222
283
  const result = computeStackTrace(mockError)
223
284
 
224
285
  expect(result).toEqual(expect.objectContaining({
@@ -233,6 +294,58 @@ describe('errors without stack property and with line property', () => {
233
294
  }))
234
295
  })
235
296
 
297
+ /**
298
+ * @deprecated sourceURL is no longer present in errors for any browsers we support
299
+ */
300
+ test('should show <inline> for same-page URLs', async () => {
301
+ const pageLocation = faker.internet.url()
302
+ const sourceURL = pageLocation + '?abc=123'
303
+ const mockError = browserErrorUtils.constructError({
304
+ ...baseMockError,
305
+ line: 100,
306
+ column: 200,
307
+ stack: undefined,
308
+ sourceURL: sourceURL
309
+ })
310
+
311
+ mockGlobalScopeLocation(pageLocation)
312
+ const { computeStackTrace } = await import('./compute-stack-trace')
313
+ const result = computeStackTrace(mockError)
314
+
315
+ expect(result).toEqual(expect.objectContaining({
316
+ stackString: `${mockError.name}: ${mockError.message}\n at <inline>:${mockError.line}:${mockError.column}`
317
+ }))
318
+ expect(result.frames).toContainEqual(expect.objectContaining({
319
+ url: '<inline>'
320
+ }))
321
+ })
322
+
323
+ /**
324
+ * @deprecated sourceURL is no longer present in errors for any browsers we support
325
+ */
326
+ test('should NOT show <inline> for same-domain URLs with a sub-path', async () => {
327
+ const pageLocation = faker.internet.url()
328
+ const sourceURL = pageLocation + '/path/to/script.js'
329
+ const mockError = browserErrorUtils.constructError({
330
+ ...baseMockError,
331
+ line: 100,
332
+ column: 200,
333
+ stack: undefined,
334
+ sourceURL
335
+ })
336
+
337
+ mockGlobalScopeLocation(pageLocation)
338
+ const { computeStackTrace } = await import('./compute-stack-trace')
339
+ const result = computeStackTrace(mockError)
340
+
341
+ expect(result).toEqual(expect.objectContaining({
342
+ stackString: `${mockError.name}: ${mockError.message}\n at ${sourceURL}:${mockError.line}:${mockError.column}`
343
+ }))
344
+ expect(result.frames).toContainEqual(expect.objectContaining({
345
+ url: sourceURL
346
+ }))
347
+ })
348
+
236
349
  // TODO: computeStackTraceBySourceAndLine does not respect firefox lineNumber and columnNumber properties when stack is empty
237
350
  })
238
351
 
@@ -241,12 +354,14 @@ describe('errors without stack property and with line property', () => {
241
354
  * error, including primitives.
242
355
  */
243
356
  describe('errors that are messages only or primitives', () => {
244
- test('parser should get error name from constructor', () => {
357
+ test('parser should get error name from constructor', async () => {
245
358
  const mockError = browserErrorUtils.constructError({
246
359
  toString: '0',
247
360
  constructor: 'function Number() { [native code] }'
248
361
  })
249
362
 
363
+ mockGlobalScopeLocation()
364
+ const { computeStackTrace } = await import('./compute-stack-trace')
250
365
  const result = computeStackTrace(mockError)
251
366
 
252
367
  expect(result).toEqual(expect.objectContaining({
@@ -257,13 +372,15 @@ describe('errors that are messages only or primitives', () => {
257
372
  }))
258
373
  })
259
374
 
260
- test('parser should get error name from name property', () => {
375
+ test('parser should get error name from name property', async () => {
261
376
  const mockError = browserErrorUtils.constructError({
262
377
  toString: '0',
263
378
  name: faker.datatype.uuid(),
264
379
  constructor: 'function Number() { [native code] }'
265
380
  })
266
381
 
382
+ mockGlobalScopeLocation()
383
+ const { computeStackTrace } = await import('./compute-stack-trace')
267
384
  const result = computeStackTrace(mockError)
268
385
 
269
386
  expect(result).toEqual(expect.objectContaining({
@@ -274,7 +391,7 @@ describe('errors that are messages only or primitives', () => {
274
391
  }))
275
392
  })
276
393
 
277
- test('parser should include the message property', () => {
394
+ test('parser should include the message property', async () => {
278
395
  const mockError = browserErrorUtils.constructError({
279
396
  toString: '0',
280
397
  name: faker.datatype.uuid(),
@@ -282,6 +399,8 @@ describe('errors that are messages only or primitives', () => {
282
399
  constructor: 'function Number() { [native code] }'
283
400
  })
284
401
 
402
+ mockGlobalScopeLocation()
403
+ const { computeStackTrace } = await import('./compute-stack-trace')
285
404
  const result = computeStackTrace(mockError)
286
405
 
287
406
  expect(result).toEqual(expect.objectContaining({
@@ -293,5 +412,3 @@ describe('errors that are messages only or primitives', () => {
293
412
  }))
294
413
  })
295
414
  })
296
-
297
- // describe('')
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import { canonicalFunctionName } from './canonical-function-name'
7
- import { cleanURL } from '../../../common/url/clean-url'
8
7
  import { computeStackTrace } from './compute-stack-trace'
9
8
  import { stringHashCode } from './string-hash-code'
10
9
  import { truncateSize } from './format-stack-trace'
@@ -23,6 +22,10 @@ import { drain } from '../../../common/drain/drain'
23
22
  import { FEATURE_NAMES } from '../../../loaders/features/features'
24
23
  import { FeatureBase } from '../../utils/feature-base'
25
24
 
25
+ /**
26
+ * @typedef {import('./compute-stack-trace.js').StackInfo} StackInfo
27
+ */
28
+
26
29
  export class Aggregate extends FeatureBase {
27
30
  static featureName = FEATURE_NAME
28
31
  constructor (agentIdentifier, aggregator) {
@@ -105,56 +108,27 @@ export class Aggregate extends FeatureBase {
105
108
  return this.nameHash(params) + ':' + stringHashCode(stringify(customParams))
106
109
  }
107
110
 
108
- canonicalizeURL (url, cleanedOrigin) {
109
- if (typeof url !== 'string') return ''
110
-
111
- var cleanedURL = cleanURL(url)
112
- if (cleanedURL === cleanedOrigin) {
113
- return '<inline>'
114
- } else {
115
- return cleanedURL
116
- }
117
- }
118
-
119
- buildCanonicalStackString (stackInfo, cleanedOrigin) {
120
- var canonicalStack = ''
111
+ /**
112
+ * Builds a standardized stack trace string from the frames in the given `stackInfo` object, with each frame separated
113
+ * by a newline character. Lines take the form `<functionName>@<url>:<lineNumber>`.
114
+ *
115
+ * @param {StackInfo} stackInfo - An object specifying a stack string and individual frames.
116
+ * @returns {string} A canonical stack string built from the URLs and function names in the given `stackInfo` object.
117
+ */
118
+ buildCanonicalStackString (stackInfo) {
119
+ var canonicalStackString = ''
121
120
 
122
121
  for (var i = 0; i < stackInfo.frames.length; i++) {
123
122
  var frame = stackInfo.frames[i]
124
123
  var func = canonicalFunctionName(frame.func)
125
124
 
126
- if (canonicalStack) canonicalStack += '\n'
127
- if (func) canonicalStack += func + '@'
128
- if (typeof frame.url === 'string') canonicalStack += frame.url
129
- if (frame.line) canonicalStack += ':' + frame.line
130
- }
131
-
132
- return canonicalStack
133
- }
134
-
135
- // Strip query parameters and fragments from the stackString property of the
136
- // given stackInfo, along with the 'url' properties of each frame in
137
- // stackInfo.frames.
138
- //
139
- // Any URLs that are equivalent to the cleaned version of the origin will also
140
- // be replaced with the string '<inline>'.
141
- //
142
- canonicalizeStackURLs (stackInfo) {
143
- // Currently, loader.origin might contain a fragment, but we don't want to use it
144
- // for comparing with frame URLs.
145
- var cleanedOrigin = cleanURL(getRuntime(this.agentIdentifier).origin)
146
-
147
- for (var i = 0; i < stackInfo.frames.length; i++) {
148
- var frame = stackInfo.frames[i]
149
- var originalURL = frame.url
150
- var cleanedURL = this.canonicalizeURL(originalURL, cleanedOrigin)
151
- if (cleanedURL && cleanedURL !== frame.url) {
152
- frame.url = cleanedURL
153
- stackInfo.stackString = stackInfo.stackString.split(originalURL).join(cleanedURL)
154
- }
125
+ if (canonicalStackString) canonicalStackString += '\n'
126
+ if (func) canonicalStackString += func + '@'
127
+ if (typeof frame.url === 'string') canonicalStackString += frame.url
128
+ if (frame.line) canonicalStackString += ':' + frame.line
155
129
  }
156
130
 
157
- return stackInfo
131
+ return canonicalStackString
158
132
  }
159
133
 
160
134
  storeError (err, time, internal, customAttributes) {
@@ -173,11 +147,11 @@ export class Aggregate extends FeatureBase {
173
147
  // Again as with previous usage, all falsey values would include the error.
174
148
  }
175
149
 
176
- var stackInfo = this.canonicalizeStackURLs(computeStackTrace(err))
177
- var canonicalStack = this.buildCanonicalStackString(stackInfo)
150
+ var stackInfo = computeStackTrace(err)
151
+ var canonicalStackString = this.buildCanonicalStackString(stackInfo)
178
152
 
179
153
  const params = {
180
- stackHash: stringHashCode(canonicalStack),
154
+ stackHash: stringHashCode(canonicalStackString),
181
155
  exceptionClass: stackInfo.name,
182
156
  request_uri: globalScope?.location.pathname
183
157
  }
@@ -7,7 +7,6 @@ import { handle } from '../../../common/event-emitter/handle'
7
7
  import { now } from '../../../common/timing/now'
8
8
  import { getOrSet } from '../../../common/util/get-or-set'
9
9
  import { wrapRaf, wrapTimer, wrapEvents, wrapXhr } from '../../../common/wrap'
10
- import slice from 'lodash._slice'
11
10
  import './debug'
12
11
  import { InstrumentBase } from '../../utils/instrument-base'
13
12
  import { FEATURE_NAME, NR_ERR_PROP } from '../constants'
@@ -8,7 +8,6 @@ import { mapOwn } from '../../../common/util/map-own'
8
8
  import { stringify } from '../../../common/util/stringify'
9
9
  import { parseUrl } from '../../../common/url/parse-url'
10
10
  import { supportsPerformanceObserver } from '../../../common/window/supports-performance-observer'
11
- import slice from 'lodash._slice'
12
11
  import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config'
13
12
  import { now } from '../../../common/timing/now'
14
13
  import { FEATURE_NAME } from '../constants'
@@ -224,7 +223,7 @@ export class Aggregate extends FeatureBase {
224
223
  } else if (t && typeof (t.tagName) === 'string') {
225
224
  origin = t.tagName.toLowerCase()
226
225
  if (t.id) origin += '#' + t.id
227
- if (t.className) origin += '.' + slice(t.classList).join('.')
226
+ if (t.className) origin += '.' + Array.from(t.classList).join('.')
228
227
  }
229
228
 
230
229
  if (origin === 'unknown') {