@cloudcare/browser-core 1.0.17 → 1.0.20

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.
@@ -151,5 +151,23 @@ function mustUseSecureCookie(userConfiguration) {
151
151
  }
152
152
 
153
153
  function isIntakeRequest(url, configuration) {
154
- return (0, _urlPolyfill.haveSameOrigin)(url, configuration.datakitUrl);
154
+ // return haveSameOrigin(url, configuration.datakitUrl)
155
+ var notTakeRequest = [configuration.datakitUrl];
156
+
157
+ if (configuration.logsEndpoint) {
158
+ notTakeRequest.push(configuration.logsEndpoint);
159
+ }
160
+
161
+ var isIntake = false;
162
+
163
+ for (var _i = 0, _notTakeRequest = notTakeRequest; _i < _notTakeRequest.length; _i++) {
164
+ var _url = _notTakeRequest[_i];
165
+
166
+ if (url.indexOf(_url) === 0) {
167
+ isIntake = true;
168
+ break;
169
+ }
170
+ }
171
+
172
+ return isIntake;
155
173
  }
package/cjs/dataMap.js CHANGED
@@ -102,6 +102,7 @@ var dataMap = {
102
102
  tags: {
103
103
  error_source: 'error.source',
104
104
  error_type: 'error.type',
105
+ error_handling: 'error.handling',
105
106
  resource_url: 'error.resource.url',
106
107
  resource_url_host: 'error.resource.url_host',
107
108
  resource_url_path: 'error.resource.url_path',
@@ -46,14 +46,16 @@ function startConsoleTracking(errorObservable) {
46
46
 
47
47
  console.error = function () {
48
48
  originalConsoleError.apply(console, arguments);
49
- errorObservable.notify((0, _tools.extend)({}, buildErrorFromParams((0, _tools.toArray)(arguments)), {
49
+ var handlingStack = (0, _errorTools.createHandlingStack)();
50
+ errorObservable.notify((0, _tools.extend)({}, buildErrorFromParams((0, _tools.toArray)(arguments), handlingStack), {
50
51
  source: _errorTools.ErrorSource.CONSOLE,
51
- startClocks: (0, _tools.clocksNow)()
52
+ startClocks: (0, _tools.clocksNow)(),
53
+ handling: _enums.ErrorHandling.HANDLED
52
54
  }));
53
55
  };
54
56
  }
55
57
 
56
- function buildErrorFromParams(params) {
58
+ function buildErrorFromParams(params, handlingStack) {
57
59
  var firstErrorParam = (0, _tools.find)(params, function (param) {
58
60
  return param instanceof Error;
59
61
  });
@@ -63,7 +65,8 @@ function buildErrorFromParams(params) {
63
65
  }).join(' ');
64
66
  return {
65
67
  message: message,
66
- stack: firstErrorParam ? (0, _errorTools.toStackTraceString)((0, _tracekit.computeStackTrace)(firstErrorParam)) : undefined
68
+ stack: firstErrorParam ? (0, _errorTools.toStackTraceString)((0, _tracekit.computeStackTrace)(firstErrorParam)) : undefined,
69
+ handlingStack: handlingStack
67
70
  };
68
71
  }
69
72
 
@@ -93,7 +96,8 @@ function startRuntimeErrorTracking(errorObservable) {
93
96
  stack: error.stack,
94
97
  type: error.type,
95
98
  source: _errorTools.ErrorSource.SOURCE,
96
- startClocks: (0, _tools.clocksNow)()
99
+ startClocks: (0, _tools.clocksNow)(),
100
+ handling: _enums.ErrorHandling.UNHANDLED
97
101
  });
98
102
  };
99
103
 
@@ -4,12 +4,15 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.formatUnknownError = formatUnknownError;
7
+ exports.createHandlingStack = createHandlingStack;
7
8
  exports.toStackTraceString = toStackTraceString;
8
9
  exports.formatErrorMessage = formatErrorMessage;
9
10
  exports.ErrorSource = void 0;
10
11
 
11
12
  var _tools = require("./tools");
12
13
 
14
+ var _tracekit = require("../tracekit");
15
+
13
16
  var ErrorSource = {
14
17
  AGENT: 'agent',
15
18
  CONSOLE: 'console',
@@ -20,11 +23,12 @@ var ErrorSource = {
20
23
  };
21
24
  exports.ErrorSource = ErrorSource;
22
25
 
23
- function formatUnknownError(stackTrace, errorObject, nonErrorPrefix) {
26
+ function formatUnknownError(stackTrace, errorObject, nonErrorPrefix, handlingStack) {
24
27
  if (!stackTrace || stackTrace.message === undefined && !(errorObject instanceof Error)) {
25
28
  return {
26
29
  message: nonErrorPrefix + '' + JSON.stringify(errorObject),
27
30
  stack: 'No stack, consider using an instance of Error',
31
+ handlingStack: handlingStack,
28
32
  type: stackTrace && stackTrace.name
29
33
  };
30
34
  }
@@ -32,9 +36,43 @@ function formatUnknownError(stackTrace, errorObject, nonErrorPrefix) {
32
36
  return {
33
37
  message: stackTrace.message || 'Empty message',
34
38
  stack: toStackTraceString(stackTrace),
39
+ handlingStack: handlingStack,
35
40
  type: stackTrace.name
36
41
  };
37
42
  }
43
+ /**
44
+ Creates a stacktrace without SDK internal frames.
45
+
46
+ Constraints:
47
+ - Has to be called at the utmost position of the call stack.
48
+ - No internal monitoring should encapsulate the function, that is why we need to use callMonitored inside of it.
49
+ */
50
+
51
+
52
+ function createHandlingStack() {
53
+ /**
54
+ * Skip the two internal frames:
55
+ * - SDK API (console.error, ...)
56
+ * - this function
57
+ * in order to keep only the user calls
58
+ */
59
+ var internalFramesToSkip = 2;
60
+ var error = new Error();
61
+ var formattedStack; // IE needs to throw the error to fill in the stack trace
62
+
63
+ if (!error.stack) {
64
+ try {
65
+ throw error;
66
+ } catch (e) {
67
+ (0, _tools.noop)();
68
+ }
69
+ }
70
+
71
+ var stackTrace = (0, _tracekit.computeStackTrace)(error);
72
+ stackTrace.stack = stackTrace.stack.slice(internalFramesToSkip);
73
+ formattedStack = toStackTraceString(stackTrace);
74
+ return formattedStack;
75
+ }
38
76
 
39
77
  function toStackTraceString(stack) {
40
78
  var result = stack.name || 'Error' + ': ' + stack.message;
@@ -5,6 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.UUID = UUID;
7
7
  exports.replaceNumberCharByPath = replaceNumberCharByPath;
8
+ exports.getType = getType;
9
+ exports.mergeInto = mergeInto;
10
+ exports.deepClone = deepClone;
8
11
  exports.getStatusGroup = getStatusGroup;
9
12
  exports.jsonStringify = jsonStringify;
10
13
  exports.noop = noop;
@@ -717,7 +720,7 @@ function UUID(placeholder) {
717
720
 
718
721
  function replaceNumberCharByPath(path) {
719
722
  if (path) {
720
- return path.replace(/\/([^\/]*)\d([^\/]*)/g, '/?');
723
+ return path.replace(/\/([^\/]*)\d([^\/]*)/g, '/?').replace(/\/$/g, '');
721
724
  } else {
722
725
  return '';
723
726
  }
@@ -1312,6 +1315,113 @@ var getURLSearchParams = function getURLSearchParams(queryString) {
1312
1315
 
1313
1316
  exports.getURLSearchParams = getURLSearchParams;
1314
1317
 
1318
+ function createCircularReferenceChecker() {
1319
+ if (typeof WeakSet !== 'undefined') {
1320
+ var set = new WeakSet();
1321
+ return {
1322
+ hasAlreadyBeenSeen: function hasAlreadyBeenSeen(value) {
1323
+ var has = set.has(value);
1324
+
1325
+ if (!has) {
1326
+ set.add(value);
1327
+ }
1328
+
1329
+ return has;
1330
+ }
1331
+ };
1332
+ }
1333
+
1334
+ var array = [];
1335
+ return {
1336
+ hasAlreadyBeenSeen: function hasAlreadyBeenSeen(value) {
1337
+ var has = array.indexOf(value) >= 0;
1338
+
1339
+ if (!has) {
1340
+ array.push(value);
1341
+ }
1342
+
1343
+ return has;
1344
+ }
1345
+ };
1346
+ }
1347
+ /**
1348
+ * Similar to `typeof`, but distinguish plain objects from `null` and arrays
1349
+ */
1350
+
1351
+
1352
+ function getType(value) {
1353
+ if (value === null) {
1354
+ return 'null';
1355
+ }
1356
+
1357
+ if (Array.isArray(value)) {
1358
+ return 'array';
1359
+ }
1360
+
1361
+ return _typeof(value);
1362
+ }
1363
+ /**
1364
+ * Iterate over source and affect its sub values into destination, recursively.
1365
+ * If the source and destination can't be merged, return source.
1366
+ */
1367
+
1368
+
1369
+ function mergeInto(destination, source, circularReferenceChecker) {
1370
+ // ignore the source if it is undefined
1371
+ if (typeof circularReferenceChecker === 'undefined') {
1372
+ circularReferenceChecker = createCircularReferenceChecker();
1373
+ }
1374
+
1375
+ if (source === undefined) {
1376
+ return destination;
1377
+ }
1378
+
1379
+ if (_typeof(source) !== 'object' || source === null) {
1380
+ // primitive values - just return source
1381
+ return source;
1382
+ } else if (source instanceof Date) {
1383
+ return new Date(source.getTime());
1384
+ } else if (source instanceof RegExp) {
1385
+ var flags = source.flags || // old browsers compatibility
1386
+ [source.global ? 'g' : '', source.ignoreCase ? 'i' : '', source.multiline ? 'm' : '', source.sticky ? 'y' : '', source.unicode ? 'u' : ''].join('');
1387
+ return new RegExp(source.source, flags);
1388
+ }
1389
+
1390
+ if (circularReferenceChecker.hasAlreadyBeenSeen(source)) {
1391
+ // remove circular references
1392
+ return undefined;
1393
+ } else if (Array.isArray(source)) {
1394
+ var merged = Array.isArray(destination) ? destination : [];
1395
+
1396
+ for (var i = 0; i < source.length; ++i) {
1397
+ merged[i] = mergeInto(merged[i], source[i], circularReferenceChecker);
1398
+ }
1399
+
1400
+ return merged;
1401
+ }
1402
+
1403
+ var merged = getType(destination) === 'object' ? destination : {};
1404
+
1405
+ for (var key in source) {
1406
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1407
+ merged[key] = mergeInto(merged[key], source[key], circularReferenceChecker);
1408
+ }
1409
+ }
1410
+
1411
+ return merged;
1412
+ }
1413
+ /**
1414
+ * A simplistic implementation of a deep clone algorithm.
1415
+ * Caveats:
1416
+ * - It doesn't maintain prototype chains - don't use with instances of custom classes.
1417
+ * - It doesn't handle Map and Set
1418
+ */
1419
+
1420
+
1421
+ function deepClone(value) {
1422
+ return mergeInto(undefined, value);
1423
+ }
1424
+
1315
1425
  var _URL = function _URL(url) {
1316
1426
  var result = {};
1317
1427
  var basicProps = ['hash', 'host', 'hostname', 'href', 'origin', 'password', 'pathname', 'port', 'protocol', 'search', 'username'];
@@ -136,5 +136,21 @@ function mustUseSecureCookie(userConfiguration) {
136
136
  }
137
137
 
138
138
  export function isIntakeRequest(url, configuration) {
139
- return haveSameOrigin(url, configuration.datakitUrl);
139
+ // return haveSameOrigin(url, configuration.datakitUrl)
140
+ var notTakeRequest = [configuration.datakitUrl];
141
+
142
+ if (configuration.logsEndpoint) {
143
+ notTakeRequest.push(configuration.logsEndpoint);
144
+ }
145
+
146
+ var isIntake = false;
147
+
148
+ for (var _url of notTakeRequest) {
149
+ if (url.indexOf(_url) === 0) {
150
+ isIntake = true;
151
+ break;
152
+ }
153
+ }
154
+
155
+ return isIntake;
140
156
  }
package/esm/dataMap.js CHANGED
@@ -93,6 +93,7 @@ export var dataMap = {
93
93
  tags: {
94
94
  error_source: 'error.source',
95
95
  error_type: 'error.type',
96
+ error_handling: 'error.handling',
96
97
  resource_url: 'error.resource.url',
97
98
  resource_url_host: 'error.resource.url_host',
98
99
  resource_url_path: 'error.resource.url_path',
@@ -1,9 +1,9 @@
1
1
  import { toArray, jsonStringify, find, clocksNow, map, extend } from './helper/tools';
2
- import { ErrorSource, formatUnknownError, toStackTraceString, formatErrorMessage } from './helper/errorTools';
2
+ import { ErrorSource, formatUnknownError, toStackTraceString, formatErrorMessage, createHandlingStack } from './helper/errorTools';
3
3
  import { computeStackTrace, subscribe, unsubscribe } from './tracekit';
4
4
  import { Observable } from './helper/observable';
5
5
  import { isIntakeRequest } from './configuration';
6
- import { RequestType } from './helper/enums';
6
+ import { RequestType, ErrorHandling } from './helper/enums';
7
7
  import { resetXhrProxy, startXhrProxy } from './xhrProxy';
8
8
  import { resetFetchProxy, startFetchProxy } from './fetchProxy';
9
9
  var errorObservable;
@@ -23,14 +23,16 @@ export function startConsoleTracking(errorObservable) {
23
23
 
24
24
  console.error = function () {
25
25
  originalConsoleError.apply(console, arguments);
26
- errorObservable.notify(extend({}, buildErrorFromParams(toArray(arguments)), {
26
+ var handlingStack = createHandlingStack();
27
+ errorObservable.notify(extend({}, buildErrorFromParams(toArray(arguments), handlingStack), {
27
28
  source: ErrorSource.CONSOLE,
28
- startClocks: clocksNow()
29
+ startClocks: clocksNow(),
30
+ handling: ErrorHandling.HANDLED
29
31
  }));
30
32
  };
31
33
  }
32
34
 
33
- function buildErrorFromParams(params) {
35
+ function buildErrorFromParams(params, handlingStack) {
34
36
  var firstErrorParam = find(params, function (param) {
35
37
  return param instanceof Error;
36
38
  });
@@ -40,7 +42,8 @@ function buildErrorFromParams(params) {
40
42
  }).join(' ');
41
43
  return {
42
44
  message: message,
43
- stack: firstErrorParam ? toStackTraceString(computeStackTrace(firstErrorParam)) : undefined
45
+ stack: firstErrorParam ? toStackTraceString(computeStackTrace(firstErrorParam)) : undefined,
46
+ handlingStack: handlingStack
44
47
  };
45
48
  }
46
49
 
@@ -69,7 +72,8 @@ export function startRuntimeErrorTracking(errorObservable) {
69
72
  stack: error.stack,
70
73
  type: error.type,
71
74
  source: ErrorSource.SOURCE,
72
- startClocks: clocksNow()
75
+ startClocks: clocksNow(),
76
+ handling: ErrorHandling.UNHANDLED
73
77
  });
74
78
  };
75
79
 
@@ -1,4 +1,5 @@
1
- import { each } from './tools';
1
+ import { each, noop } from './tools';
2
+ import { computeStackTrace } from '../tracekit';
2
3
  export var ErrorSource = {
3
4
  AGENT: 'agent',
4
5
  CONSOLE: 'console',
@@ -7,11 +8,12 @@ export var ErrorSource = {
7
8
  LOGGER: 'logger',
8
9
  CUSTOM: 'custom'
9
10
  };
10
- export function formatUnknownError(stackTrace, errorObject, nonErrorPrefix) {
11
+ export function formatUnknownError(stackTrace, errorObject, nonErrorPrefix, handlingStack) {
11
12
  if (!stackTrace || stackTrace.message === undefined && !(errorObject instanceof Error)) {
12
13
  return {
13
14
  message: nonErrorPrefix + '' + JSON.stringify(errorObject),
14
15
  stack: 'No stack, consider using an instance of Error',
16
+ handlingStack: handlingStack,
15
17
  type: stackTrace && stackTrace.name
16
18
  };
17
19
  }
@@ -19,9 +21,42 @@ export function formatUnknownError(stackTrace, errorObject, nonErrorPrefix) {
19
21
  return {
20
22
  message: stackTrace.message || 'Empty message',
21
23
  stack: toStackTraceString(stackTrace),
24
+ handlingStack: handlingStack,
22
25
  type: stackTrace.name
23
26
  };
24
27
  }
28
+ /**
29
+ Creates a stacktrace without SDK internal frames.
30
+
31
+ Constraints:
32
+ - Has to be called at the utmost position of the call stack.
33
+ - No internal monitoring should encapsulate the function, that is why we need to use callMonitored inside of it.
34
+ */
35
+
36
+ export function createHandlingStack() {
37
+ /**
38
+ * Skip the two internal frames:
39
+ * - SDK API (console.error, ...)
40
+ * - this function
41
+ * in order to keep only the user calls
42
+ */
43
+ var internalFramesToSkip = 2;
44
+ var error = new Error();
45
+ var formattedStack; // IE needs to throw the error to fill in the stack trace
46
+
47
+ if (!error.stack) {
48
+ try {
49
+ throw error;
50
+ } catch (e) {
51
+ noop();
52
+ }
53
+ }
54
+
55
+ var stackTrace = computeStackTrace(error);
56
+ stackTrace.stack = stackTrace.stack.slice(internalFramesToSkip);
57
+ formattedStack = toStackTraceString(stackTrace);
58
+ return formattedStack;
59
+ }
25
60
  export function toStackTraceString(stack) {
26
61
  var result = stack.name || 'Error' + ': ' + stack.message;
27
62
  each(stack.stack, function (frame) {
@@ -543,7 +543,7 @@ export function UUID(placeholder) {
543
543
 
544
544
  export function replaceNumberCharByPath(path) {
545
545
  if (path) {
546
- return path.replace(/\/([^\/]*)\d([^\/]*)/g, '/?');
546
+ return path.replace(/\/([^\/]*)\d([^\/]*)/g, '/?').replace(/\/$/g, '');
547
547
  } else {
548
548
  return '';
549
549
  }
@@ -1098,6 +1098,113 @@ export var getURLSearchParams = function getURLSearchParams(queryString) {
1098
1098
 
1099
1099
  return args;
1100
1100
  };
1101
+
1102
+ function createCircularReferenceChecker() {
1103
+ if (typeof WeakSet !== 'undefined') {
1104
+ var set = new WeakSet();
1105
+ return {
1106
+ hasAlreadyBeenSeen(value) {
1107
+ var has = set.has(value);
1108
+
1109
+ if (!has) {
1110
+ set.add(value);
1111
+ }
1112
+
1113
+ return has;
1114
+ }
1115
+
1116
+ };
1117
+ }
1118
+
1119
+ var array = [];
1120
+ return {
1121
+ hasAlreadyBeenSeen(value) {
1122
+ var has = array.indexOf(value) >= 0;
1123
+
1124
+ if (!has) {
1125
+ array.push(value);
1126
+ }
1127
+
1128
+ return has;
1129
+ }
1130
+
1131
+ };
1132
+ }
1133
+ /**
1134
+ * Similar to `typeof`, but distinguish plain objects from `null` and arrays
1135
+ */
1136
+
1137
+
1138
+ export function getType(value) {
1139
+ if (value === null) {
1140
+ return 'null';
1141
+ }
1142
+
1143
+ if (Array.isArray(value)) {
1144
+ return 'array';
1145
+ }
1146
+
1147
+ return typeof value;
1148
+ }
1149
+ /**
1150
+ * Iterate over source and affect its sub values into destination, recursively.
1151
+ * If the source and destination can't be merged, return source.
1152
+ */
1153
+
1154
+ export function mergeInto(destination, source, circularReferenceChecker) {
1155
+ // ignore the source if it is undefined
1156
+ if (typeof circularReferenceChecker === 'undefined') {
1157
+ circularReferenceChecker = createCircularReferenceChecker();
1158
+ }
1159
+
1160
+ if (source === undefined) {
1161
+ return destination;
1162
+ }
1163
+
1164
+ if (typeof source !== 'object' || source === null) {
1165
+ // primitive values - just return source
1166
+ return source;
1167
+ } else if (source instanceof Date) {
1168
+ return new Date(source.getTime());
1169
+ } else if (source instanceof RegExp) {
1170
+ var flags = source.flags || // old browsers compatibility
1171
+ [source.global ? 'g' : '', source.ignoreCase ? 'i' : '', source.multiline ? 'm' : '', source.sticky ? 'y' : '', source.unicode ? 'u' : ''].join('');
1172
+ return new RegExp(source.source, flags);
1173
+ }
1174
+
1175
+ if (circularReferenceChecker.hasAlreadyBeenSeen(source)) {
1176
+ // remove circular references
1177
+ return undefined;
1178
+ } else if (Array.isArray(source)) {
1179
+ var merged = Array.isArray(destination) ? destination : [];
1180
+
1181
+ for (var i = 0; i < source.length; ++i) {
1182
+ merged[i] = mergeInto(merged[i], source[i], circularReferenceChecker);
1183
+ }
1184
+
1185
+ return merged;
1186
+ }
1187
+
1188
+ var merged = getType(destination) === 'object' ? destination : {};
1189
+
1190
+ for (var key in source) {
1191
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1192
+ merged[key] = mergeInto(merged[key], source[key], circularReferenceChecker);
1193
+ }
1194
+ }
1195
+
1196
+ return merged;
1197
+ }
1198
+ /**
1199
+ * A simplistic implementation of a deep clone algorithm.
1200
+ * Caveats:
1201
+ * - It doesn't maintain prototype chains - don't use with instances of custom classes.
1202
+ * - It doesn't handle Map and Set
1203
+ */
1204
+
1205
+ export function deepClone(value) {
1206
+ return mergeInto(undefined, value);
1207
+ }
1101
1208
  export var _URL = function _URL(url) {
1102
1209
  var result = {};
1103
1210
  var basicProps = ['hash', 'host', 'hostname', 'href', 'origin', 'password', 'pathname', 'port', 'protocol', 'search', 'username'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudcare/browser-core",
3
- "version": "1.0.17",
3
+ "version": "1.0.20",
4
4
  "main": "cjs/index.js",
5
5
  "module": "esm/index.js",
6
6
  "scripts": {
@@ -20,5 +20,5 @@
20
20
  "author": "dataflux",
21
21
  "license": "MIT",
22
22
  "description": "DataFlux RUM Web 端数据指标监控",
23
- "gitHead": "aa44bc2dbca2017e36e0561d810825e89715d847"
23
+ "gitHead": "a80f418bef92d7c86b3965fee63e6dc11f11b9e9"
24
24
  }
@@ -132,5 +132,17 @@ function mustUseSecureCookie(userConfiguration) {
132
132
  }
133
133
 
134
134
  export function isIntakeRequest(url, configuration) {
135
- return haveSameOrigin(url, configuration.datakitUrl)
135
+ // return haveSameOrigin(url, configuration.datakitUrl)
136
+ var notTakeRequest = [configuration.datakitUrl]
137
+ if (configuration.logsEndpoint) {
138
+ notTakeRequest.push(configuration.logsEndpoint)
139
+ }
140
+ var isIntake = false
141
+ for(var _url of notTakeRequest) {
142
+ if (url.indexOf(_url) === 0) {
143
+ isIntake = true
144
+ break;
145
+ }
146
+ }
147
+ return isIntake
136
148
  }
package/src/dataMap.js CHANGED
@@ -93,6 +93,7 @@ export var dataMap = {
93
93
  tags: {
94
94
  error_source: 'error.source',
95
95
  error_type: 'error.type',
96
+ error_handling: 'error.handling',
96
97
  resource_url: 'error.resource.url',
97
98
  resource_url_host: 'error.resource.url_host',
98
99
  resource_url_path: 'error.resource.url_path',
@@ -10,12 +10,13 @@ import {
10
10
  ErrorSource,
11
11
  formatUnknownError,
12
12
  toStackTraceString,
13
- formatErrorMessage
13
+ formatErrorMessage,
14
+ createHandlingStack
14
15
  } from './helper/errorTools'
15
16
  import { computeStackTrace, subscribe, unsubscribe } from './tracekit'
16
17
  import { Observable } from './helper/observable'
17
18
  import { isIntakeRequest } from './configuration'
18
- import { RequestType } from './helper/enums'
19
+ import { RequestType, ErrorHandling } from './helper/enums'
19
20
  import { resetXhrProxy, startXhrProxy } from './xhrProxy'
20
21
  import { resetFetchProxy, startFetchProxy } from './fetchProxy'
21
22
 
@@ -37,16 +38,18 @@ export function startConsoleTracking(errorObservable) {
37
38
  originalConsoleError = console.error
38
39
  console.error = function () {
39
40
  originalConsoleError.apply(console, arguments)
41
+ const handlingStack = createHandlingStack()
40
42
  errorObservable.notify(
41
- extend({}, buildErrorFromParams(toArray(arguments)), {
43
+ extend({}, buildErrorFromParams(toArray(arguments), handlingStack), {
42
44
  source: ErrorSource.CONSOLE,
43
- startClocks: clocksNow()
45
+ startClocks: clocksNow(),
46
+ handling: ErrorHandling.HANDLED
44
47
  })
45
48
  )
46
49
  }
47
50
  }
48
51
 
49
- function buildErrorFromParams(params) {
52
+ function buildErrorFromParams(params, handlingStack) {
50
53
  var firstErrorParam = find(params, function (param) {
51
54
  return param instanceof Error
52
55
  })
@@ -58,7 +61,8 @@ function buildErrorFromParams(params) {
58
61
  message: message,
59
62
  stack: firstErrorParam
60
63
  ? toStackTraceString(computeStackTrace(firstErrorParam))
61
- : undefined
64
+ : undefined,
65
+ handlingStack: handlingStack
62
66
  }
63
67
  }
64
68
 
@@ -86,7 +90,8 @@ export function startRuntimeErrorTracking(errorObservable) {
86
90
  stack: error.stack,
87
91
  type: error.type,
88
92
  source: ErrorSource.SOURCE,
89
- startClocks: clocksNow()
93
+ startClocks: clocksNow(),
94
+ handling: ErrorHandling.UNHANDLED
90
95
  })
91
96
  }
92
97
 
@@ -1,4 +1,6 @@
1
- import { each } from './tools'
1
+ import { each , noop} from './tools'
2
+ import { computeStackTrace} from '../tracekit'
3
+
2
4
  export var ErrorSource = {
3
5
  AGENT: 'agent',
4
6
  CONSOLE: 'console',
@@ -7,7 +9,8 @@ export var ErrorSource = {
7
9
  LOGGER: 'logger',
8
10
  CUSTOM: 'custom'
9
11
  }
10
- export function formatUnknownError(stackTrace, errorObject, nonErrorPrefix) {
12
+
13
+ export function formatUnknownError(stackTrace, errorObject, nonErrorPrefix,handlingStack) {
11
14
  if (
12
15
  !stackTrace ||
13
16
  (stackTrace.message === undefined && !(errorObject instanceof Error))
@@ -15,16 +18,50 @@ export function formatUnknownError(stackTrace, errorObject, nonErrorPrefix) {
15
18
  return {
16
19
  message: nonErrorPrefix + '' + JSON.stringify(errorObject),
17
20
  stack: 'No stack, consider using an instance of Error',
21
+ handlingStack:handlingStack,
18
22
  type: stackTrace && stackTrace.name
19
23
  }
20
24
  }
21
25
  return {
22
26
  message: stackTrace.message || 'Empty message',
23
27
  stack: toStackTraceString(stackTrace),
28
+ handlingStack:handlingStack,
24
29
  type: stackTrace.name
25
30
  }
26
31
  }
32
+ /**
33
+ Creates a stacktrace without SDK internal frames.
34
+
35
+ Constraints:
36
+ - Has to be called at the utmost position of the call stack.
37
+ - No internal monitoring should encapsulate the function, that is why we need to use callMonitored inside of it.
38
+ */
39
+ export function createHandlingStack() {
40
+ /**
41
+ * Skip the two internal frames:
42
+ * - SDK API (console.error, ...)
43
+ * - this function
44
+ * in order to keep only the user calls
45
+ */
46
+ const internalFramesToSkip = 2
47
+ const error = new Error()
48
+ let formattedStack
27
49
 
50
+ // IE needs to throw the error to fill in the stack trace
51
+ if (!error.stack) {
52
+ try {
53
+ throw error
54
+ } catch (e) {
55
+ noop()
56
+ }
57
+ }
58
+
59
+ const stackTrace = computeStackTrace(error)
60
+ stackTrace.stack = stackTrace.stack.slice(internalFramesToSkip)
61
+ formattedStack = toStackTraceString(stackTrace)
62
+
63
+ return formattedStack
64
+ }
28
65
  export function toStackTraceString(stack) {
29
66
  var result = stack.name || 'Error' + ': ' + stack.message
30
67
  each(stack.stack, function (frame) {
@@ -536,7 +536,7 @@ export function UUID(placeholder) {
536
536
  // 替换url包含数字的路由
537
537
  export function replaceNumberCharByPath(path) {
538
538
  if (path) {
539
- return path.replace(/\/([^\/]*)\d([^\/]*)/g, '/?')
539
+ return path.replace(/\/([^\/]*)\d([^\/]*)/g, '/?').replace(/\/$/g, '')
540
540
  } else {
541
541
  return ''
542
542
  }
@@ -1064,7 +1064,107 @@ export var getURLSearchParams = function (queryString) {
1064
1064
  }
1065
1065
  return args
1066
1066
  }
1067
+ function createCircularReferenceChecker() {
1068
+ if (typeof WeakSet !== 'undefined') {
1069
+ var set = new WeakSet()
1070
+ return {
1071
+ hasAlreadyBeenSeen(value) {
1072
+ var has = set.has(value)
1073
+ if (!has) {
1074
+ set.add(value)
1075
+ }
1076
+ return has
1077
+ },
1078
+ }
1079
+ }
1080
+ var array = []
1081
+ return {
1082
+ hasAlreadyBeenSeen(value) {
1083
+ var has = array.indexOf(value) >= 0
1084
+ if (!has) {
1085
+ array.push(value)
1086
+ }
1087
+ return has
1088
+ },
1089
+ }
1090
+ }
1091
+ /**
1092
+ * Similar to `typeof`, but distinguish plain objects from `null` and arrays
1093
+ */
1094
+ export function getType(value) {
1095
+ if (value === null) {
1096
+ return 'null'
1097
+ }
1098
+ if (Array.isArray(value)) {
1099
+ return 'array'
1100
+ }
1101
+ return typeof value
1102
+ }
1103
+ /**
1104
+ * Iterate over source and affect its sub values into destination, recursively.
1105
+ * If the source and destination can't be merged, return source.
1106
+ */
1107
+ export function mergeInto(
1108
+ destination,
1109
+ source,
1110
+ circularReferenceChecker
1111
+ ) {
1112
+ // ignore the source if it is undefined
1113
+ if (typeof circularReferenceChecker === 'undefined') {
1114
+ circularReferenceChecker = createCircularReferenceChecker()
1115
+ }
1116
+ if (source === undefined) {
1117
+ return destination
1118
+ }
1119
+
1120
+ if (typeof source !== 'object' || source === null) {
1121
+ // primitive values - just return source
1122
+ return source
1123
+ } else if (source instanceof Date) {
1124
+ return new Date(source.getTime())
1125
+ } else if (source instanceof RegExp) {
1126
+ var flags =
1127
+ source.flags ||
1128
+ // old browsers compatibility
1129
+ [
1130
+ source.global ? 'g' : '',
1131
+ source.ignoreCase ? 'i' : '',
1132
+ source.multiline ? 'm' : '',
1133
+ source.sticky ? 'y' : '',
1134
+ source.unicode ? 'u' : '',
1135
+ ].join('')
1136
+ return new RegExp(source.source, flags)
1137
+ }
1138
+
1139
+ if (circularReferenceChecker.hasAlreadyBeenSeen(source)) {
1140
+ // remove circular references
1141
+ return undefined
1142
+ } else if (Array.isArray(source)) {
1143
+ var merged= Array.isArray(destination) ? destination : []
1144
+ for (var i = 0; i < source.length; ++i) {
1145
+ merged[i] = mergeInto(merged[i], source[i], circularReferenceChecker)
1146
+ }
1147
+ return merged
1148
+ }
1149
+
1150
+ var merged = getType(destination) === 'object' ? destination : {}
1151
+ for (var key in source) {
1152
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1153
+ merged[key] = mergeInto(merged[key], source[key], circularReferenceChecker)
1154
+ }
1155
+ }
1156
+ return merged
1157
+ }
1067
1158
 
1159
+ /**
1160
+ * A simplistic implementation of a deep clone algorithm.
1161
+ * Caveats:
1162
+ * - It doesn't maintain prototype chains - don't use with instances of custom classes.
1163
+ * - It doesn't handle Map and Set
1164
+ */
1165
+ export function deepClone(value){
1166
+ return mergeInto(undefined, value)
1167
+ }
1068
1168
  export var _URL = function (url) {
1069
1169
  var result = {}
1070
1170
  var basicProps = [