flutter.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. import {Fragment} from 'react';
  2. import {Alert} from 'sentry/components/core/alert';
  3. import ExternalLink from 'sentry/components/links/externalLink';
  4. import List from 'sentry/components/list';
  5. import ListItem from 'sentry/components/list/listItem';
  6. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  7. import type {
  8. BasePlatformOptions,
  9. Docs,
  10. DocsParams,
  11. OnboardingConfig,
  12. } from 'sentry/components/onboarding/gettingStartedDoc/types';
  13. import {
  14. getReplayMobileConfigureDescription,
  15. getReplayVerifyStep,
  16. } from 'sentry/components/onboarding/gettingStartedDoc/utils/replayOnboarding';
  17. import {feedbackOnboardingCrashApiDart} from 'sentry/gettingStartedDocs/dart/dart';
  18. import {t, tct} from 'sentry/locale';
  19. import {getPackageVersion} from 'sentry/utils/gettingStartedDocs/getPackageVersion';
  20. import {getWizardInstallSnippet} from 'sentry/utils/gettingStartedDocs/mobileWizard';
  21. export enum InstallationMode {
  22. AUTO = 'auto',
  23. MANUAL = 'manual',
  24. }
  25. const platformOptions = {
  26. installationMode: {
  27. label: t('Installation Mode'),
  28. items: [
  29. {
  30. label: t('Auto'),
  31. value: InstallationMode.AUTO,
  32. },
  33. {
  34. label: t('Manual'),
  35. value: InstallationMode.MANUAL,
  36. },
  37. ],
  38. defaultValue:
  39. navigator.userAgent.indexOf('Win') !== -1
  40. ? InstallationMode.MANUAL
  41. : InstallationMode.AUTO,
  42. },
  43. } satisfies BasePlatformOptions;
  44. type PlatformOptions = typeof platformOptions;
  45. type Params = DocsParams<PlatformOptions>;
  46. const isAutoInstall = (params: Params) =>
  47. params.platformOptions?.installationMode === InstallationMode.AUTO;
  48. const getManualInstallSnippet = (params: Params) => {
  49. const version = getPackageVersion(params, 'sentry.dart.flutter', '8.13.2');
  50. return `dependencies:
  51. sentry_flutter: ^${version}`;
  52. };
  53. const getConfigureSnippet = (params: Params) => `
  54. import 'package:sentry_flutter/sentry_flutter.dart';
  55. Future<void> main() async {
  56. await SentryFlutter.init(
  57. (options) {
  58. options.dsn = '${params.dsn.public}';${
  59. params.isPerformanceSelected
  60. ? `
  61. // Set tracesSampleRate to 1.0 to capture 100% of transactions for tracing.
  62. // We recommend adjusting this value in production.
  63. options.tracesSampleRate = 1.0;`
  64. : ''
  65. }${
  66. params.isProfilingSelected
  67. ? `
  68. // The sampling rate for profiling is relative to tracesSampleRate
  69. // Setting to 1.0 will profile 100% of sampled transactions:
  70. options.profilesSampleRate = 1.0;`
  71. : ''
  72. }
  73. },
  74. appRunner: () => runApp(
  75. SentryWidget(
  76. child: MyApp(),
  77. ),
  78. ),
  79. );
  80. // or define SENTRY_DSN via Dart environment variable (--dart-define)
  81. }`;
  82. const configureAdditionalInfo = tct(
  83. 'You can configure the [code: SENTRY_DSN], [code: SENTRY_RELEASE], [code: SENTRY_DIST], and [code: SENTRY_ENVIRONMENT] via the Dart environment variables passing the [code: --dart-define] flag to the compiler, as noted in the code sample.',
  84. {
  85. code: <code />,
  86. }
  87. );
  88. const getVerifySnippet = () => `
  89. child: ElevatedButton(
  90. onPressed: () {
  91. throw Exception('This is test exception');
  92. },
  93. child: const Text('Verify Sentry Setup'),
  94. )
  95. `;
  96. const getPerformanceSnippet = () => `
  97. import 'package:sentry/sentry.dart';
  98. void execute() async {
  99. final transaction = Sentry.startTransaction('processOrderBatch()', 'task');
  100. try {
  101. await processOrderBatch(transaction);
  102. } catch (exception) {
  103. transaction.throwable = exception;
  104. transaction.status = const SpanStatus.internalError();
  105. } finally {
  106. await transaction.finish();
  107. }
  108. }
  109. Future<void> processOrderBatch(ISentrySpan span) async {
  110. // span operation: task, span description: operation
  111. final innerSpan = span.startChild('task', description: 'operation');
  112. try {
  113. // omitted code
  114. } catch (exception) {
  115. innerSpan.throwable = exception;
  116. innerSpan.status = const SpanStatus.notFound();
  117. } finally {
  118. await innerSpan.finish();
  119. }
  120. }`;
  121. const getInstallReplaySnippet = () => `
  122. await SentryFlutter.init(
  123. (options) {
  124. ...
  125. options.experimental.replay.sessionSampleRate = 1.0;
  126. options.experimental.replay.onErrorSampleRate = 1.0;
  127. },
  128. appRunner: () => runApp(
  129. SentryWidget(
  130. child: MyApp(),
  131. ),
  132. ),
  133. );
  134. `;
  135. const getConfigureReplaySnippet = () => `
  136. options.experimental.replay.maskAllText = true;
  137. options.experimental.replay.maskAllImages = true;`;
  138. const onboarding: OnboardingConfig<PlatformOptions> = {
  139. install: params =>
  140. isAutoInstall(params)
  141. ? [
  142. {
  143. type: StepType.INSTALL,
  144. description: tct(
  145. 'Add Sentry automatically to your app with the [wizardLink:Sentry wizard] (call this inside your project directory).',
  146. {
  147. wizardLink: (
  148. <ExternalLink href="https://docs.sentry.io/platforms/flutter/#install" />
  149. ),
  150. }
  151. ),
  152. configurations: [
  153. {
  154. code: getWizardInstallSnippet({
  155. platform: 'flutter',
  156. params,
  157. }),
  158. },
  159. {
  160. description: (
  161. <Fragment>
  162. <p>
  163. {t(
  164. 'The Sentry wizard will automatically patch your project with the following:'
  165. )}
  166. </p>
  167. <List symbol="bullet">
  168. <ListItem>
  169. {tct(
  170. 'Configure the SDK with your DSN and performance monitoring options in your [main:main.dart] file.',
  171. {
  172. main: <code />,
  173. }
  174. )}
  175. </ListItem>
  176. <ListItem>
  177. {tct(
  178. 'Update your [pubspec:pubspec.yaml] with the Sentry package',
  179. {
  180. pubspec: <code />,
  181. }
  182. )}
  183. </ListItem>
  184. <ListItem>
  185. {t('Add an example error to verify your setup')}
  186. </ListItem>
  187. </List>
  188. </Fragment>
  189. ),
  190. },
  191. ],
  192. },
  193. ]
  194. : [
  195. {
  196. type: StepType.INSTALL,
  197. description: tct(
  198. 'Sentry captures data by using an SDK within your application. Add the following to your [pubspec:pubspec.yaml]',
  199. {
  200. pubspec: <code />,
  201. }
  202. ),
  203. configurations: [
  204. {
  205. code: [
  206. {
  207. label: 'YAML',
  208. value: 'yaml',
  209. language: 'yaml',
  210. filename: 'pubspec.yaml',
  211. partialLoading: params.sourcePackageRegistries?.isLoading,
  212. code: getManualInstallSnippet(params),
  213. },
  214. ],
  215. },
  216. ],
  217. },
  218. ],
  219. configure: params =>
  220. isAutoInstall(params)
  221. ? []
  222. : [
  223. {
  224. type: StepType.CONFIGURE,
  225. description: tct(
  226. 'Import [sentryFlutter: sentry_flutter] and initialize it in your [main:main.dart]',
  227. {
  228. sentryFlutter: <code />,
  229. main: <code />,
  230. }
  231. ),
  232. configurations: [
  233. ...(params.isProfilingSelected
  234. ? [
  235. {
  236. description: t(
  237. 'Flutter Profiling alpha is available for iOS and macOS since SDK version 7.12.0.'
  238. ),
  239. },
  240. ]
  241. : []),
  242. {
  243. code: [
  244. {
  245. label: 'Dart',
  246. value: 'dart',
  247. language: 'dart',
  248. filename: 'main.dart',
  249. code: getConfigureSnippet(params),
  250. },
  251. ],
  252. additionalInfo: params.isPerformanceSelected ? (
  253. <Fragment>
  254. <p>{configureAdditionalInfo}</p>
  255. <Alert type="info">
  256. {t(
  257. 'To monitor performance, you need to add extra instrumentation as described in the Tracing section below.'
  258. )}
  259. </Alert>
  260. </Fragment>
  261. ) : (
  262. configureAdditionalInfo
  263. ),
  264. },
  265. ],
  266. },
  267. ],
  268. verify: params =>
  269. isAutoInstall(params)
  270. ? []
  271. : [
  272. {
  273. type: StepType.VERIFY,
  274. description: t(
  275. 'Create an intentional error, so you can test that everything is working. In the example below, pressing the button will throw an exception:'
  276. ),
  277. configurations: [
  278. {
  279. code: [
  280. {
  281. label: 'Dart',
  282. value: 'dart',
  283. language: 'dart',
  284. code: getVerifySnippet(),
  285. },
  286. ],
  287. },
  288. ],
  289. },
  290. ...(params.isPerformanceSelected
  291. ? [
  292. {
  293. title: t('Tracing'),
  294. description: t(
  295. "You'll be able to monitor the performance of your app using the SDK. For example:"
  296. ),
  297. configurations: [
  298. {
  299. code: [
  300. {
  301. label: 'Dart',
  302. value: 'dart',
  303. language: 'dart',
  304. code: getPerformanceSnippet(),
  305. },
  306. ],
  307. additionalInfo: tct(
  308. 'To learn more about the API and automatic instrumentations, check out the [perfDocs: tracing documentation].',
  309. {
  310. perfDocs: (
  311. <ExternalLink href="https://docs.sentry.io/platforms/flutter/tracing/instrumentation/" />
  312. ),
  313. }
  314. ),
  315. },
  316. ],
  317. },
  318. ]
  319. : []),
  320. ],
  321. nextSteps: () => [
  322. {
  323. name: t('Upload Debug Symbols'),
  324. description: t(
  325. 'We offer a range of methods to provide Sentry with debug symbols so that you can see symbolicated stack traces and find the cause of your errors faster.'
  326. ),
  327. link: 'https://docs.sentry.io/platforms/flutter/upload-debug/',
  328. },
  329. {
  330. name: t('Distributed Tracing'),
  331. description: t(
  332. 'Connect all your services by configuring your endpoints in the Sentry init.'
  333. ),
  334. link: 'https://docs.sentry.io/platforms/flutter/tracing/trace-propagation/limiting-trace-propagation/',
  335. },
  336. {
  337. name: t('Connect your Git Repo'),
  338. description: t(
  339. 'Adding our Git integrations will allow us determine suspect commits, comment on PRs, and create links directly to your source code from Sentry issues.'
  340. ),
  341. link: 'https://docs.sentry.io/organization/integrations/source-code-mgmt/',
  342. },
  343. ],
  344. };
  345. const replayOnboarding: OnboardingConfig<PlatformOptions> = {
  346. install: params => [
  347. {
  348. type: StepType.INSTALL,
  349. description: tct(
  350. 'Make sure your Sentry Flutter SDK version is at least 8.9.0, which is required for Session Replay. You can update your [code:pubspec.yaml] to the matching version:',
  351. {code: <code />}
  352. ),
  353. configurations: [
  354. {
  355. code: [
  356. {
  357. label: 'YAML',
  358. value: 'yaml',
  359. language: 'yaml',
  360. code: getManualInstallSnippet(params),
  361. },
  362. ],
  363. },
  364. {
  365. description: t(
  366. 'To set up the integration, add the following to your Sentry initialization:'
  367. ),
  368. },
  369. {
  370. code: [
  371. {
  372. label: 'Dart',
  373. value: 'dart',
  374. language: 'dart',
  375. code: getInstallReplaySnippet(),
  376. },
  377. ],
  378. },
  379. ],
  380. },
  381. ],
  382. configure: () => [
  383. {
  384. type: StepType.CONFIGURE,
  385. description: getReplayMobileConfigureDescription({
  386. link: 'https://docs.sentry.io/platforms/flutter/session-replay/#privacy',
  387. }),
  388. configurations: [
  389. {
  390. description: t(
  391. 'The following code is the default configuration, which masks and blocks everything.'
  392. ),
  393. code: [
  394. {
  395. label: 'Dart',
  396. value: 'dart',
  397. language: 'dart',
  398. code: getConfigureReplaySnippet(),
  399. },
  400. ],
  401. },
  402. ],
  403. },
  404. ],
  405. verify: getReplayVerifyStep({
  406. replayOnErrorSampleRateName:
  407. 'options\u200b.experimental\u200b.sessionReplay\u200b.onErrorSampleRate',
  408. replaySessionSampleRateName:
  409. 'options\u200b.experimental\u200b.sessionReplay\u200b.sessionSampleRate',
  410. }),
  411. nextSteps: () => [],
  412. };
  413. const docs: Docs<PlatformOptions> = {
  414. onboarding,
  415. feedbackOnboardingCrashApi: feedbackOnboardingCrashApiDart,
  416. crashReportOnboarding: feedbackOnboardingCrashApiDart,
  417. platformOptions,
  418. replayOnboarding,
  419. };
  420. export default docs;