flutter.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import {Alert} from 'sentry/components/alert';
  4. import ExternalLink from 'sentry/components/links/externalLink';
  5. import Link from 'sentry/components/links/link';
  6. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  7. import type {
  8. Docs,
  9. DocsParams,
  10. OnboardingConfig,
  11. } from 'sentry/components/onboarding/gettingStartedDoc/types';
  12. import {MobileBetaBanner} from 'sentry/components/onboarding/gettingStartedDoc/utils';
  13. import exampleSnippets from 'sentry/components/onboarding/gettingStartedDoc/utils/metricsExampleSnippets';
  14. import {metricTagsExplanation} from 'sentry/components/onboarding/gettingStartedDoc/utils/metricsOnboarding';
  15. import {
  16. getReplayMobileConfigureDescription,
  17. getReplayVerifyStep,
  18. } from 'sentry/components/onboarding/gettingStartedDoc/utils/replayOnboarding';
  19. import {feedbackOnboardingCrashApiDart} from 'sentry/gettingStartedDocs/dart/dart';
  20. import {t, tct} from 'sentry/locale';
  21. import {getPackageVersion} from 'sentry/utils/gettingStartedDocs/getPackageVersion';
  22. type Params = DocsParams;
  23. const getInstallSnippet = (params: Params) => `
  24. dependencies:
  25. sentry_flutter: ^${getPackageVersion(params, 'sentry.dart.flutter', '7.8.0')}`;
  26. const getConfigureSnippet = (params: Params) => `
  27. import 'package:sentry_flutter/sentry_flutter.dart';
  28. Future<void> main() async {
  29. await SentryFlutter.init(
  30. (options) {
  31. options.dsn = '${params.dsn.public}';${
  32. params.isPerformanceSelected
  33. ? `
  34. // Set tracesSampleRate to 1.0 to capture 100% of transactions for tracing.
  35. // We recommend adjusting this value in production.
  36. options.tracesSampleRate = 1.0;`
  37. : ''
  38. }${
  39. params.isProfilingSelected
  40. ? `
  41. // The sampling rate for profiling is relative to tracesSampleRate
  42. // Setting to 1.0 will profile 100% of sampled transactions:
  43. options.profilesSampleRate = 1.0;`
  44. : ''
  45. }
  46. },
  47. appRunner: () => runApp(const MyApp()),
  48. );
  49. // or define SENTRY_DSN via Dart environment variable (--dart-define)
  50. }`;
  51. const configureAdditionalInfo = tct(
  52. '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.',
  53. {
  54. code: <code />,
  55. }
  56. );
  57. const getVerifySnippet = () => `
  58. child: ElevatedButton(
  59. onPressed: () {
  60. throw Exception('This is test exception');
  61. },
  62. child: const Text('Verify Sentry Setup'),
  63. )
  64. `;
  65. const getPerformanceSnippet = () => `
  66. import 'package:sentry/sentry.dart';
  67. void execute() async {
  68. final transaction = Sentry.startTransaction('processOrderBatch()', 'task');
  69. try {
  70. await processOrderBatch(transaction);
  71. } catch (exception) {
  72. transaction.throwable = exception;
  73. transaction.status = const SpanStatus.internalError();
  74. } finally {
  75. await transaction.finish();
  76. }
  77. }
  78. Future<void> processOrderBatch(ISentrySpan span) async {
  79. // span operation: task, span description: operation
  80. final innerSpan = span.startChild('task', description: 'operation');
  81. try {
  82. // omitted code
  83. } catch (exception) {
  84. innerSpan.throwable = exception;
  85. innerSpan.status = const SpanStatus.notFound();
  86. } finally {
  87. await innerSpan.finish();
  88. }
  89. }`;
  90. const getConfigureMetricsSnippet = (params: Params) => `
  91. import 'package:sentry_flutter/sentry_flutter.dart';
  92. Future<void> main() async {
  93. await SentryFlutter.init(
  94. (options) {
  95. options.dsn = '${params.dsn.public}';
  96. options.enableMetrics = true;
  97. },
  98. appRunner: initApp, // Init your App.
  99. );
  100. };`;
  101. const getInstallReplaySnippet = () => `
  102. await SentryFlutter.init(
  103. (options) {
  104. ...
  105. options.experimental.replay.sessionSampleRate = 1.0;
  106. options.experimental.replay.onErrorSampleRate = 1.0;
  107. },
  108. appRunner: () => runApp(MyApp()),
  109. );
  110. `;
  111. const getConfigureReplaySnippet = () => `
  112. options.experimental.replay.maskAllText = true;
  113. options.experimental.replay.maskAllImages = true;`;
  114. const metricsOnboarding: OnboardingConfig = {
  115. install: (params: DocsParams) => [
  116. {
  117. type: StepType.INSTALL,
  118. description: tct(
  119. 'You need Sentry Flutter SDK version [code:7.19.0] or higher. Learn more about installation methods in our [docsLink:full documentation].',
  120. {
  121. code: <code />,
  122. docsLink: <Link to={`/projects/${params.projectSlug}/getting-started/`} />,
  123. }
  124. ),
  125. configurations: [
  126. {
  127. language: 'yml',
  128. partialLoading: params.sourcePackageRegistries?.isLoading,
  129. code: getInstallSnippet(params),
  130. },
  131. ],
  132. },
  133. ],
  134. configure: (params: DocsParams) => [
  135. {
  136. type: StepType.CONFIGURE,
  137. description: t(
  138. 'To enable capturing metrics, you need to enable the metrics feature.'
  139. ),
  140. configurations: [
  141. {
  142. code: [
  143. {
  144. label: 'Dart',
  145. value: 'dart',
  146. language: 'dart',
  147. code: getConfigureMetricsSnippet(params),
  148. },
  149. ],
  150. },
  151. ],
  152. },
  153. ],
  154. verify: () => [
  155. {
  156. type: StepType.VERIFY,
  157. description: tct(
  158. "Then you'll be able to add metrics as [code:counters], [code:sets], [code:distributions], and [code:gauges]. These are available under the [code:Sentry.metrics()] namespace.",
  159. {
  160. code: <code />,
  161. }
  162. ),
  163. configurations: [
  164. {
  165. description: metricTagsExplanation,
  166. },
  167. {
  168. description: t('Try out these examples:'),
  169. code: [
  170. {
  171. label: 'Counter',
  172. value: 'counter',
  173. language: 'dart',
  174. code: exampleSnippets.dart.counter,
  175. },
  176. {
  177. label: 'Distribution',
  178. value: 'distribution',
  179. language: 'dart',
  180. code: exampleSnippets.dart.distribution,
  181. },
  182. {
  183. label: 'Set',
  184. value: 'set',
  185. language: 'dart',
  186. code: exampleSnippets.dart.set,
  187. },
  188. {
  189. label: 'Gauge',
  190. value: 'gauge',
  191. language: 'dart',
  192. code: exampleSnippets.dart.gauge,
  193. },
  194. ],
  195. },
  196. {
  197. description: t(
  198. 'It can take up to 3 minutes for the data to appear in the Sentry UI.'
  199. ),
  200. },
  201. {
  202. description: tct(
  203. 'Learn more about metrics and how to configure them, by reading the [docsLink:docs].',
  204. {
  205. docsLink: (
  206. <ExternalLink href="https://docs.sentry.io/platforms/flutter/metrics/" />
  207. ),
  208. }
  209. ),
  210. },
  211. ],
  212. },
  213. ],
  214. };
  215. const onboarding: OnboardingConfig = {
  216. install: params => [
  217. {
  218. type: StepType.INSTALL,
  219. description: tct(
  220. 'Sentry captures data by using an SDK within your application’s runtime. Add the following to your [pubspec: pubspec.yaml]',
  221. {
  222. pubspec: <code />,
  223. }
  224. ),
  225. configurations: [
  226. {
  227. code: [
  228. {
  229. label: 'YAML',
  230. value: 'yaml',
  231. language: 'yaml',
  232. filename: 'pubspec.yaml',
  233. partialLoading: params.sourcePackageRegistries?.isLoading,
  234. code: getInstallSnippet(params),
  235. },
  236. ],
  237. },
  238. ],
  239. },
  240. ],
  241. configure: params => [
  242. {
  243. type: StepType.CONFIGURE,
  244. description: tct('Import [sentryFlutter: sentry_flutter] and initialize it', {
  245. sentryFlutter: <code />,
  246. }),
  247. configurations: [
  248. ...(params.isProfilingSelected
  249. ? [
  250. {
  251. description: t(
  252. 'Flutter Profiling alpha is available for iOS and macOS since SDK version 7.12.0.'
  253. ),
  254. },
  255. ]
  256. : []),
  257. {
  258. code: [
  259. {
  260. label: 'Dart',
  261. value: 'dart',
  262. language: 'dart',
  263. filename: 'main.dart',
  264. code: getConfigureSnippet(params),
  265. },
  266. ],
  267. additionalInfo: params.isPerformanceSelected ? (
  268. <Fragment>
  269. <p>{configureAdditionalInfo}</p>
  270. <AlertWithoutMarginBottom type="info">
  271. {t(
  272. 'To monitor performance, you need to add extra instrumentation as described in the Tracing section below.'
  273. )}
  274. </AlertWithoutMarginBottom>
  275. </Fragment>
  276. ) : (
  277. configureAdditionalInfo
  278. ),
  279. },
  280. ],
  281. },
  282. ],
  283. verify: (params: Params) => [
  284. {
  285. type: StepType.VERIFY,
  286. description: t(
  287. 'Create an intentional error, so you can test that everything is working. In the example below, pressing the button will throw an exception:'
  288. ),
  289. configurations: [
  290. {
  291. code: [
  292. {
  293. label: 'Dart',
  294. value: 'dart',
  295. language: 'dart',
  296. code: getVerifySnippet(),
  297. },
  298. ],
  299. },
  300. ],
  301. },
  302. ...(params.isPerformanceSelected
  303. ? [
  304. {
  305. title: t('Tracing'),
  306. description: t(
  307. "You'll be able to monitor the performance of your app using the SDK. For example:"
  308. ),
  309. configurations: [
  310. {
  311. code: [
  312. {
  313. label: 'Dart',
  314. value: 'dart',
  315. language: 'dart',
  316. code: getPerformanceSnippet(),
  317. },
  318. ],
  319. additionalInfo: tct(
  320. 'To learn more about the API and automatic instrumentations, check out the [perfDocs: tracing documentation].',
  321. {
  322. perfDocs: (
  323. <ExternalLink href="https://docs.sentry.io/platforms/flutter/tracing/instrumentation/" />
  324. ),
  325. }
  326. ),
  327. },
  328. ],
  329. },
  330. ]
  331. : []),
  332. ],
  333. nextSteps: () => [
  334. {
  335. name: t('Debug Symbols'),
  336. description: t(
  337. 'We offer a range of methods to provide Sentry with debug symbols so that you can see symbolicated stack traces and triage issues faster.'
  338. ),
  339. link: 'https://docs.sentry.io/platforms/flutter/upload-debug/',
  340. },
  341. {
  342. name: t('Source Context'),
  343. description: t(
  344. "If Sentry has access to your application's source code, it can show snippets of code source context around the location of stack frames, which helps to quickly pinpoint problematic code."
  345. ),
  346. link: 'https://docs.sentry.io/platforms/flutter/upload-debug/#uploading-source-context-for-flutter-android-ios-and-macos',
  347. },
  348. ],
  349. };
  350. const replayOnboarding: OnboardingConfig = {
  351. introduction: () => (
  352. <MobileBetaBanner link="https://docs.sentry.io/platforms/flutter/session-replay/" />
  353. ),
  354. install: (params: Params) => [
  355. {
  356. type: StepType.INSTALL,
  357. description: tct(
  358. '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:',
  359. {code: <code />}
  360. ),
  361. configurations: [
  362. {
  363. code: [
  364. {
  365. label: 'YAML',
  366. value: 'yaml',
  367. language: 'yaml',
  368. code: getInstallSnippet(params),
  369. },
  370. ],
  371. },
  372. {
  373. description: t(
  374. 'To set up the integration, add the following to your Sentry initialization:'
  375. ),
  376. },
  377. {
  378. code: [
  379. {
  380. label: 'Dart',
  381. value: 'dart',
  382. language: 'dart',
  383. code: getInstallReplaySnippet(),
  384. },
  385. ],
  386. },
  387. ],
  388. },
  389. ],
  390. configure: () => [
  391. {
  392. type: StepType.CONFIGURE,
  393. description: getReplayMobileConfigureDescription({
  394. link: 'https://docs.sentry.io/platforms/flutter/session-replay/#privacy',
  395. }),
  396. configurations: [
  397. {
  398. description: t(
  399. 'The following code is the default configuration, which masks and blocks everything.'
  400. ),
  401. code: [
  402. {
  403. label: 'Dart',
  404. value: 'dart',
  405. language: 'dart',
  406. code: getConfigureReplaySnippet(),
  407. },
  408. ],
  409. },
  410. ],
  411. },
  412. ],
  413. verify: getReplayVerifyStep({
  414. replayOnErrorSampleRateName:
  415. 'options\u200b.experimental\u200b.sessionReplay\u200b.onErrorSampleRate',
  416. replaySessionSampleRateName:
  417. 'options\u200b.experimental\u200b.sessionReplay\u200b.sessionSampleRate',
  418. }),
  419. nextSteps: () => [],
  420. };
  421. const docs: Docs = {
  422. onboarding,
  423. feedbackOnboardingCrashApi: feedbackOnboardingCrashApiDart,
  424. crashReportOnboarding: feedbackOnboardingCrashApiDart,
  425. customMetricsOnboarding: metricsOnboarding,
  426. replayOnboarding,
  427. };
  428. export default docs;
  429. const AlertWithoutMarginBottom = styled(Alert)`
  430. margin-bottom: 0;
  431. `;