ios.tsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. import ExternalLink from 'sentry/components/links/externalLink';
  2. import Link from 'sentry/components/links/link';
  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 {metricTagsExplanation} from 'sentry/components/onboarding/gettingStartedDoc/utils/metricsOnboarding';
  13. import {appleFeedbackOnboarding} from 'sentry/gettingStartedDocs/apple/macos';
  14. import {t, tct} from 'sentry/locale';
  15. import {getPackageVersion} from 'sentry/utils/gettingStartedDocs/getPackageVersion';
  16. export enum InstallationMode {
  17. AUTO = 'auto',
  18. MANUAL = 'manual',
  19. }
  20. const platformOptions = {
  21. installationMode: {
  22. label: t('Installation Mode'),
  23. items: [
  24. {
  25. label: t('Auto'),
  26. value: InstallationMode.AUTO,
  27. },
  28. {
  29. label: t('Manual'),
  30. value: InstallationMode.MANUAL,
  31. },
  32. ],
  33. defaultValue:
  34. navigator.userAgent.indexOf('Win') !== -1
  35. ? InstallationMode.MANUAL
  36. : InstallationMode.AUTO,
  37. },
  38. } satisfies BasePlatformOptions;
  39. type PlatformOptions = typeof platformOptions;
  40. type Params = DocsParams<PlatformOptions>;
  41. const isAutoInstall = (params: Params) =>
  42. params.platformOptions.installationMode === InstallationMode.AUTO;
  43. const getAutoInstallSnippet = () =>
  44. `brew install getsentry/tools/sentry-wizard && sentry-wizard -i ios`;
  45. const getManualInstallSnippet = (params: Params) => `
  46. .package(url: "https://github.com/getsentry/sentry-cocoa", from: "${getPackageVersion(
  47. params,
  48. 'sentry.cocoa',
  49. '8.9.3'
  50. )}"),`;
  51. const getConfigurationSnippet = (params: Params) => `
  52. import Sentry
  53. // ....
  54. func application(_ application: UIApplication,
  55. didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  56. SentrySDK.start { options in
  57. options.dsn = "${params.dsn}"
  58. options.debug = true // Enabling debug when first installing is always helpful${
  59. params.isPerformanceSelected
  60. ? `
  61. // Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
  62. // We recommend adjusting this value in production.
  63. options.tracesSampleRate = 1.0`
  64. : ''
  65. }${
  66. params.isProfilingSelected
  67. ? `
  68. // Sample rate for profiling, applied on top of TracesSampleRate.
  69. // We recommend adjusting this value in production.
  70. options.profilesSampleRate = 1.0`
  71. : ''
  72. }
  73. }
  74. return true
  75. }`;
  76. const getConfigurationSnippetSwiftUi = (params: Params) => `
  77. import Sentry
  78. @main
  79. struct SwiftUIApp: App {
  80. init() {
  81. SentrySDK.start { options in
  82. options.dsn = "${params.dsn}"
  83. options.debug = true // Enabling debug when first installing is always helpful${
  84. params.isPerformanceSelected
  85. ? `
  86. // Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
  87. // We recommend adjusting this value in production.
  88. options.tracesSampleRate = 1.0`
  89. : ''
  90. }${
  91. params.isProfilingSelected
  92. ? `
  93. // Sample rate for profiling, applied on top of TracesSampleRate.
  94. // We recommend adjusting this value in production.
  95. options.profilesSampleRate = 1.0`
  96. : ''
  97. }
  98. }
  99. }
  100. }`;
  101. const getVerifySnippet = () => `
  102. let button = UIButton(type: .roundedRect)
  103. button.frame = CGRect(x: 20, y: 50, width: 100, height: 30)
  104. button.setTitle("Break the world", for: [])
  105. button.addTarget(self, action: #selector(self.breakTheWorld(_:)), for: .touchUpInside)
  106. view.addSubview(button)
  107. @IBAction func breakTheWorld(_ sender: AnyObject) {
  108. fatalError("Break the world")
  109. }`;
  110. const getExperimentalFeaturesSnippetSwift = () => `
  111. import Sentry
  112. SentrySDK.start { options in
  113. // ...
  114. // Enable all experimental features
  115. options.attachViewHierarchy = true
  116. options.enableMetricKit = true
  117. options.enableTimeToFullDisplayTracing = true
  118. options.swiftAsyncStacktraces = true
  119. options.enableAppLaunchProfiling = true
  120. }`;
  121. const getExperimentalFeaturesSnippetObjC = () => `
  122. @import Sentry;
  123. [SentrySDK startWithConfigureOptions:^(SentryOptions *options) {
  124. // ...
  125. // Enable all experimental features
  126. options.attachViewHierarchy = YES;
  127. options.enableMetricKit = YES;
  128. options.enableTimeToFullDisplayTracing = YES;
  129. options.swiftAsyncStacktraces = YES;
  130. options.enableAppLaunchProfiling = YES;
  131. }];`;
  132. const getConfigureMetricsSnippetSwift = (params: Params) => `
  133. import Sentry
  134. SentrySDK.start { options in
  135. options.dsn = "${params.dsn}"
  136. options.enableMetrics = true
  137. }`;
  138. const getConfigureMetricsSnippetObjC = (params: Params) => `
  139. @import Sentry;
  140. [SentrySDK startWithConfigureOptions:^(SentryOptions * options) {
  141. options.Dsn = @"${params.dsn}";
  142. options.enableMetrics = YES;
  143. }];`;
  144. const getVerifyMetricsSnippetSwift = () => `
  145. import Sentry
  146. // Incrementing a counter by one for each button click.
  147. SentrySDK.metrics
  148. .increment(key: "button_login_click",
  149. value: 1.0,
  150. tags: ["screen": "login"]
  151. )
  152. // Add '150' to a distribution used to track the loading time.
  153. SentrySDK.metrics
  154. .distribution(key: "image_download_duration",
  155. value: 150.0,
  156. unit: MeasurementUnitDuration.millisecond,
  157. tags: ["screen": "login"]
  158. )
  159. // Adding '1' to a gauge used to track the loading time.
  160. SentrySDK.metrics
  161. .gauge(key: "page_load",
  162. value: 1.0,
  163. unit: MeasurementUnitDuration.millisecond,
  164. tags: ["screen": "login"]
  165. )
  166. // Add 'jane' to a set
  167. // used for tracking the number of users that viewed a page.
  168. SentrySDK.metrics
  169. .set(key: "user_view",
  170. value: "jane",
  171. unit: MeasurementUnit(unit: "username"),
  172. tags: ["screen": "login"]
  173. )`;
  174. const getVerifyMetricsSnippetObjC = () => `
  175. @import Sentry;
  176. // Incrementing a counter by one for each button click.
  177. [SentrySDK.metrics
  178. incrementWithKey :@"button_login_click"
  179. value: 1.0
  180. unit: SentryMeasurementUnit.none
  181. tags: @{ @"screen" : @"login" }
  182. ];
  183. // Add '150' to a distribution used to track the loading time.
  184. [SentrySDK.metrics
  185. distributionWithKey: @"image_download_duration"
  186. value: 150.0
  187. unit: SentryMeasurementUnitDuration.millisecond
  188. tags: @{ @"screen" : @"login" }
  189. ];
  190. // Adding '1' to a gauge used to track the loading time.
  191. [SentrySDK.metrics
  192. gaugeWithKey: @"page_load"
  193. value: 1.0
  194. unit: SentryMeasurementUnitDuration.millisecond
  195. tags: @{ @"screen" : @"login" }
  196. ];
  197. // Add 'jane' to a set
  198. // used for tracking the number of users that viewed a page.
  199. [SentrySDK.metrics
  200. setWithKey :@"user_view"
  201. value: @"jane"
  202. unit: [[SentryMeasurementUnit alloc] initWithUnit:@"username"]
  203. tags: @{ @"screen" : @"login" }
  204. ];`;
  205. const onboarding: OnboardingConfig<PlatformOptions> = {
  206. install: params =>
  207. isAutoInstall(params)
  208. ? [
  209. {
  210. type: StepType.INSTALL,
  211. description: (
  212. <p>
  213. {tct(
  214. 'Add Sentry automatically to your app with the [wizardLink:Sentry wizard] (call this inside your project directory).',
  215. {
  216. wizardLink: (
  217. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/ios/#install" />
  218. ),
  219. }
  220. )}
  221. </p>
  222. ),
  223. configurations: [
  224. {
  225. language: 'bash',
  226. code: getAutoInstallSnippet(),
  227. },
  228. ],
  229. },
  230. ]
  231. : [
  232. {
  233. type: StepType.INSTALL,
  234. description: tct(
  235. 'We recommend installing the SDK with Swift Package Manager (SPM), but we also support [alternateMethods: alternate installation methods]. To integrate Sentry into your Xcode project using SPM, open your App in Xcode and open [addPackage: File > Add Packages]. Then add the SDK by entering the Git repo url in the top right search field:',
  236. {
  237. alternateMethods: (
  238. <ExternalLink href="https://docs.sentry.io/platforms/apple/install/" />
  239. ),
  240. addPackage: <strong />,
  241. }
  242. ),
  243. configurations: [
  244. {
  245. language: 'url',
  246. code: `https://github.com/getsentry/sentry-cocoa.git`,
  247. },
  248. {
  249. description: (
  250. <p>
  251. {tct(
  252. 'Alternatively, when your project uses a [packageSwift: Package.swift] file to manage dependencies, you can specify the target with:',
  253. {
  254. packageSwift: <code />,
  255. }
  256. )}
  257. </p>
  258. ),
  259. language: 'swift',
  260. partialLoading: params.sourcePackageRegistries.isLoading,
  261. code: getManualInstallSnippet(params),
  262. },
  263. ],
  264. },
  265. ],
  266. configure: params =>
  267. isAutoInstall(params)
  268. ? [
  269. {
  270. type: StepType.CONFIGURE,
  271. description: t(
  272. 'The Sentry wizard will automatically patch your application:'
  273. ),
  274. configurations: [
  275. {
  276. description: (
  277. <List symbol="bullet">
  278. <ListItem>
  279. {t('Install the Sentry SDK via Swift Package Manager or Cocoapods')}
  280. </ListItem>
  281. <ListItem>
  282. {tct(
  283. 'Update your [appDelegate: AppDelegate] or SwiftUI App Initializer with the default Sentry configuration and an example error',
  284. {
  285. appDelegate: <code />,
  286. }
  287. )}
  288. </ListItem>
  289. <ListItem>
  290. {tct(
  291. 'Add a new [phase: Upload Debug Symbols] phase to your [xcodebuild: xcodebuild] build script',
  292. {
  293. phase: <code />,
  294. xcodebuild: <code />,
  295. }
  296. )}
  297. </ListItem>
  298. <ListItem>
  299. {tct(
  300. 'Create [sentryclirc: .sentryclirc] with an auth token to upload debug symbols (this file is automatically added to [gitignore: .gitignore])',
  301. {
  302. sentryclirc: <code />,
  303. gitignore: <code />,
  304. }
  305. )}
  306. </ListItem>
  307. <ListItem>
  308. {t(
  309. "When you're using Fastlane, it will add a Sentry lane for uploading debug symbols"
  310. )}
  311. </ListItem>
  312. </List>
  313. ),
  314. additionalInfo: tct(
  315. 'Alternatively, you can also [manualSetupLink:set up the SDK manually].',
  316. {
  317. manualSetupLink: (
  318. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/ios/manual-setup/" />
  319. ),
  320. stepsBelow: <strong />,
  321. }
  322. ),
  323. },
  324. ],
  325. },
  326. ]
  327. : [
  328. {
  329. type: StepType.CONFIGURE,
  330. description: (
  331. <p>
  332. {tct(
  333. 'Make sure you initialize the SDK as soon as possible in your application lifecycle e.g. in your [appDelegate:] method:',
  334. {
  335. appDelegate: (
  336. <code>
  337. - [UIAppDelegate application:didFinishLaunchingWithOptions:]
  338. </code>
  339. ),
  340. }
  341. )}
  342. </p>
  343. ),
  344. configurations: [
  345. {
  346. language: 'swift',
  347. code: getConfigurationSnippet(params),
  348. },
  349. {
  350. description: (
  351. <p>
  352. {tct(
  353. "When using SwiftUI and your app doesn't implement an app delegate, initialize the SDK within the [initializer: App conformer's initializer]:",
  354. {
  355. initializer: (
  356. <ExternalLink href="https://developer.apple.com/documentation/swiftui/app/main()" />
  357. ),
  358. }
  359. )}
  360. </p>
  361. ),
  362. language: 'swift',
  363. code: getConfigurationSnippetSwiftUi(params),
  364. },
  365. ],
  366. },
  367. ],
  368. verify: params =>
  369. isAutoInstall(params)
  370. ? [
  371. {
  372. type: StepType.VERIFY,
  373. description: t(
  374. 'The Sentry wizard automatically adds a code snippet that captures a message to your project. Simply run your app and you should see this message in your Sentry project.'
  375. ),
  376. },
  377. {
  378. title: t('Experimental Features'),
  379. description: tct(
  380. 'Want to play with some new features? Try out our experimental features for [vh: View Hierarchy], [ttfd: Time to Full Display (TTFD)], [metricKit: MetricKit], [prewarmedAppStart: Prewarmed App Start Tracing], and [asyncStacktraces: Swift Async Stacktraces]. Experimental features are still a work-in-progress and may have bugs. We recognize the irony. [break] Let us know if you have feedback through [gh: GitHub issues].',
  381. {
  382. vh: (
  383. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/ios/enriching-events/viewhierarchy/" />
  384. ),
  385. ttfd: (
  386. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/ios/performance/instrumentation/automatic-instrumentation/#time-to-full-display" />
  387. ),
  388. metricKit: (
  389. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/watchos/configuration/metric-kit/" />
  390. ),
  391. prewarmedAppStart: (
  392. <ExternalLink href="https://docs.sentry.io/platforms/apple/performance/instrumentation/automatic-instrumentation/#prewarmed-app-start-tracing" />
  393. ),
  394. asyncStacktraces: (
  395. <ExternalLink href="https://docs.sentry.io/platforms/apple/guides/ios/#stitch-together-swift-concurrency-stack-traces" />
  396. ),
  397. gh: (
  398. <ExternalLink href="https://github.com/getsentry/sentry-cocoa/issues" />
  399. ),
  400. break: <br />,
  401. }
  402. ),
  403. configurations: [
  404. {
  405. code: [
  406. {
  407. label: 'Swift',
  408. value: 'swift',
  409. language: 'swift',
  410. code: getExperimentalFeaturesSnippetSwift(),
  411. },
  412. {
  413. label: 'Objective-C',
  414. value: 'c',
  415. language: 'c',
  416. code: getExperimentalFeaturesSnippetObjC(),
  417. },
  418. ],
  419. },
  420. ],
  421. },
  422. ]
  423. : [
  424. {
  425. type: StepType.VERIFY,
  426. description: (
  427. <p>
  428. {tct(
  429. 'This snippet contains an intentional error you can use to test that errors are uploaded to Sentry correctly. You can add it to your main [viewController: ViewController].',
  430. {
  431. viewController: <code />,
  432. }
  433. )}
  434. </p>
  435. ),
  436. configurations: [
  437. {
  438. language: 'swift',
  439. code: getVerifySnippet(),
  440. },
  441. ],
  442. },
  443. ],
  444. nextSteps: () => [
  445. {
  446. id: 'cocoapods-carthage',
  447. name: t('CocoaPods/Carthage'),
  448. description: t(
  449. 'Learn about integrating Sentry into your project using CocoaPods or Carthage.'
  450. ),
  451. link: 'https://docs.sentry.io/platforms/apple/install/',
  452. },
  453. {
  454. id: 'debug-symbols',
  455. name: t('Debug Symbols'),
  456. description: t('Symbolicate and get readable stacktraces in your Sentry errors.'),
  457. link: 'https://docs.sentry.io/platforms/apple/dsym/',
  458. },
  459. {
  460. id: 'swiftui',
  461. name: t('SwiftUI'),
  462. description: t('Learn about our first class integration with SwiftUI.'),
  463. link: 'https://docs.sentry.io/platforms/apple/performance/instrumentation/swiftui-instrumentation/',
  464. },
  465. {
  466. id: 'profiling',
  467. name: t('Profiling'),
  468. description: t(
  469. 'Collect and analyze performance profiles from real user devices in production.'
  470. ),
  471. link: 'https://docs.sentry.io/platforms/apple/profiling/',
  472. },
  473. ],
  474. };
  475. const metricsOnboarding: OnboardingConfig<PlatformOptions> = {
  476. install: (params: Params) => [
  477. {
  478. type: StepType.INSTALL,
  479. description: tct(
  480. 'You need Sentry Cocoa SDK version [codeVersion:8.23.0] or higher. Learn more about installation methods in our [docsLink:full documentation].',
  481. {
  482. codeVersion: <code />,
  483. docsLink: <Link to={`/projects/${params.projectSlug}/getting-started/`} />,
  484. }
  485. ),
  486. configurations: [
  487. {
  488. language: 'yml',
  489. partialLoading: params.sourcePackageRegistries?.isLoading,
  490. code: getAutoInstallSnippet(),
  491. },
  492. ],
  493. },
  494. ],
  495. configure: (params: Params) => [
  496. {
  497. type: StepType.CONFIGURE,
  498. description: t(
  499. 'To enable capturing metrics, you need to enable the metrics feature.'
  500. ),
  501. configurations: [
  502. {
  503. code: [
  504. {
  505. label: 'Swift',
  506. value: 'swift',
  507. language: 'swift',
  508. code: getConfigureMetricsSnippetSwift(params),
  509. },
  510. {
  511. label: 'Objective-C',
  512. value: 'c',
  513. language: 'c',
  514. code: getConfigureMetricsSnippetObjC(params),
  515. },
  516. ],
  517. },
  518. ],
  519. },
  520. ],
  521. verify: () => [
  522. {
  523. type: StepType.VERIFY,
  524. description: tct(
  525. "Then you'll be able to add metrics as [codeCounters:counters], [codeSets:sets], [codeDistribution:distributions], and [codeGauge:gauges]. These are available under the [codeNamespace:SentrySDK.metrics()] namespace.",
  526. {
  527. codeCounters: <code />,
  528. codeSets: <code />,
  529. codeDistribution: <code />,
  530. codeGauge: <code />,
  531. codeNamespace: <code />,
  532. }
  533. ),
  534. configurations: [
  535. {
  536. description: metricTagsExplanation,
  537. },
  538. {
  539. description: t('Try out these examples:'),
  540. code: [
  541. {
  542. label: 'Swift',
  543. value: 'swift',
  544. language: 'swift',
  545. code: getVerifyMetricsSnippetSwift(),
  546. },
  547. {
  548. label: 'Objective-C',
  549. value: 'c',
  550. language: 'c',
  551. code: getVerifyMetricsSnippetObjC(),
  552. },
  553. ],
  554. },
  555. {
  556. description: t(
  557. 'It can take up to 3 minutes for the data to appear in the Sentry UI.'
  558. ),
  559. },
  560. {
  561. description: tct(
  562. 'Learn more about metrics and how to configure them, by reading the [docsLink:docs].',
  563. {
  564. docsLink: (
  565. <ExternalLink href="https://docs.sentry.io/platforms/apple/metrics/" />
  566. ),
  567. }
  568. ),
  569. },
  570. ],
  571. },
  572. ],
  573. };
  574. const docs: Docs<PlatformOptions> = {
  575. onboarding,
  576. feedbackOnboardingCrashApi: appleFeedbackOnboarding,
  577. crashReportOnboarding: appleFeedbackOnboarding,
  578. customMetricsOnboarding: metricsOnboarding,
  579. platformOptions,
  580. };
  581. export default docs;