Repository: getsentry/sentry-cocoa
Pull request #5088: chore(file-io): add data and file manager swizzling to enabled features
Author: login: philprime
Created: 2025-04-14T09:00:56Z | Merged: 2025-04-15T11:02:35Z

## :scroll: Description

Adds two flags for data and file manager swizzling adoption tracking

## :bulb: Motivation and Context

Closes #4906

## :green_heart: How did you test it?

Added tests

## :pencil: Checklist

You have to check all boxes before merging:

- [x] I added tests to verify the changes.
- [x] No new PII added or SDK only sends newly added PII if `sendDefaultPII` is enabled.
- [x] I updated the docs if needed.
- [x] I updated the wizard if needed.
- [x] Review from the native team if needed.
- [x] No breaking change or entry added to the changelog.
- [x] No breaking change for hybrid SDKs or communicated to hybrid SDKs.

#skip-changelog

Linked issue #4906: Track adoption of enableFileManagerSwizzling
### Description

Track the adoption of the feature via the [SentryEnabledFeaturesBuilder](https://github.com/getsentry/sentry-cocoa/blob/main/Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift). When the option enableFileManagerSwizzling is enabled, please append it to the list, which gets added to the SDK event payload and gets indexed in Looker.

Diff:
diff --git a/Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift b/Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift
index 253496d57dc..3408ac30358 100644
--- a/Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift
+++ b/Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift
@@ -2,7 +2,7 @@ import Foundation
 
 @objcMembers class SentryEnabledFeaturesBuilder: NSObject {
 
-    // swiftlint:disable cyclomatic_complexity
+    // swiftlint:disable cyclomatic_complexity function_body_length
     static func getEnabledFeatures(options: Options?) -> [String] {
         guard let options = options else {
             return []
@@ -57,7 +57,14 @@ import Foundation
             features.append("fastViewRendering")
         }
 #endif // #if os(iOS) && !SENTRY_NO_UIKIT
+
+        if options.experimental.enableDataSwizzling {
+            features.append("dataSwizzling")
+        }
+        if options.experimental.enableFileManagerSwizzling {
+            features.append("fileManagerSwizzling")
+        }
         return features
     }
-    // swiftlint:enable cyclomatic_complexity
+    // swiftlint:enable cyclomatic_complexity function_body_length
 }
diff --git a/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift b/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift
index 475f1693e14..203cb29f6ce 100644
--- a/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift
+++ b/Tests/SentryTests/Helper/SentryEnabledFeaturesBuilderTests.swift
@@ -11,7 +11,7 @@ final class SentryEnabledFeaturesBuilderTests: XCTestCase {
         let features = SentryEnabledFeaturesBuilder.getEnabledFeatures(options: options)
 
         // -- Assert --
-        XCTAssertEqual(features, ["captureFailedRequests"])
+        XCTAssertEqual(features, ["captureFailedRequests", "dataSwizzling"])
     }
 
     func testEnableAllFeatures() throws {
@@ -113,4 +113,56 @@ final class SentryEnabledFeaturesBuilderTests: XCTestCase {
         throw XCTSkip("Test not supported on this platform")
 #endif
     }
+
+    func testEnableDataSwizzling_isEnabled_shouldAddFeature() throws {
+        // -- Arrange --
+        let options = Options()
+
+        options.experimental.enableDataSwizzling = true
+
+        // -- Act --
+        let features = SentryEnabledFeaturesBuilder.getEnabledFeatures(options: options)
+
+        // -- Assert --
+        XCTAssert(features.contains("dataSwizzling"))
+    }
+
+    func testEnableDataSwizzling_isDisabled_shouldNotAddFeature() throws {
+        // -- Arrange --
+        let options = Options()
+
+        options.experimental.enableDataSwizzling = false
+
+        // -- Act --
+        let features = SentryEnabledFeaturesBuilder.getEnabledFeatures(options: options)
+
+        // -- Assert --
+        XCTAssertFalse(features.contains("dataSwizzling"))
+    }
+
+    func testEnableFileManagerSwizzling_isEnabled_shouldAddFeature() throws {
+        // -- Arrange --
+        let options = Options()
+
+        options.experimental.enableFileManagerSwizzling = true
+
+        // -- Act --
+        let features = SentryEnabledFeaturesBuilder.getEnabledFeatures(options: options)
+
+        // -- Assert --
+        XCTAssert(features.contains("fileManagerSwizzling"))
+    }
+
+    func testEnableFileManagerSwizzling_isDisabled_shouldNotAddFeature() throws {
+        // -- Arrange --
+        let options = Options()
+
+        options.experimental.enableFileManagerSwizzling = false
+
+        // -- Act --
+        let features = SentryEnabledFeaturesBuilder.getEnabledFeatures(options: options)
+
+        // -- Assert --
+        XCTAssertFalse(features.contains("fileManagerSwizzling"))
+    }
 }


Reviews:
user: login: philipphofmann
body: LGTM, thanks.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-14T14:24:21Z
user: login: philprime
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-14T14:27:32Z
user: login: philprime
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-14T15:26:09Z

Review comments:
diff_hunk: @@ -57,7 +57,18 @@ import Foundation
             features.append("fastViewRendering")
         }
 #endif // #if os(iOS) && !SENTRY_NO_UIKIT
+
+        addFileIOFeatures(options: options, to: &features)
path: Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift
user: login: philipphofmann
body: `l`: IMO, the extra method harms readability a bit. Now I have to jump around to see which features are added to the list. For me, it's OK to have all features in one method. No need to add an extra one.
created_at: 2025-04-14T14:24:01Z
author_association: MEMBER
diff_hunk: @@ -57,7 +57,18 @@ import Foundation
             features.append("fastViewRendering")
         }
 #endif // #if os(iOS) && !SENTRY_NO_UIKIT
+
+        addFileIOFeatures(options: options, to: &features)
path: Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift
user: login: philprime
body: I also don't like this but swiftlint complained about function body length and cyclomatic complexity is already disabled too, so maybe it's worth starting to extract into multiple methods.

created_at: 2025-04-14T14:27:32Z
author_association: MEMBER
diff_hunk: @@ -57,7 +57,18 @@ import Foundation
             features.append("fastViewRendering")
         }
 #endif // #if os(iOS) && !SENTRY_NO_UIKIT
+
+        addFileIOFeatures(options: options, to: &features)
path: Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift
user: login: philprime
body: As we both don't like this I'll change it and force-ignore the linter
created_at: 2025-04-14T15:26:09Z
author_association: MEMBER

PR comments:
user: login: codecov[bot]
created_at: 2025-04-14T09:07:48Z
body: ## [Codecov](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5088?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 92.744%. Comparing base [(`d8e1ae2`)](https://app.codecov.io/gh/getsentry/sentry-cocoa/commit/d8e1ae2a0987ab2a89c82799c806cb25301dfaa0?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry) to head [(`5ffcee4`)](https://app.codecov.io/gh/getsentry/sentry-cocoa/commit/5ffcee428bc7bab64c1c9c2003c1c4f84706f5ed?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry).
> Report is 1 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


[![Impacted file tree graph](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5088/graphs/tree.svg?width=650&height=150&src=pr&token=PTZKtOJlrs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5088?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)

```diff
@@              Coverage Diff              @@
##              main     #5088       +/-   ##
=============================================
+ Coverage   92.741%   92.744%   +0.003%     
=============================================
  Files          675       675               
  Lines        83676     83735       +59     
  Branches     30469     30492       +23     
=============================================
+ Hits         77602     77660       +58     
- Misses        5974      5977        +3     
+ Partials       100        98        -2     
```

| [Files with missing lines](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5088?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry) | Coverage Δ | |
|---|---|---|
| [...es/Swift/Helper/SentryEnabledFeaturesBuilder.swift](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5088?src=pr&el=tree&filepath=Sources%2FSwift%2FHelper%2FSentryEnabledFeaturesBuilder.swift&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry#diff-U291cmNlcy9Td2lmdC9IZWxwZXIvU2VudHJ5RW5hYmxlZEZlYXR1cmVzQnVpbGRlci5zd2lmdA==) | `100.000% <100.000%> (ø)` | |
| [...sts/Helper/SentryEnabledFeaturesBuilderTests.swift](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5088?src=pr&el=tree&filepath=Tests%2FSentryTests%2FHelper%2FSentryEnabledFeaturesBuilderTests.swift&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry#diff-VGVzdHMvU2VudHJ5VGVzdHMvSGVscGVyL1NlbnRyeUVuYWJsZWRGZWF0dXJlc0J1aWxkZXJUZXN0cy5zd2lmdA==) | `100.000% <100.000%> (ø)` | |

... and [12 files with indirect coverage changes](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5088/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)

------

[Continue to review full report in Codecov by Sentry](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5088?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5088?dropdown=coverage&src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry). Last update [d8e1ae2...5ffcee4](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5088?dropdown=coverage&src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry).

</details>
<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-14T09:12:35Z
body: ##  Performance metrics :rocket:
<table>
  <tr>
    <th>&nbsp;</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr>
  <tr>
    <th align="left">Startup time</th>
    <td align="right">1228.82 ms</td>
    <td align="right">1247.82 ms</td>
    <td align="right"><strong>19.00 ms</strong></td>
  </tr>
  <tr>
    <th align="left">Size</th>
    <td align="right">22.30 KiB</td>
    <td align="right">847.63 KiB</td>
    <td align="right"><strong>825.32 KiB</strong></td>
  </tr>
</table>
<details><summary><h3>Baseline results on branch: main</h3></summary>
<h3>Startup times</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">ee3f02eee71adf7c703e8f79f16dc0d7eca34dbd</th>
  <td align="right">1236.53 ms</td>
  <td align="right">1263.54 ms</td>
  <td align="right"><strong>27.01 ms</strong></td>
</tr><tr>
  <th align="left">2df93b0cb25daee69a9db00098942de617dc8e0f</th>
  <td align="right">1210.73 ms</td>
  <td align="right">1228.76 ms</td>
  <td align="right"><strong>18.02 ms</strong></td>
</tr><tr>
  <th align="left">fc163f589106843d00b24c410c9a32634865a9c1</th>
  <td align="right">1224.17 ms</td>
  <td align="right">1248.24 ms</td>
  <td align="right"><strong>24.08 ms</strong></td>
</tr><tr>
  <th align="left">02671d850aa5eb27ea7810311729a22911d2d3a1</th>
  <td align="right">1246.80 ms</td>
  <td align="right">1266.42 ms</td>
  <td align="right"><strong>19.62 ms</strong></td>
</tr><tr>
  <th align="left">e32423038e99f0c5d868744421d664cdd55c7383</th>
  <td align="right">1244.43 ms</td>
  <td align="right">1252.98 ms</td>
  <td align="right"><strong>8.55 ms</strong></td>
</tr><tr>
  <th align="left">c2acec5accaef211813fdda6ac2b54b3a0fbb374</th>
  <td align="right">1200.60 ms</td>
  <td align="right">1227.08 ms</td>
  <td align="right"><strong>26.48 ms</strong></td>
</tr><tr>
  <th align="left">afce5bf26a9f92100f9766489286470f62a4ae26</th>
  <td align="right">1199.94 ms</td>
  <td align="right">1213.27 ms</td>
  <td align="right"><strong>13.33 ms</strong></td>
</tr><tr>
  <th align="left">0538fb6529832abdaf0d27f41c00a202d94bc511</th>
  <td align="right">1218.35 ms</td>
  <td align="right">1241.36 ms</td>
  <td align="right"><strong>23.01 ms</strong></td>
</tr><tr>
  <th align="left">061c982c8616fa6ca7f0762998f39a8f4d8d2fc2</th>
  <td align="right">1229.73 ms</td>
  <td align="right">1253.88 ms</td>
  <td align="right"><strong>24.14 ms</strong></td>
</tr><tr>
  <th align="left">8f397a72ebc82923bd173410e0902c7cd70c7ba0</th>
  <td align="right">1251.82 ms</td>
  <td align="right">1268.34 ms</td>
  <td align="right"><strong>16.52 ms</strong></td>
</tr></table>
<h3>App size</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">ee3f02eee71adf7c703e8f79f16dc0d7eca34dbd</th>
  <td align="right">22.84 KiB</td>
  <td align="right">401.67 KiB</td>
  <td align="right"><strong>378.83 KiB</strong></td>
</tr><tr>
  <th align="left">2df93b0cb25daee69a9db00098942de617dc8e0f</th>
  <td align="right">21.58 KiB</td>
  <td align="right">682.40 KiB</td>
  <td align="right"><strong>660.81 KiB</strong></td>
</tr><tr>
  <th align="left">fc163f589106843d00b24c410c9a32634865a9c1</th>
  <td align="right">20.76 KiB</td>
  <td align="right">436.30 KiB</td>
  <td align="right"><strong>415.54 KiB</strong></td>
</tr><tr>
  <th align="left">02671d850aa5eb27ea7810311729a22911d2d3a1</th>
  <td align="right">21.58 KiB</td>
  <td align="right">705.40 KiB</td>
  <td align="right"><strong>683.82 KiB</strong></td>
</tr><tr>
  <th align="left">e32423038e99f0c5d868744421d664cdd55c7383</th>
  <td align="right">22.85 KiB</td>
  <td align="right">408.88 KiB</td>
  <td align="right"><strong>386.03 KiB</strong></td>
</tr><tr>
  <th align="left">c2acec5accaef211813fdda6ac2b54b3a0fbb374</th>
  <td align="right">22.85 KiB</td>
  <td align="right">408.88 KiB</td>
  <td align="right"><strong>386.03 KiB</strong></td>
</tr><tr>
  <th align="left">afce5bf26a9f92100f9766489286470f62a4ae26</th>
  <td align="right">21.58 KiB</td>
  <td align="right">542.18 KiB</td>
  <td align="right"><strong>520.60 KiB</strong></td>
</tr><tr>
  <th align="left">0538fb6529832abdaf0d27f41c00a202d94bc511</th>
  <td align="right">21.58 KiB</td>
  <td align="right">683.50 KiB</td>
  <td align="right"><strong>661.92 KiB</strong></td>
</tr><tr>
  <th align="left">061c982c8616fa6ca7f0762998f39a8f4d8d2fc2</th>
  <td align="right">21.58 KiB</td>
  <td align="right">683.51 KiB</td>
  <td align="right"><strong>661.92 KiB</strong></td>
</tr><tr>
  <th align="left">8f397a72ebc82923bd173410e0902c7cd70c7ba0</th>
  <td align="right">20.76 KiB</td>
  <td align="right">420.55 KiB</td>
  <td align="right"><strong>399.79 KiB</strong></td>
</tr></table>
</details>
<details><summary><h3>Previous results on branch: philprime/issue-4906</h3></summary>
<h3>Startup times</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">11e147bf1030617a7f261beee69a59114f2effe0</th>
  <td align="right">1234.45 ms</td>
  <td align="right">1243.45 ms</td>
  <td align="right"><strong>9.00 ms</strong></td>
</tr></table>
<h3>App size</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">11e147bf1030617a7f261beee69a59114f2effe0</th>
  <td align="right">22.30 KiB</td>
  <td align="right">847.65 KiB</td>
  <td align="right"><strong>825.35 KiB</strong></td>
</tr></table>
</details>

author_association: CONTRIBUTOR