initializeSdk.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import {browserHistory, createRoutes, match} from 'react-router';
  2. import {ExtraErrorData} from '@sentry/integrations';
  3. import * as Sentry from '@sentry/react';
  4. import SentryRRWeb from '@sentry/rrweb';
  5. import {Integrations} from '@sentry/tracing';
  6. import {_browserPerformanceTimeOriginMode} from '@sentry/utils';
  7. import {DISABLE_RR_WEB, SENTRY_RELEASE_VERSION, SPA_DSN} from 'sentry/constants';
  8. import {Config} from 'sentry/types';
  9. import {
  10. initializeMeasureAssetsTimeout,
  11. LongTaskObserver,
  12. } from 'sentry/utils/performanceForSentry';
  13. const SPA_MODE_ALLOW_URLS = [
  14. 'localhost',
  15. 'dev.getsentry.net',
  16. 'sentry.dev',
  17. 'webpack-internal://',
  18. ];
  19. /**
  20. * We accept a routes argument here because importing `static/routes`
  21. * is expensive in regards to bundle size. Some entrypoints may opt to forgo
  22. * having routing instrumentation in order to have a smaller bundle size.
  23. * (e.g. `static/views/integrationPipeline`)
  24. */
  25. function getSentryIntegrations(
  26. sentryConfig: Config['sentryConfig'],
  27. hasReplays: boolean = false,
  28. routes?: Function
  29. ) {
  30. const extraTracingOrigins = SPA_DSN
  31. ? SPA_MODE_ALLOW_URLS
  32. : [...sentryConfig?.whitelistUrls];
  33. const partialTracingOptions: Partial<Integrations.BrowserTracing['options']> = {
  34. tracingOrigins: ['localhost', /^\//, ...extraTracingOrigins],
  35. };
  36. const integrations = [
  37. new ExtraErrorData({
  38. // 6 is arbitrary, seems like a nice number
  39. depth: 6,
  40. }),
  41. new Integrations.BrowserTracing({
  42. ...(typeof routes === 'function'
  43. ? {
  44. routingInstrumentation: Sentry.reactRouterV3Instrumentation(
  45. browserHistory as any,
  46. createRoutes(routes()),
  47. match
  48. ),
  49. }
  50. : {}),
  51. idleTimeout: 5000,
  52. _metricOptions: {
  53. _reportAllChanges: false,
  54. },
  55. ...partialTracingOptions,
  56. }),
  57. ];
  58. if (hasReplays) {
  59. // eslint-disable-next-line no-console
  60. console.log('[sentry] Instrumenting session with rrweb');
  61. // TODO(ts): The type returned by SentryRRWeb seems to be somewhat
  62. // incompatible. It's a newer plugin, so this can be expected, but we
  63. // should fix.
  64. integrations.push(
  65. new SentryRRWeb({
  66. checkoutEveryNms: 60 * 1000, // 60 seconds
  67. }) as any
  68. );
  69. }
  70. return integrations;
  71. }
  72. /**
  73. * Initialize the Sentry SDK
  74. *
  75. * If `routes` is passed, we will instrument react-router. Not all
  76. * entrypoints require this.
  77. */
  78. export function initializeSdk(config: Config, {routes}: {routes?: Function} = {}) {
  79. const {apmSampling, sentryConfig, userIdentity} = config;
  80. const tracesSampleRate = apmSampling ?? 0;
  81. const hasReplays = userIdentity?.isStaff && !DISABLE_RR_WEB;
  82. Sentry.init({
  83. ...sentryConfig,
  84. /**
  85. * For SPA mode, we need a way to overwrite the default DSN from backend
  86. * as well as `whitelistUrls`
  87. */
  88. dsn: SPA_DSN || sentryConfig?.dsn,
  89. /**
  90. * Frontend can be built with a `SENTRY_RELEASE_VERSION` environment variable for release string, useful if frontend is
  91. * deployed separately from backend.
  92. */
  93. release: SENTRY_RELEASE_VERSION ?? sentryConfig?.release,
  94. allowUrls: SPA_DSN ? SPA_MODE_ALLOW_URLS : sentryConfig?.whitelistUrls,
  95. integrations: getSentryIntegrations(sentryConfig, hasReplays, routes),
  96. tracesSampleRate,
  97. /**
  98. * There is a bug in Safari, that causes `AbortError` when fetch is aborted, and you are in the middle of reading the response.
  99. * In Chrome and other browsers, it is handled gracefully, where in Safari, it produces additional error, that is jumping
  100. * outside of the original Promise chain and bubbles up to the `unhandledRejection` handler, that we then captures as error.
  101. * Ref: https://bugs.webkit.org/show_bug.cgi?id=215771
  102. */
  103. ignoreErrors: ['AbortError: Fetch is aborted'],
  104. });
  105. // Track timeOrigin Selection by the SDK to see if it improves transaction durations
  106. Sentry.addGlobalEventProcessor((event: Sentry.Event, _hint?: Sentry.EventHint) => {
  107. event.tags = event.tags || {};
  108. event.tags['timeOrigin.mode'] = _browserPerformanceTimeOriginMode;
  109. return event;
  110. });
  111. if (userIdentity) {
  112. Sentry.setUser(userIdentity);
  113. }
  114. if (window.__SENTRY__VERSION) {
  115. Sentry.setTag('sentry_version', window.__SENTRY__VERSION);
  116. }
  117. Sentry.setTag('rrweb.active', hasReplays ? 'yes' : 'no');
  118. LongTaskObserver.startPerformanceObserver();
  119. initializeMeasureAssetsTimeout();
  120. }