long-stack-trace-zone.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /**
  2. * @license
  3. * Copyright Google Inc. All Rights Reserved.
  4. *
  5. * Use of this source code is governed by an MIT-style license that can be
  6. * found in the LICENSE file at https://angular.io/license
  7. */
  8. (function (global, factory) {
  9. typeof exports === 'object' && typeof module !== 'undefined' ? factory() :
  10. typeof define === 'function' && define.amd ? define(factory) :
  11. (factory());
  12. }(this, (function () { 'use strict';
  13. /**
  14. * @license
  15. * Copyright Google Inc. All Rights Reserved.
  16. *
  17. * Use of this source code is governed by an MIT-style license that can be
  18. * found in the LICENSE file at https://angular.io/license
  19. */
  20. /**
  21. * @fileoverview
  22. * @suppress {globalThis}
  23. */
  24. var __assign = (undefined && undefined.__assign) || function () {
  25. __assign = Object.assign || function(t) {
  26. for (var s, i = 1, n = arguments.length; i < n; i++) {
  27. s = arguments[i];
  28. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  29. t[p] = s[p];
  30. }
  31. return t;
  32. };
  33. return __assign.apply(this, arguments);
  34. };
  35. var NEWLINE = '\n';
  36. var IGNORE_FRAMES = {};
  37. var creationTrace = '__creationTrace__';
  38. var ERROR_TAG = 'STACKTRACE TRACKING';
  39. var SEP_TAG = '__SEP_TAG__';
  40. var sepTemplate = SEP_TAG + '@[native]';
  41. var LongStackTrace = /** @class */ (function () {
  42. function LongStackTrace() {
  43. this.error = getStacktrace();
  44. this.timestamp = new Date();
  45. }
  46. return LongStackTrace;
  47. }());
  48. function getStacktraceWithUncaughtError() {
  49. return new Error(ERROR_TAG);
  50. }
  51. function getStacktraceWithCaughtError() {
  52. try {
  53. throw getStacktraceWithUncaughtError();
  54. }
  55. catch (err) {
  56. return err;
  57. }
  58. }
  59. // Some implementations of exception handling don't create a stack trace if the exception
  60. // isn't thrown, however it's faster not to actually throw the exception.
  61. var error = getStacktraceWithUncaughtError();
  62. var caughtError = getStacktraceWithCaughtError();
  63. var getStacktrace = error.stack ?
  64. getStacktraceWithUncaughtError :
  65. (caughtError.stack ? getStacktraceWithCaughtError : getStacktraceWithUncaughtError);
  66. function getFrames(error) {
  67. return error.stack ? error.stack.split(NEWLINE) : [];
  68. }
  69. function addErrorStack(lines, error) {
  70. var trace = getFrames(error);
  71. for (var i = 0; i < trace.length; i++) {
  72. var frame = trace[i];
  73. // Filter out the Frames which are part of stack capturing.
  74. if (!IGNORE_FRAMES.hasOwnProperty(frame)) {
  75. lines.push(trace[i]);
  76. }
  77. }
  78. }
  79. function renderLongStackTrace(frames, stack) {
  80. var longTrace = [stack ? stack.trim() : ''];
  81. if (frames) {
  82. var timestamp = new Date().getTime();
  83. for (var i = 0; i < frames.length; i++) {
  84. var traceFrames = frames[i];
  85. var lastTime = traceFrames.timestamp;
  86. var separator = "____________________Elapsed " + (timestamp - lastTime.getTime()) + " ms; At: " + lastTime;
  87. separator = separator.replace(/[^\w\d]/g, '_');
  88. longTrace.push(sepTemplate.replace(SEP_TAG, separator));
  89. addErrorStack(longTrace, traceFrames.error);
  90. timestamp = lastTime.getTime();
  91. }
  92. }
  93. return longTrace.join(NEWLINE);
  94. }
  95. Zone['longStackTraceZoneSpec'] = {
  96. name: 'long-stack-trace',
  97. longStackTraceLimit: 10,
  98. // add a getLongStackTrace method in spec to
  99. // handle handled reject promise error.
  100. getLongStackTrace: function (error) {
  101. if (!error) {
  102. return undefined;
  103. }
  104. var trace = error[Zone.__symbol__('currentTaskTrace')];
  105. if (!trace) {
  106. return error.stack;
  107. }
  108. return renderLongStackTrace(trace, error.stack);
  109. },
  110. onScheduleTask: function (parentZoneDelegate, currentZone, targetZone, task) {
  111. if (Error.stackTraceLimit > 0) {
  112. // if Error.stackTraceLimit is 0, means stack trace
  113. // is disabled, so we don't need to generate long stack trace
  114. // this will improve performance in some test(some test will
  115. // set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698
  116. var currentTask = Zone.currentTask;
  117. var trace = currentTask && currentTask.data && currentTask.data[creationTrace] || [];
  118. trace = [new LongStackTrace()].concat(trace);
  119. if (trace.length > this.longStackTraceLimit) {
  120. trace.length = this.longStackTraceLimit;
  121. }
  122. if (!task.data)
  123. task.data = {};
  124. if (task.type === 'eventTask') {
  125. // Fix issue https://github.com/angular/zone.js/issues/1195,
  126. // For event task of browser, by default, all task will share a
  127. // singleton instance of data object, we should create a new one here
  128. // The cast to `any` is required to workaround a closure bug which wrongly applies
  129. // URL sanitization rules to .data access.
  130. task.data = __assign({}, task.data);
  131. }
  132. task.data[creationTrace] = trace;
  133. }
  134. return parentZoneDelegate.scheduleTask(targetZone, task);
  135. },
  136. onHandleError: function (parentZoneDelegate, currentZone, targetZone, error) {
  137. if (Error.stackTraceLimit > 0) {
  138. // if Error.stackTraceLimit is 0, means stack trace
  139. // is disabled, so we don't need to generate long stack trace
  140. // this will improve performance in some test(some test will
  141. // set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698
  142. var parentTask = Zone.currentTask || error.task;
  143. if (error instanceof Error && parentTask) {
  144. var longStack = renderLongStackTrace(parentTask.data && parentTask.data[creationTrace], error.stack);
  145. try {
  146. error.stack = error.longStack = longStack;
  147. }
  148. catch (err) {
  149. }
  150. }
  151. }
  152. return parentZoneDelegate.handleError(targetZone, error);
  153. }
  154. };
  155. function captureStackTraces(stackTraces, count) {
  156. if (count > 0) {
  157. stackTraces.push(getFrames((new LongStackTrace()).error));
  158. captureStackTraces(stackTraces, count - 1);
  159. }
  160. }
  161. function computeIgnoreFrames() {
  162. if (Error.stackTraceLimit <= 0) {
  163. return;
  164. }
  165. var frames = [];
  166. captureStackTraces(frames, 2);
  167. var frames1 = frames[0];
  168. var frames2 = frames[1];
  169. for (var i = 0; i < frames1.length; i++) {
  170. var frame1 = frames1[i];
  171. if (frame1.indexOf(ERROR_TAG) == -1) {
  172. var match = frame1.match(/^\s*at\s+/);
  173. if (match) {
  174. sepTemplate = match[0] + SEP_TAG + ' (http://localhost)';
  175. break;
  176. }
  177. }
  178. }
  179. for (var i = 0; i < frames1.length; i++) {
  180. var frame1 = frames1[i];
  181. var frame2 = frames2[i];
  182. if (frame1 === frame2) {
  183. IGNORE_FRAMES[frame1] = true;
  184. }
  185. else {
  186. break;
  187. }
  188. }
  189. }
  190. computeIgnoreFrames();
  191. })));