feat(tracing): Add automatic tracing of time to initial display for react-navigation
:loudspeaker: Type of change
- [ ] Bugfix
- [x] New feature
- [ ] Enhancement
- [ ] Refactoring
:scroll: Description
This PR adds automatic TTID spans and measurements for React Navigation version 5 and newer. When TTID enables new navigation.processing span is added. This represents the duration from navigation dispatch to the new screen resolved in JS. This was the original minimum transaction duration.
Technical details
On iOS React Navigation uses ViewControllers to create RN Screens. We swizzle the RNSScreen view controller viewDidAppear to start listening for the next new frame. We can't start listening to the new frame when the JS layer is done with the navigation, because the next frame after that will be from the old screen/animation to the new screen.
A current limitation is that this works only for native view controller animations. Animations initiated from JS happen after the view didAppear.
On Android React Navigation creates Fragments to create RN Screens. We hook into onFragmentViewCreated where we check if the fragment is RNSScreenFragment. If that is we hook onto the event dispatcher attached to that fragment and wait for appeareEvent and then for the next rendered frame.
We can't use the JS viewApear hook as this is processed by the JS Engine asynchronously from the main application thread and might happen after (depending on the JS loop queue) the first frame of the screen is rendered.
Known limitations
- Needs native code so it doesn't work in Expo Go
- On iOS JS initiated animations, happen after the view controller first frame
- There doesn't seem to be a way to hook into the View event dispatcher used by the RNScreens on iOS, so we had to use swizzling.
How to enable TTID
import * as Sentry from "@sentry/react-native";
const routingInstrumentation = new Sentry.ReactNavigationInstrumentation({
enableTimeToInitialDisplay: true,
});
Sentry.init({
integrations: [
new Sentry.ReactNativeTracing({routingInstrumentation}),
],
});
Examples in Sentry
Example 1: https://sentry-sdks.sentry.io/discover/sentry-react-native:7432443eb31a4166be70d4b8d63b040b
Example 2: https://sentry-sdks.sentry.io/discover/sentry-react-native:4429cff3025b4ec8aa2b128f1d564459
:bulb: Motivation and Context
:green_heart: How did you test it?
sample app, unit and integration tests
:pencil: Checklist
- [x] I reviewed submitted code
- [x] I added tests to verify changes
- [x] No new PII added or SDK only sends newly added PII if
sendDefaultPIIis enabled - [x] All tests passing
- [x] No breaking changes
:crystal_ball: Next steps
- [x] https://github.com/getsentry/sentry-cocoa/pull/3683
- [x] https://github.com/getsentry/sentry-cocoa/pull/3684
- [x] Bump
sentry-cocoa, above changes will be included in8.21.0
| Messages | |
|---|---|
| :book: | Do not forget to update Sentry-docs with your feature once the pull request gets approved. |
Generated by :no_entry_sign: dangerJS against 9b833b28b9c93663d4cf8d85ea58f73b2d33d153
Android (legacy) Performance metrics :rocket:
| Plain | With Sentry | Diff | |
|---|---|---|---|
| Startup time | 422.54 ms | 449.60 ms | 27.06 ms |
| Size | 17.73 MiB | 19.92 MiB | 2.19 MiB |
Baseline results on branch: main
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d197b5c9ca10ac3f729d1b3ef805328665aa0895+dirty | 338.94 ms | 354.87 ms | 15.93 ms |
| acadc0f974a0c234a3d9010117b076792d14d6e8+dirty | 373.24 ms | 381.51 ms | 8.27 ms |
| 9a3ca655542f9224aa21b4838b439748a3043b4b+dirty | 326.93 ms | 330.14 ms | 3.21 ms |
| ad6c2993f6b77abbcf4094d17dd1fa9f7742ae99 | 375.94 ms | 382.02 ms | 6.08 ms |
| 9433f356583b99b5c970842ca1f926315bf23ba9 | 347.64 ms | 356.22 ms | 8.58 ms |
| d7401ac44acf524fe4d9a6a525f2cc13c70ce9e5+dirty | 375.20 ms | 383.51 ms | 8.31 ms |
| 15c80abcaf3bedf5d6f15c0eebefc9e7c1524da1+dirty | 336.27 ms | 350.58 ms | 14.31 ms |
| 86d6d2c81bc42209de70f7f3b97a1fbbde04025f+dirty | 332.90 ms | 352.45 ms | 19.55 ms |
| 3853f4362ec819042552ffa9ed30e8f6627e60bf | 329.68 ms | 346.32 ms | 16.64 ms |
| 22e31b6ad7bd629bf078367aee82121c08977ded | 396.48 ms | 419.64 ms | 23.16 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d197b5c9ca10ac3f729d1b3ef805328665aa0895+dirty | 17.73 MiB | 20.04 MiB | 2.31 MiB |
| acadc0f974a0c234a3d9010117b076792d14d6e8+dirty | 17.73 MiB | 19.75 MiB | 2.01 MiB |
| 9a3ca655542f9224aa21b4838b439748a3043b4b+dirty | 17.73 MiB | 20.04 MiB | 2.31 MiB |
| ad6c2993f6b77abbcf4094d17dd1fa9f7742ae99 | 17.73 MiB | 19.75 MiB | 2.02 MiB |
| 9433f356583b99b5c970842ca1f926315bf23ba9 | 17.73 MiB | 19.81 MiB | 2.08 MiB |
| d7401ac44acf524fe4d9a6a525f2cc13c70ce9e5+dirty | 17.73 MiB | 19.75 MiB | 2.02 MiB |
| 15c80abcaf3bedf5d6f15c0eebefc9e7c1524da1+dirty | 17.73 MiB | 20.04 MiB | 2.31 MiB |
| 86d6d2c81bc42209de70f7f3b97a1fbbde04025f+dirty | 17.73 MiB | 20.04 MiB | 2.31 MiB |
| 3853f4362ec819042552ffa9ed30e8f6627e60bf | 17.73 MiB | 19.81 MiB | 2.08 MiB |
| 22e31b6ad7bd629bf078367aee82121c08977ded | 17.73 MiB | 19.84 MiB | 2.10 MiB |
iOS (legacy) Performance metrics :rocket:
| Plain | With Sentry | Diff | |
|---|---|---|---|
| Startup time | 1226.62 ms | 1232.39 ms | 5.77 ms |
| Size | 2.36 MiB | 2.91 MiB | 561.07 KiB |
Baseline results on branch: main
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 80b2ce3d0ebe86bf1196944a2036912f6670295c+dirty | 1265.92 ms | 1268.60 ms | 2.69 ms |
| d7401ac44acf524fe4d9a6a525f2cc13c70ce9e5+dirty | 1252.38 ms | 1275.04 ms | 22.66 ms |
| e5c9b8b6d5ce209fa4b3a77aa9de65bd590fa727+dirty | 1258.57 ms | 1267.32 ms | 8.75 ms |
| acadc0f974a0c234a3d9010117b076792d14d6e8+dirty | 1264.38 ms | 1290.06 ms | 25.68 ms |
| 728164bd341a3b0e14876d86101c4bcca5b1f1ed+dirty | 1256.10 ms | 1259.08 ms | 2.98 ms |
| 3ffcddd6248046202afca78f6b9af8e3f591202c+dirty | 1244.47 ms | 1264.14 ms | 19.67 ms |
| 9a3ca655542f9224aa21b4838b439748a3043b4b+dirty | 1247.06 ms | 1274.58 ms | 27.52 ms |
| 457e29fc08e6edbebee646d095513d72728a5756+dirty | 1253.94 ms | 1269.18 ms | 15.24 ms |
| 12427f44d4b7746c431a369b538ec70ab2993c02+dirty | 1267.15 ms | 1271.30 ms | 4.15 ms |
| 25343377820b65409b646b44bc8e9bc9fbb51c8c+dirty | 1225.08 ms | 1230.26 ms | 5.17 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 80b2ce3d0ebe86bf1196944a2036912f6670295c+dirty | 2.36 MiB | 2.84 MiB | 486.98 KiB |
| d7401ac44acf524fe4d9a6a525f2cc13c70ce9e5+dirty | 2.36 MiB | 2.83 MiB | 481.14 KiB |
| e5c9b8b6d5ce209fa4b3a77aa9de65bd590fa727+dirty | 2.36 MiB | 2.87 MiB | 520.43 KiB |
| acadc0f974a0c234a3d9010117b076792d14d6e8+dirty | 2.36 MiB | 2.83 MiB | 480.37 KiB |
| 728164bd341a3b0e14876d86101c4bcca5b1f1ed+dirty | 2.36 MiB | 2.88 MiB | 530.38 KiB |
| 3ffcddd6248046202afca78f6b9af8e3f591202c+dirty | 2.36 MiB | 2.84 MiB | 489.60 KiB |
| 9a3ca655542f9224aa21b4838b439748a3043b4b+dirty | 2.36 MiB | 2.82 MiB | 462.89 KiB |
| 457e29fc08e6edbebee646d095513d72728a5756+dirty | 2.36 MiB | 2.87 MiB | 520.67 KiB |
| 12427f44d4b7746c431a369b538ec70ab2993c02+dirty | 2.36 MiB | 2.88 MiB | 530.38 KiB |
| 25343377820b65409b646b44bc8e9bc9fbb51c8c+dirty | 2.36 MiB | 2.88 MiB | 525.47 KiB |
Android (new) Performance metrics :rocket:
| Plain | With Sentry | Diff | |
|---|---|---|---|
| Startup time | 354.04 ms | 409.04 ms | 55.00 ms |
| Size | 7.15 MiB | 8.20 MiB | 1.05 MiB |
Baseline results on branch: main
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d197b5c9ca10ac3f729d1b3ef805328665aa0895+dirty | 258.75 ms | 313.61 ms | 54.86 ms |
| d361d3886b2303280797f653160c781700570edf+dirty | 257.72 ms | 318.76 ms | 61.04 ms |
| acadc0f974a0c234a3d9010117b076792d14d6e8+dirty | 259.04 ms | 304.67 ms | 45.63 ms |
| 9a3ca655542f9224aa21b4838b439748a3043b4b+dirty | 344.96 ms | 358.92 ms | 13.96 ms |
| 9433f356583b99b5c970842ca1f926315bf23ba9+dirty | 265.50 ms | 336.08 ms | 70.58 ms |
| 31fcca2b37834863733f6f21677efb4b7a490aa8+dirty | 366.64 ms | 395.78 ms | 29.14 ms |
| d7401ac44acf524fe4d9a6a525f2cc13c70ce9e5+dirty | 373.98 ms | 394.08 ms | 20.10 ms |
| 575f9da84059fc88110565adb1ffc0751799bcf4+dirty | 337.15 ms | 370.47 ms | 33.32 ms |
| 15c80abcaf3bedf5d6f15c0eebefc9e7c1524da1+dirty | 276.38 ms | 327.54 ms | 51.17 ms |
| 86d6d2c81bc42209de70f7f3b97a1fbbde04025f+dirty | 267.21 ms | 325.24 ms | 58.04 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d197b5c9ca10ac3f729d1b3ef805328665aa0895+dirty | 7.15 MiB | 8.09 MiB | 962.72 KiB |
| d361d3886b2303280797f653160c781700570edf+dirty | 7.15 MiB | 8.08 MiB | 959.34 KiB |
| acadc0f974a0c234a3d9010117b076792d14d6e8+dirty | 7.15 MiB | 8.03 MiB | 903.20 KiB |
| 9a3ca655542f9224aa21b4838b439748a3043b4b+dirty | 7.15 MiB | 8.09 MiB | 962.83 KiB |
| 9433f356583b99b5c970842ca1f926315bf23ba9+dirty | 7.15 MiB | 8.08 MiB | 959.34 KiB |
| 31fcca2b37834863733f6f21677efb4b7a490aa8+dirty | 7.15 MiB | 8.18 MiB | 1.03 MiB |
| d7401ac44acf524fe4d9a6a525f2cc13c70ce9e5+dirty | 7.15 MiB | 8.04 MiB | 910.85 KiB |
| 575f9da84059fc88110565adb1ffc0751799bcf4+dirty | 7.15 MiB | 8.10 MiB | 979.68 KiB |
| 15c80abcaf3bedf5d6f15c0eebefc9e7c1524da1+dirty | 7.15 MiB | 8.09 MiB | 966.13 KiB |
| 86d6d2c81bc42209de70f7f3b97a1fbbde04025f+dirty | 7.15 MiB | 8.09 MiB | 962.69 KiB |
iOS (new) Performance metrics :rocket:
| Plain | With Sentry | Diff | |
|---|---|---|---|
| Startup time | 1216.27 ms | 1217.92 ms | 1.65 ms |
| Size | 2.92 MiB | 3.48 MiB | 573.21 KiB |
Baseline results on branch: main
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 80b2ce3d0ebe86bf1196944a2036912f6670295c+dirty | 1245.12 ms | 1262.04 ms | 16.92 ms |
| d7401ac44acf524fe4d9a6a525f2cc13c70ce9e5+dirty | 1288.10 ms | 1289.54 ms | 1.44 ms |
| e5c9b8b6d5ce209fa4b3a77aa9de65bd590fa727+dirty | 1276.90 ms | 1280.92 ms | 4.02 ms |
| acadc0f974a0c234a3d9010117b076792d14d6e8+dirty | 1271.12 ms | 1272.28 ms | 1.16 ms |
| 728164bd341a3b0e14876d86101c4bcca5b1f1ed+dirty | 1280.06 ms | 1285.26 ms | 5.20 ms |
| 3ffcddd6248046202afca78f6b9af8e3f591202c+dirty | 1272.22 ms | 1273.98 ms | 1.76 ms |
| 9a3ca655542f9224aa21b4838b439748a3043b4b+dirty | 1276.40 ms | 1279.14 ms | 2.74 ms |
| 457e29fc08e6edbebee646d095513d72728a5756+dirty | 1256.71 ms | 1258.50 ms | 1.79 ms |
| 12427f44d4b7746c431a369b538ec70ab2993c02+dirty | 1224.90 ms | 1231.40 ms | 6.50 ms |
| 25343377820b65409b646b44bc8e9bc9fbb51c8c+dirty | 1220.87 ms | 1221.47 ms | 0.60 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 80b2ce3d0ebe86bf1196944a2036912f6670295c+dirty | 2.92 MiB | 3.40 MiB | 492.75 KiB |
| d7401ac44acf524fe4d9a6a525f2cc13c70ce9e5+dirty | 2.92 MiB | 3.40 MiB | 488.06 KiB |
| e5c9b8b6d5ce209fa4b3a77aa9de65bd590fa727+dirty | 2.92 MiB | 3.43 MiB | 524.50 KiB |
| acadc0f974a0c234a3d9010117b076792d14d6e8+dirty | 2.92 MiB | 3.39 MiB | 487.34 KiB |
| 728164bd341a3b0e14876d86101c4bcca5b1f1ed+dirty | 2.92 MiB | 3.44 MiB | 533.26 KiB |
| 3ffcddd6248046202afca78f6b9af8e3f591202c+dirty | 2.92 MiB | 3.40 MiB | 494.39 KiB |
| 9a3ca655542f9224aa21b4838b439748a3043b4b+dirty | 2.92 MiB | 3.37 MiB | 464.32 KiB |
| 457e29fc08e6edbebee646d095513d72728a5756+dirty | 2.92 MiB | 3.43 MiB | 524.75 KiB |
| 12427f44d4b7746c431a369b538ec70ab2993c02+dirty | 2.92 MiB | 3.44 MiB | 533.29 KiB |
| 25343377820b65409b646b44bc8e9bc9fbb51c8c+dirty | 2.92 MiB | 3.43 MiB | 529.76 KiB |