globalhandlers.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. Object.defineProperty(exports, '__esModule', { value: true });
  2. const core = require('@sentry/core');
  3. const utils = require('@sentry/utils');
  4. const debugBuild = require('../debug-build.js');
  5. const eventbuilder = require('../eventbuilder.js');
  6. const helpers = require('../helpers.js');
  7. /* eslint-disable @typescript-eslint/no-unsafe-member-access */
  8. const INTEGRATION_NAME = 'GlobalHandlers';
  9. const _globalHandlersIntegration = ((options = {}) => {
  10. const _options = {
  11. onerror: true,
  12. onunhandledrejection: true,
  13. ...options,
  14. };
  15. return {
  16. name: INTEGRATION_NAME,
  17. setupOnce() {
  18. Error.stackTraceLimit = 50;
  19. },
  20. setup(client) {
  21. if (_options.onerror) {
  22. _installGlobalOnErrorHandler(client);
  23. globalHandlerLog('onerror');
  24. }
  25. if (_options.onunhandledrejection) {
  26. _installGlobalOnUnhandledRejectionHandler(client);
  27. globalHandlerLog('onunhandledrejection');
  28. }
  29. },
  30. };
  31. }) ;
  32. const globalHandlersIntegration = core.defineIntegration(_globalHandlersIntegration);
  33. /**
  34. * Global handlers.
  35. * @deprecated Use `globalHandlersIntegration()` instead.
  36. */
  37. // eslint-disable-next-line deprecation/deprecation
  38. const GlobalHandlers = core.convertIntegrationFnToClass(
  39. INTEGRATION_NAME,
  40. globalHandlersIntegration,
  41. )
  42. ;
  43. function _installGlobalOnErrorHandler(client) {
  44. utils.addGlobalErrorInstrumentationHandler(data => {
  45. const { stackParser, attachStacktrace } = getOptions();
  46. if (core.getClient() !== client || helpers.shouldIgnoreOnError()) {
  47. return;
  48. }
  49. const { msg, url, line, column, error } = data;
  50. const event =
  51. error === undefined && utils.isString(msg)
  52. ? _eventFromIncompleteOnError(msg, url, line, column)
  53. : _enhanceEventWithInitialFrame(
  54. eventbuilder.eventFromUnknownInput(stackParser, error || msg, undefined, attachStacktrace, false),
  55. url,
  56. line,
  57. column,
  58. );
  59. event.level = 'error';
  60. core.captureEvent(event, {
  61. originalException: error,
  62. mechanism: {
  63. handled: false,
  64. type: 'onerror',
  65. },
  66. });
  67. });
  68. }
  69. function _installGlobalOnUnhandledRejectionHandler(client) {
  70. utils.addGlobalUnhandledRejectionInstrumentationHandler(e => {
  71. const { stackParser, attachStacktrace } = getOptions();
  72. if (core.getClient() !== client || helpers.shouldIgnoreOnError()) {
  73. return;
  74. }
  75. const error = _getUnhandledRejectionError(e );
  76. const event = utils.isPrimitive(error)
  77. ? _eventFromRejectionWithPrimitive(error)
  78. : eventbuilder.eventFromUnknownInput(stackParser, error, undefined, attachStacktrace, true);
  79. event.level = 'error';
  80. core.captureEvent(event, {
  81. originalException: error,
  82. mechanism: {
  83. handled: false,
  84. type: 'onunhandledrejection',
  85. },
  86. });
  87. });
  88. }
  89. function _getUnhandledRejectionError(error) {
  90. if (utils.isPrimitive(error)) {
  91. return error;
  92. }
  93. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  94. const e = error ;
  95. // dig the object of the rejection out of known event types
  96. try {
  97. // PromiseRejectionEvents store the object of the rejection under 'reason'
  98. // see https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent
  99. if ('reason' in e) {
  100. return e.reason;
  101. }
  102. // something, somewhere, (likely a browser extension) effectively casts PromiseRejectionEvents
  103. // to CustomEvents, moving the `promise` and `reason` attributes of the PRE into
  104. // the CustomEvent's `detail` attribute, since they're not part of CustomEvent's spec
  105. // see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent and
  106. // https://github.com/getsentry/sentry-javascript/issues/2380
  107. else if ('detail' in e && 'reason' in e.detail) {
  108. return e.detail.reason;
  109. }
  110. } catch (e2) {} // eslint-disable-line no-empty
  111. return error;
  112. }
  113. /**
  114. * Create an event from a promise rejection where the `reason` is a primitive.
  115. *
  116. * @param reason: The `reason` property of the promise rejection
  117. * @returns An Event object with an appropriate `exception` value
  118. */
  119. function _eventFromRejectionWithPrimitive(reason) {
  120. return {
  121. exception: {
  122. values: [
  123. {
  124. type: 'UnhandledRejection',
  125. // String() is needed because the Primitive type includes symbols (which can't be automatically stringified)
  126. value: `Non-Error promise rejection captured with value: ${String(reason)}`,
  127. },
  128. ],
  129. },
  130. };
  131. }
  132. /**
  133. * This function creates a stack from an old, error-less onerror handler.
  134. */
  135. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  136. function _eventFromIncompleteOnError(msg, url, line, column) {
  137. const ERROR_TYPES_RE =
  138. /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/i;
  139. // If 'message' is ErrorEvent, get real message from inside
  140. let message = utils.isErrorEvent(msg) ? msg.message : msg;
  141. let name = 'Error';
  142. const groups = message.match(ERROR_TYPES_RE);
  143. if (groups) {
  144. name = groups[1];
  145. message = groups[2];
  146. }
  147. const event = {
  148. exception: {
  149. values: [
  150. {
  151. type: name,
  152. value: message,
  153. },
  154. ],
  155. },
  156. };
  157. return _enhanceEventWithInitialFrame(event, url, line, column);
  158. }
  159. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  160. function _enhanceEventWithInitialFrame(event, url, line, column) {
  161. // event.exception
  162. const e = (event.exception = event.exception || {});
  163. // event.exception.values
  164. const ev = (e.values = e.values || []);
  165. // event.exception.values[0]
  166. const ev0 = (ev[0] = ev[0] || {});
  167. // event.exception.values[0].stacktrace
  168. const ev0s = (ev0.stacktrace = ev0.stacktrace || {});
  169. // event.exception.values[0].stacktrace.frames
  170. const ev0sf = (ev0s.frames = ev0s.frames || []);
  171. const colno = isNaN(parseInt(column, 10)) ? undefined : column;
  172. const lineno = isNaN(parseInt(line, 10)) ? undefined : line;
  173. const filename = utils.isString(url) && url.length > 0 ? url : utils.getLocationHref();
  174. // event.exception.values[0].stacktrace.frames
  175. if (ev0sf.length === 0) {
  176. ev0sf.push({
  177. colno,
  178. filename,
  179. function: '?',
  180. in_app: true,
  181. lineno,
  182. });
  183. }
  184. return event;
  185. }
  186. function globalHandlerLog(type) {
  187. debugBuild.DEBUG_BUILD && utils.logger.log(`Global Handler attached: ${type}`);
  188. }
  189. function getOptions() {
  190. const client = core.getClient();
  191. const options = (client && client.getOptions()) || {
  192. stackParser: () => [],
  193. attachStacktrace: false,
  194. };
  195. return options;
  196. }
  197. exports.GlobalHandlers = GlobalHandlers;
  198. exports.globalHandlersIntegration = globalHandlersIntegration;
  199. //# sourceMappingURL=globalhandlers.js.map