react-native.tsx 16 KB

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