react-native.tsx 14 KB

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