react-native.tsx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. import {Fragment} from 'react';
  2. import ExternalLink from 'sentry/components/links/externalLink';
  3. import List from 'sentry/components/list/';
  4. import ListItem from 'sentry/components/list/listItem';
  5. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  6. import type {
  7. BasePlatformOptions,
  8. Docs,
  9. DocsParams,
  10. OnboardingConfig,
  11. } from 'sentry/components/onboarding/gettingStartedDoc/types';
  12. import {
  13. getCrashReportApiIntroduction,
  14. getCrashReportInstallDescription,
  15. } from 'sentry/components/onboarding/gettingStartedDoc/utils/feedbackOnboarding';
  16. import {
  17. getReplayMobileConfigureDescription,
  18. getReplayVerifyStep,
  19. } from 'sentry/components/onboarding/gettingStartedDoc/utils/replayOnboarding';
  20. import {t, tct} from 'sentry/locale';
  21. import {getInstallConfig} from 'sentry/utils/gettingStartedDocs/reactNative';
  22. export enum InstallationMode {
  23. AUTO = 'auto',
  24. MANUAL = 'manual',
  25. }
  26. const platformOptions = {
  27. installationMode: {
  28. label: t('Installation Mode'),
  29. items: [
  30. {
  31. label: t('Auto'),
  32. value: InstallationMode.AUTO,
  33. },
  34. {
  35. label: t('Manual'),
  36. value: InstallationMode.MANUAL,
  37. },
  38. ],
  39. defaultValue:
  40. navigator.userAgent.indexOf('Win') === -1
  41. ? InstallationMode.AUTO
  42. : InstallationMode.MANUAL,
  43. },
  44. } satisfies BasePlatformOptions;
  45. type PlatformOptions = typeof platformOptions;
  46. type Params = DocsParams<PlatformOptions>;
  47. const isAutoInstall = (params: Params) =>
  48. params.platformOptions?.installationMode === InstallationMode.AUTO;
  49. const getConfigureSnippet = (params: Params) => `
  50. import * as Sentry from "@sentry/react-native";
  51. Sentry.init({
  52. dsn: "${params.dsn.public}",
  53. // Adds more context data to events (IP address, cookies, user, etc.)
  54. // For more information, visit: https://docs.sentry.io/platforms/react-native/data-management/data-collected/
  55. sendDefaultPii: true,${
  56. params.isPerformanceSelected
  57. ? `
  58. // Set tracesSampleRate to 1.0 to capture 100% of transactions for tracing.
  59. // We recommend adjusting this value in production.
  60. tracesSampleRate: 1.0,`
  61. : ''
  62. }${
  63. params.isProfilingSelected
  64. ? `
  65. // profilesSampleRate is relative to tracesSampleRate.
  66. // Here, we'll capture profiles for 100% of transactions.
  67. profilesSampleRate: 1.0,`
  68. : ''
  69. }
  70. });`;
  71. const getPerformanceSnippet = () => `
  72. // Let's say this function is invoked when a user clicks on the checkout button of your shop
  73. shopCheckout() {
  74. // This will create a new Transaction for you
  75. const transaction = Sentry.startTransaction({ name: "shopCheckout" });
  76. // Set transaction on scope to associate with errors and get included span instrumentation
  77. // If there's currently an unfinished transaction, it may be dropped
  78. Sentry.getCurrentHub().configureScope(scope => scope.setSpan(transaction));
  79. // Assume this function makes an xhr/fetch call
  80. const result = validateShoppingCartOnServer();
  81. const span = transaction.startChild({
  82. data: {
  83. result
  84. },
  85. op: 'task',
  86. description: "processing shopping cart result",
  87. });
  88. try {
  89. processAndValidateShoppingCart(result);
  90. span.setStatus(SpanStatus.Ok);
  91. } catch (err) {
  92. span.setStatus(SpanStatus.UnknownError);
  93. throw err;
  94. } finally {
  95. span.finish();
  96. transaction.finish();
  97. }
  98. }`;
  99. const getReplaySetupSnippet = (params: Params) => `
  100. import * as Sentry from '@sentry/react-native';
  101. Sentry.init({
  102. dsn: "${params.dsn.public}",
  103. replaysSessionSampleRate: 0.1,
  104. replaysOnErrorSampleRate: 1.0,
  105. integrations: [
  106. Sentry.mobileReplayIntegration(),
  107. ],
  108. });`;
  109. const getReplayConfigurationSnippet = () => `
  110. Sentry.mobileReplayIntegration({
  111. maskAllText: true,
  112. maskAllImages: true,
  113. maskAllVectors: true,
  114. }),`;
  115. const onboarding: OnboardingConfig<PlatformOptions> = {
  116. install: params =>
  117. isAutoInstall(params)
  118. ? [
  119. {
  120. type: StepType.INSTALL,
  121. description: tct(
  122. 'Run [code:@sentry/wizard] to automatically configure your project:',
  123. {code: <code />}
  124. ),
  125. configurations: [
  126. {
  127. code: [
  128. {
  129. label: 'npx',
  130. value: 'npx',
  131. language: 'bash',
  132. code: `npx @sentry/wizard@latest -i reactNative ${params.isSelfHosted ? '' : '--saas'} --org ${params.organization.slug} --project ${params.projectSlug}`,
  133. },
  134. ],
  135. },
  136. {
  137. description: (
  138. <Fragment>
  139. <p>
  140. {t(
  141. 'The Sentry wizard will automatically patch your project with the following:'
  142. )}
  143. </p>
  144. <List symbol="bullet">
  145. <ListItem>{t('Configure the SDK with your DSN')}</ListItem>
  146. <ListItem>
  147. {t('Add source maps upload to your build process')}
  148. </ListItem>
  149. <ListItem>
  150. {t('Add debug symbols upload to your build process')}
  151. </ListItem>
  152. </List>
  153. </Fragment>
  154. ),
  155. },
  156. ],
  157. },
  158. ]
  159. : [
  160. {
  161. title: t('Install SDK Package'),
  162. description: t('Install the @sentry/react-native package:'),
  163. configurations: getInstallConfig(params, {
  164. basePackage: '@sentry/react-native',
  165. }),
  166. },
  167. ],
  168. configure: params =>
  169. isAutoInstall(params)
  170. ? []
  171. : [
  172. {
  173. type: StepType.CONFIGURE,
  174. configurations: [
  175. ...(params.isProfilingSelected
  176. ? [
  177. {
  178. description: t(
  179. 'React Native Profiling is available since SDK version 5.32.0.'
  180. ),
  181. },
  182. ]
  183. : []),
  184. {
  185. language: 'javascript',
  186. code: getConfigureSnippet(params),
  187. },
  188. {
  189. language: 'javascript',
  190. description: tct(
  191. 'Wrap your app with Sentry to automatically instrument it with [touchEventTrakingLink:touch event tracking] and [automaticPerformanceMonitoringLink:automatic tracing]:',
  192. {
  193. touchEventTrakingLink: (
  194. <ExternalLink href="https://docs.sentry.io/platforms/react-native/touchevents/" />
  195. ),
  196. automaticPerformanceMonitoringLink: (
  197. <ExternalLink href="https://docs.sentry.io/platforms/react-native/tracing/instrumentation/automatic-instrumentation/" />
  198. ),
  199. }
  200. ),
  201. code: 'export default Sentry.wrap(App);',
  202. additionalInfo: t(
  203. 'You do not need to do this for Sentry to work or if your app does not have a single parent "App" component.'
  204. ),
  205. },
  206. ],
  207. },
  208. ],
  209. verify: params =>
  210. isAutoInstall(params)
  211. ? []
  212. : [
  213. {
  214. type: StepType.VERIFY,
  215. description: t(
  216. 'Then create an intentional error, so you can test that everything is working:'
  217. ),
  218. configurations: [
  219. {
  220. language: 'javascript',
  221. code: "throw new Error('My first Sentry error!');",
  222. },
  223. {
  224. language: 'javascript',
  225. description: t('Or, try a native crash with:'),
  226. code: 'Sentry.nativeCrash();',
  227. additionalInfo: (
  228. <Fragment>
  229. {t(
  230. "If you're new to Sentry, use the email alert to access your account and complete a product tour."
  231. )}
  232. {t(
  233. "If you're an existing user and have disabled alerts, you won't receive this email."
  234. )}
  235. </Fragment>
  236. ),
  237. },
  238. ],
  239. },
  240. ...(params.isPerformanceSelected
  241. ? [
  242. {
  243. title: t('Tracing'),
  244. description: (
  245. <Fragment>
  246. {t(
  247. 'Sentry can measure the performance of your app automatically when instrumented with the following routers:'
  248. )}
  249. <List symbol="bullet">
  250. <ListItem>
  251. <ExternalLink href="https://docs.sentry.io/platforms/react-native/tracing/instrumentation/react-navigation/">
  252. {t('React Navigation')}
  253. </ExternalLink>
  254. </ListItem>
  255. <ListItem>
  256. <ExternalLink href="https://docs.sentry.io/platforms/react-native/tracing/instrumentation/react-navigation-v4/">
  257. {t('React Navigation V4 and prior')}
  258. </ExternalLink>
  259. </ListItem>
  260. <ListItem>
  261. <ExternalLink href="https://docs.sentry.io/platforms/react-native/tracing/instrumentation/react-native-navigation/">
  262. {t('React Native Navigation')}
  263. </ExternalLink>
  264. </ListItem>
  265. <ListItem>
  266. <ExternalLink href="https://docs.sentry.io/platforms/react-native/tracing/instrumentation/expo-router/">
  267. {t('Expo Router')}
  268. </ExternalLink>
  269. </ListItem>
  270. </List>
  271. {t(
  272. 'Additionally, you can create transactions and spans programatically:'
  273. )}
  274. </Fragment>
  275. ),
  276. configurations: [
  277. {
  278. description: t('For example:'),
  279. language: 'javascript',
  280. code: getPerformanceSnippet(),
  281. additionalInfo: tct(
  282. 'For more information, please refer to the [docLink: Sentry React Native documentation].',
  283. {
  284. docLink: (
  285. <ExternalLink href="https://docs.sentry.io/platforms/react-native/tracing/instrumentation/" />
  286. ),
  287. }
  288. ),
  289. },
  290. ],
  291. },
  292. ]
  293. : []),
  294. {
  295. title: t('Debug Symbols'),
  296. description: (
  297. <Fragment>
  298. {t(
  299. 'We offer a range of methods to provide Sentry with debug symbols so that you can see symbolicated stack traces and triage issues faster.'
  300. )}
  301. <p>
  302. {tct(
  303. "Complete stack traces will be shown for React Native Javascript errors by default using Sentry's [automaticSourceMapsUploadLink:automatic source maps upload]. To set up manual source maps upload follow [guideLink:this guide].",
  304. {
  305. automaticSourceMapsUploadLink: (
  306. <ExternalLink href="https://docs.sentry.io/platforms/react-native/sourcemaps/" />
  307. ),
  308. guideLink: (
  309. <ExternalLink href="https://docs.sentry.io/platforms/react-native/sourcemaps/" />
  310. ),
  311. }
  312. )}
  313. </p>
  314. <p>
  315. {tct(
  316. "You'll also need to upload [debugSymbolsLink:Debug Symbols] generated by the native iOS and Android tooling for native crashes.",
  317. {
  318. debugSymbolsLink: (
  319. <ExternalLink href="https://docs.sentry.io/platforms/react-native/upload-debug/" />
  320. ),
  321. }
  322. )}
  323. </p>
  324. </Fragment>
  325. ),
  326. },
  327. {
  328. title: t('Source Context'),
  329. description: (
  330. <Fragment>
  331. <p>
  332. {tct(
  333. "If Sentry has access to your application's source code, it can show snippets of code [italic:(source context)] around the location of stack frames, which helps to quickly pinpoint problematic code.",
  334. {
  335. italic: <i />,
  336. }
  337. )}
  338. </p>
  339. <p>
  340. {tct(
  341. 'Source Context will be shown for React Native Javascript error by default if source maps are uploaded. To set up source maps upload, follow the [sourceMapsGuideLink:Source Maps guide].',
  342. {
  343. sourceMapsGuideLink: (
  344. <ExternalLink href="https://docs.sentry.io/platforms/react-native/sourcemaps/" />
  345. ),
  346. }
  347. )}
  348. </p>
  349. <p>
  350. {tct(
  351. "To enable source context for native errors, you'll need to upload native debug symbols to Sentry by following the instructions at [uploadWithGradleLink:Uploading Source Code Context With Sentry Gradle Plugin] and Uploading Source Context With Xcode.",
  352. {
  353. uploadWithGradleLink: (
  354. <ExternalLink href="https://docs.sentry.io/platforms/react-native/upload-debug/#uploading-source-context-with-sentry-gradle-plugin" />
  355. ),
  356. uploadWithXCodeLink: (
  357. <ExternalLink href="https://docs.sentry.io/platforms/react-native/upload-debug/#uploading-source-context-with-xcode" />
  358. ),
  359. }
  360. )}
  361. </p>
  362. </Fragment>
  363. ),
  364. },
  365. ],
  366. nextSteps: params =>
  367. // i am abusing the isAutoInstall because i was tired of fighting with the Next Steps type definition
  368. isAutoInstall(params)
  369. ? [
  370. {
  371. name: t('React Navigation'),
  372. description: t('Set up automatic instrumentation with React Navigation'),
  373. link: 'https://docs.sentry.io/platforms/react-native/tracing/instrumentation/react-navigation/',
  374. },
  375. {
  376. name: t('React Native Navigation'),
  377. description: t(
  378. 'Set up automatic instrumentation with React Native Navigation'
  379. ),
  380. link: 'https://docs.sentry.io/platforms/react-native/tracing/instrumentation/react-native-navigation/',
  381. },
  382. {
  383. name: t('Expo Router'),
  384. description: t('Set up automatic instrumentation with Expo Router'),
  385. link: 'https://docs.sentry.io/platforms/react-native/tracing/instrumentation/expo-router/',
  386. },
  387. ]
  388. : [],
  389. };
  390. const feedbackOnboardingCrashApi: OnboardingConfig = {
  391. introduction: () => getCrashReportApiIntroduction(),
  392. install: () => [
  393. {
  394. type: StepType.INSTALL,
  395. description: getCrashReportInstallDescription(),
  396. configurations: [
  397. {
  398. code: [
  399. {
  400. label: 'TypeScript',
  401. value: 'typescript',
  402. language: 'typescript',
  403. code: `import * as Sentry from "@sentry/react-native";
  404. import { UserFeedback } from "@sentry/react-native";
  405. const sentryId = Sentry.captureMessage("My Message");
  406. // OR: const sentryId = Sentry.lastEventId();
  407. const userFeedback: UserFeedback = {
  408. event_id: sentryId,
  409. name: "John Doe",
  410. email: "john@doe.com",
  411. comments: "Hello World!",
  412. };
  413. Sentry.captureUserFeedback(userFeedback);`,
  414. },
  415. ],
  416. },
  417. ],
  418. },
  419. ],
  420. configure: () => [],
  421. verify: () => [],
  422. nextSteps: () => [],
  423. };
  424. const replayOnboarding: OnboardingConfig<PlatformOptions> = {
  425. install: (params: DocsParams<PlatformOptions>) => [
  426. {
  427. type: StepType.INSTALL,
  428. description: t(
  429. 'Make sure your Sentry React Native SDK version is at least 6.5.0. If you already have the SDK installed, you can update it to the latest version with:'
  430. ),
  431. configurations: [
  432. {
  433. code: [
  434. {
  435. label: 'npm',
  436. value: 'npm',
  437. language: 'bash',
  438. code: `npm install @sentry/react-native --save`,
  439. },
  440. {
  441. label: 'yarn',
  442. value: 'yarn',
  443. language: 'bash',
  444. code: `yarn add @sentry/react-native`,
  445. },
  446. {
  447. label: 'pnpm',
  448. value: 'pnpm',
  449. language: 'bash',
  450. code: `pnpm add @sentry/react-native`,
  451. },
  452. ],
  453. },
  454. {
  455. description: t(
  456. 'To set up the integration, add the following to your Sentry initialization:'
  457. ),
  458. },
  459. {
  460. code: [
  461. {
  462. label: 'JavaScript',
  463. value: 'javascript',
  464. language: 'javascript',
  465. code: getReplaySetupSnippet(params),
  466. },
  467. ],
  468. },
  469. ],
  470. },
  471. ],
  472. configure: () => [
  473. {
  474. type: StepType.CONFIGURE,
  475. description: getReplayMobileConfigureDescription({
  476. link: 'https://docs.sentry.io/platforms/react-native/session-replay/#privacy',
  477. }),
  478. configurations: [
  479. {
  480. description: t(
  481. 'The following code is the default configuration, which masks and blocks everything.'
  482. ),
  483. code: [
  484. {
  485. label: 'JavaScript',
  486. value: 'javascript',
  487. language: 'javascript',
  488. code: getReplayConfigurationSnippet(),
  489. },
  490. ],
  491. },
  492. ],
  493. },
  494. ],
  495. verify: getReplayVerifyStep(),
  496. nextSteps: () => [],
  497. };
  498. const docs: Docs<PlatformOptions> = {
  499. onboarding,
  500. feedbackOnboardingCrashApi,
  501. crashReportOnboarding: feedbackOnboardingCrashApi,
  502. replayOnboarding,
  503. platformOptions,
  504. };
  505. export default docs;