@grafana/faro-react-native 1.3.1 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +176 -30
- package/android/build.gradle +17 -12
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashIds.kt +44 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashReporter.kt +134 -38
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashSessionStore.kt +433 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashTraceCache.kt +11 -2
- package/android/src/main/java/com/grafana/faro/reactnative/FaroReactNativeModule.kt +128 -17
- package/android/src/main/java/com/grafana/faro/reactnative/FaroSessionProcess.kt +88 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FrameMonitor.kt +34 -42
- package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashReporterBelowApi30Test.kt +21 -0
- package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashReporterTest.kt +59 -0
- package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashSessionStoreTest.kt +268 -0
- package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashTraceCacheTest.kt +52 -0
- package/android/src/test/java/com/grafana/faro/reactnative/FaroSessionProcessTest.kt +127 -0
- package/dist/cjs/config/getRNInstrumentations.js +6 -8
- package/dist/cjs/config/getRNInstrumentations.js.map +1 -1
- package/dist/cjs/config/makeRNConfig.js +5 -5
- package/dist/cjs/config/makeRNConfig.js.map +1 -1
- package/dist/cjs/config/sampling.js.map +1 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/dataCollection/DataCollectionPolicy.js +1 -2
- package/dist/cjs/dataCollection/DataCollectionPolicy.js.map +1 -1
- package/dist/cjs/generated/faroRNPackageMeta.js +1 -1
- package/dist/cjs/generated/faroRNPackageMeta.js.map +1 -1
- package/dist/cjs/index.js +8 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/instrumentations/anr/instrumentation.js +10 -1
- package/dist/cjs/instrumentations/anr/instrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/appState/index.js +8 -2
- package/dist/cjs/instrumentations/appState/index.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js +19 -6
- package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js +331 -0
- package/dist/cjs/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +2 -2
- package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +2 -2
- package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/types.js.map +1 -1
- package/dist/cjs/instrumentations/errors/index.js +8 -3
- package/dist/cjs/instrumentations/errors/index.js.map +1 -1
- package/dist/cjs/instrumentations/frameMonitoring/instrumentation.js +20 -31
- package/dist/cjs/instrumentations/frameMonitoring/instrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/frameMonitoring/types.js.map +1 -1
- package/dist/cjs/instrumentations/performance/index.js +2 -6
- package/dist/cjs/instrumentations/performance/index.js.map +1 -1
- package/dist/cjs/instrumentations/session/FaroSessionActivityBoundary.js +48 -0
- package/dist/cjs/instrumentations/session/FaroSessionActivityBoundary.js.map +1 -0
- package/dist/cjs/instrumentations/session/directSessionActivity.js +37 -0
- package/dist/cjs/instrumentations/session/directSessionActivity.js.map +1 -0
- package/dist/cjs/instrumentations/session/index.js +214 -45
- package/dist/cjs/instrumentations/session/index.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionActivity.js +43 -0
- package/dist/cjs/instrumentations/session/sessionActivity.js.map +1 -0
- package/dist/cjs/instrumentations/session/sessionAttributes.js +8 -8
- package/dist/cjs/instrumentations/session/sessionAttributes.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js +199 -24
- package/dist/cjs/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/VolatileSessionManager.js +31 -13
- package/dist/cjs/instrumentations/session/sessionManager/VolatileSessionManager.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/persistentSessionRecord.js +72 -0
- package/dist/cjs/instrumentations/session/sessionManager/persistentSessionRecord.js.map +1 -0
- package/dist/cjs/instrumentations/session/sessionManager/sessionConstants.js +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/sessionConstants.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/sessionManagerUtils.js +124 -96
- package/dist/cjs/instrumentations/session/sessionManager/sessionManagerUtils.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/types.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionProcess.js +96 -0
- package/dist/cjs/instrumentations/session/sessionProcess.js.map +1 -0
- package/dist/cjs/instrumentations/startup/index.js +2 -6
- package/dist/cjs/instrumentations/startup/index.js.map +1 -1
- package/dist/cjs/navigation/utils.js +3 -1
- package/dist/cjs/navigation/utils.js.map +1 -1
- package/dist/cjs/transports/fetch/index.js.map +1 -1
- package/dist/cjs/transports/fetch/transport.js +56 -25
- package/dist/cjs/transports/fetch/transport.js.map +1 -1
- package/dist/cjs/transports/fetch/types.js.map +1 -1
- package/dist/cjs/transports/offline/ConnectivityService.js +1 -1
- package/dist/cjs/transports/offline/ConnectivityService.js.map +1 -1
- package/dist/cjs/transports/offline/OfflineCache.js +2 -2
- package/dist/cjs/transports/offline/OfflineCache.js.map +1 -1
- package/dist/cjs/transports/offline/transport.js +3 -4
- package/dist/cjs/transports/offline/transport.js.map +1 -1
- package/dist/cjs/userPersistence/UserPersistence.js +1 -2
- package/dist/cjs/userPersistence/UserPersistence.js.map +1 -1
- package/dist/esm/config/getRNInstrumentations.js +6 -8
- package/dist/esm/config/getRNInstrumentations.js.map +1 -1
- package/dist/esm/config/makeRNConfig.js +5 -5
- package/dist/esm/config/makeRNConfig.js.map +1 -1
- package/dist/esm/config/sampling.js.map +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/dataCollection/DataCollectionPolicy.js +1 -2
- package/dist/esm/dataCollection/DataCollectionPolicy.js.map +1 -1
- package/dist/esm/generated/faroRNPackageMeta.js +1 -1
- package/dist/esm/generated/faroRNPackageMeta.js.map +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/instrumentations/anr/instrumentation.js +6 -1
- package/dist/esm/instrumentations/anr/instrumentation.js.map +1 -1
- package/dist/esm/instrumentations/appState/index.js +8 -2
- package/dist/esm/instrumentations/appState/index.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js +15 -4
- package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js +230 -0
- package/dist/esm/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +2 -2
- package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +2 -2
- package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/types.js.map +1 -1
- package/dist/esm/instrumentations/errors/index.js +8 -3
- package/dist/esm/instrumentations/errors/index.js.map +1 -1
- package/dist/esm/instrumentations/frameMonitoring/instrumentation.js +17 -32
- package/dist/esm/instrumentations/frameMonitoring/instrumentation.js.map +1 -1
- package/dist/esm/instrumentations/frameMonitoring/types.js.map +1 -1
- package/dist/esm/instrumentations/performance/index.js +2 -6
- package/dist/esm/instrumentations/performance/index.js.map +1 -1
- package/dist/esm/instrumentations/session/FaroSessionActivityBoundary.js +34 -0
- package/dist/esm/instrumentations/session/FaroSessionActivityBoundary.js.map +1 -0
- package/dist/esm/instrumentations/session/directSessionActivity.js +32 -0
- package/dist/esm/instrumentations/session/directSessionActivity.js.map +1 -0
- package/dist/esm/instrumentations/session/index.js +207 -46
- package/dist/esm/instrumentations/session/index.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionActivity.js +38 -0
- package/dist/esm/instrumentations/session/sessionActivity.js.map +1 -0
- package/dist/esm/instrumentations/session/sessionAttributes.js +7 -7
- package/dist/esm/instrumentations/session/sessionAttributes.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js +190 -27
- package/dist/esm/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionManager/VolatileSessionManager.js +31 -14
- package/dist/esm/instrumentations/session/sessionManager/VolatileSessionManager.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionManager/persistentSessionRecord.js +56 -0
- package/dist/esm/instrumentations/session/sessionManager/persistentSessionRecord.js.map +1 -0
- package/dist/esm/instrumentations/session/sessionManager/sessionConstants.js +1 -1
- package/dist/esm/instrumentations/session/sessionManager/sessionConstants.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionManager/sessionManagerUtils.js +120 -44
- package/dist/esm/instrumentations/session/sessionManager/sessionManagerUtils.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionManager/types.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionProcess.js +89 -0
- package/dist/esm/instrumentations/session/sessionProcess.js.map +1 -0
- package/dist/esm/instrumentations/startup/index.js +2 -6
- package/dist/esm/instrumentations/startup/index.js.map +1 -1
- package/dist/esm/navigation/utils.js +2 -1
- package/dist/esm/navigation/utils.js.map +1 -1
- package/dist/esm/transports/fetch/index.js.map +1 -1
- package/dist/esm/transports/fetch/transport.js +38 -14
- package/dist/esm/transports/fetch/transport.js.map +1 -1
- package/dist/esm/transports/fetch/types.js.map +1 -1
- package/dist/esm/transports/offline/ConnectivityService.js +1 -1
- package/dist/esm/transports/offline/ConnectivityService.js.map +1 -1
- package/dist/esm/transports/offline/OfflineCache.js +2 -2
- package/dist/esm/transports/offline/OfflineCache.js.map +1 -1
- package/dist/esm/transports/offline/transport.js +3 -4
- package/dist/esm/transports/offline/transport.js.map +1 -1
- package/dist/esm/userPersistence/UserPersistence.js +1 -2
- package/dist/esm/userPersistence/UserPersistence.js.map +1 -1
- package/dist/types/config/getRNInstrumentations.d.ts +1 -2
- package/dist/types/config/sampling.d.ts +0 -3
- package/dist/types/config/types.d.ts +5 -3
- package/dist/types/dataCollection/DataCollectionPolicy.d.ts +1 -2
- package/dist/types/generated/faroRNPackageMeta.d.ts +1 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/instrumentations/crashReporting/BaseCrashReportingInstrumentation.d.ts +14 -4
- package/dist/types/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.d.ts +27 -0
- package/dist/types/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.d.ts +2 -2
- package/dist/types/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.d.ts +2 -2
- package/dist/types/instrumentations/crashReporting/types.d.ts +6 -0
- package/dist/types/instrumentations/frameMonitoring/instrumentation.d.ts +2 -2
- package/dist/types/instrumentations/frameMonitoring/types.d.ts +4 -6
- package/dist/types/instrumentations/performance/index.d.ts +0 -2
- package/dist/types/instrumentations/session/FaroSessionActivityBoundary.d.ts +8 -0
- package/dist/types/instrumentations/session/directSessionActivity.d.ts +13 -0
- package/dist/types/instrumentations/session/index.d.ts +20 -1
- package/dist/types/instrumentations/session/sessionActivity.d.ts +9 -0
- package/dist/types/instrumentations/session/sessionAttributes.d.ts +6 -3
- package/dist/types/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.d.ts +16 -3
- package/dist/types/instrumentations/session/sessionManager/VolatileSessionManager.d.ts +9 -3
- package/dist/types/instrumentations/session/sessionManager/persistentSessionRecord.d.ts +4 -0
- package/dist/types/instrumentations/session/sessionManager/sessionManagerUtils.d.ts +19 -7
- package/dist/types/instrumentations/session/sessionManager/types.d.ts +6 -0
- package/dist/types/instrumentations/session/sessionProcess.d.ts +17 -0
- package/dist/types/instrumentations/startup/index.d.ts +2 -6
- package/dist/types/navigation/utils.d.ts +1 -0
- package/dist/types/transports/fetch/index.d.ts +1 -1
- package/dist/types/transports/fetch/transport.d.ts +8 -1
- package/dist/types/transports/fetch/types.d.ts +5 -0
- package/dist/types/transports/offline/ConnectivityService.d.ts +1 -1
- package/dist/types/transports/offline/OfflineCache.d.ts +2 -2
- package/dist/types/transports/offline/transport.d.ts +3 -4
- package/dist/types/userPersistence/UserPersistence.d.ts +1 -2
- package/ios/FaroCrashReporter.swift +214 -21
- package/ios/FaroReactNative.swift +24 -0
- package/ios/FaroReactNativeModule.h +2 -1
- package/ios/FaroReactNativeModule.mm +121 -6
- package/ios/RefreshRateVitals.swift +34 -38
- package/package.json +7 -5
- package/src/config/getRNInstrumentations.ts +6 -8
- package/src/config/makeRNConfig.test.ts +6 -0
- package/src/config/makeRNConfig.ts +10 -9
- package/src/config/sampling.ts +0 -3
- package/src/config/types.ts +5 -3
- package/src/dataCollection/DataCollectionPolicy.ts +1 -2
- package/src/generated/faroRNPackageMeta.ts +1 -1
- package/src/index.ts +8 -2
- package/src/initialize.test.ts +63 -2
- package/src/instrumentations/anr/instrumentation.ts +8 -1
- package/src/instrumentations/appState/index.ts +10 -2
- package/src/instrumentations/crashReporting/BaseCrashReportingInstrumentation.ts +28 -8
- package/src/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.ts +277 -0
- package/src/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.ts +2 -2
- package/src/instrumentations/crashReporting/instrumentation.test.ts +433 -5
- package/src/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.ts +2 -2
- package/src/instrumentations/crashReporting/types.ts +7 -0
- package/src/instrumentations/errors/index.ts +12 -4
- package/src/instrumentations/errors/instrumentation.test.ts +35 -0
- package/src/instrumentations/frameMonitoring/instrumentation.test.ts +155 -0
- package/src/instrumentations/frameMonitoring/instrumentation.ts +19 -38
- package/src/instrumentations/frameMonitoring/types.ts +4 -6
- package/src/instrumentations/performance/index.ts +2 -6
- package/src/instrumentations/session/FaroSessionActivityBoundary.test.ts +60 -0
- package/src/instrumentations/session/FaroSessionActivityBoundary.tsx +41 -0
- package/src/instrumentations/session/beforeSendHook.test.ts +246 -0
- package/src/instrumentations/session/directSessionActivity.test.ts +158 -0
- package/src/instrumentations/session/directSessionActivity.ts +36 -0
- package/src/instrumentations/session/index.ts +269 -46
- package/src/instrumentations/session/persistentColdStart.test.ts +196 -0
- package/src/instrumentations/session/sessionActivity.test.ts +68 -0
- package/src/instrumentations/session/sessionActivity.ts +58 -0
- package/src/instrumentations/session/sessionAttributes.test.ts +37 -2
- package/src/instrumentations/session/sessionAttributes.ts +12 -6
- package/src/instrumentations/session/sessionCleanup.test.ts +410 -0
- package/src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.test.ts +552 -0
- package/src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.ts +249 -33
- package/src/instrumentations/session/sessionManager/VolatileSessionManager.ts +38 -18
- package/src/instrumentations/session/sessionManager/persistentSessionRecord.test.ts +103 -0
- package/src/instrumentations/session/sessionManager/persistentSessionRecord.ts +78 -0
- package/src/instrumentations/session/sessionManager/sampling.test.ts +1 -1
- package/src/instrumentations/session/sessionManager/sessionConstants.ts +1 -1
- package/src/instrumentations/session/sessionManager/sessionManagerUtils.test.ts +256 -18
- package/src/instrumentations/session/sessionManager/sessionManagerUtils.ts +180 -39
- package/src/instrumentations/session/sessionManager/types.ts +8 -0
- package/src/instrumentations/session/sessionManagerInstance.test.ts +65 -0
- package/src/instrumentations/session/sessionProcess.test.ts +136 -0
- package/src/instrumentations/session/sessionProcess.ts +114 -0
- package/src/instrumentations/session/startNewSession.test.ts +337 -0
- package/src/instrumentations/startup/index.ts +2 -6
- package/src/navigation/utils.ts +3 -1
- package/src/transports/fetch/index.ts +6 -1
- package/src/transports/fetch/transport.test.ts +86 -2
- package/src/transports/fetch/transport.ts +38 -16
- package/src/transports/fetch/types.ts +7 -0
- package/src/transports/offline/ConnectivityService.ts +1 -1
- package/src/transports/offline/OfflineCache.ts +2 -2
- package/src/transports/offline/transport.ts +3 -4
- package/src/userPersistence/UserPersistence.ts +1 -2
- package/dist/cjs/utils/throttle.js +0 -42
- package/dist/cjs/utils/throttle.js.map +0 -1
- package/dist/esm/utils/throttle.js +0 -34
- package/dist/esm/utils/throttle.js.map +0 -1
- package/dist/types/utils/throttle.d.ts +0 -9
- package/src/utils/throttle.test.ts +0 -141
- package/src/utils/throttle.ts +0 -34
package/README.md
CHANGED
|
@@ -62,9 +62,7 @@ initializeFaro({
|
|
|
62
62
|
// Session - optional
|
|
63
63
|
sessionTracking: {
|
|
64
64
|
enabled: true,
|
|
65
|
-
persistent:
|
|
66
|
-
inactivityTimeout: 15 * 60 * 1000,
|
|
67
|
-
sessionExpirationTime: 4 * 60 * 60 * 1000,
|
|
65
|
+
persistent: true,
|
|
68
66
|
maxSessionPersistenceTime: 15 * 60 * 1000,
|
|
69
67
|
// Optional: sampling: new SamplingRate(0.1) or new SamplingFunction((ctx) => ...)
|
|
70
68
|
// Omit sampling to record all sessions (default).
|
|
@@ -178,6 +176,12 @@ This package’s **`android/build.gradle`** registers **`faroUploadComposedSourc
|
|
|
178
176
|
- **Crash Reporting Instrumentation** - Captures native crashes — `enableCrashReporting` (default: false)
|
|
179
177
|
- **Tracing Instrumentation** - OpenTelemetry distributed tracing (requires `@grafana/faro-react-native-tracing`) — `enableTracing` (default: false)
|
|
180
178
|
|
|
179
|
+
On iOS and Android 11 or newer, recovered native crashes are reported on the next launch with the session ID
|
|
180
|
+
and timestamp from the process that crashed. Failed deliveries remain pending for a later launch; Android
|
|
181
|
+
retries reports for up to seven days, while PLCrashReporter keeps one pending iOS report. The newly started
|
|
182
|
+
session continues to identify live telemetry. If the original session context is unavailable, the recovered
|
|
183
|
+
crash is skipped rather than assigned to the newly started session.
|
|
184
|
+
|
|
181
185
|
### React Integration
|
|
182
186
|
|
|
183
187
|
- **Error Boundary** - Catch and report React component errors with `FaroErrorBoundary`
|
|
@@ -777,7 +781,64 @@ initializeFaro({
|
|
|
777
781
|
|
|
778
782
|
### Session Configuration
|
|
779
783
|
|
|
780
|
-
|
|
784
|
+
Session persistence is enabled by default. The SDK does not bundle storage, so
|
|
785
|
+
apps using the default configuration must install the optional
|
|
786
|
+
`react-native-mmkv` peer dependency:
|
|
787
|
+
|
|
788
|
+
```bash
|
|
789
|
+
yarn add react-native-mmkv
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
Rebuild the native projects after installing or upgrading the SDK. A JavaScript-only
|
|
793
|
+
or OTA update cannot add the native process-coordination methods; when they are
|
|
794
|
+
unavailable, Faro uses an in-memory session rather than risking concurrent writes.
|
|
795
|
+
Apps using `persistent: false` use in-memory sessions and do not need MMKV.
|
|
796
|
+
|
|
797
|
+
Use `maxSessionPersistenceTime` to control the inactivity and cold-start linking window. A session's
|
|
798
|
+
maximum lifetime is fixed at four hours.
|
|
799
|
+
|
|
800
|
+
The inactivity window is refreshed only by meaningful activity:
|
|
801
|
+
|
|
802
|
+
| Activity source | Activity category |
|
|
803
|
+
| ------------------------------------------------------------------------- | ----------------- |
|
|
804
|
+
| Navigation and view changes | Meaningful |
|
|
805
|
+
| Return from `background` to `active` | Meaningful |
|
|
806
|
+
| Telemetry linked to a tracked user action | Meaningful |
|
|
807
|
+
| React Native touch starts inside `FaroSessionActivityBoundary` | Meaningful |
|
|
808
|
+
| Explicit `notifySessionActivity()` calls | Meaningful |
|
|
809
|
+
| Other app lifecycle events | Passive |
|
|
810
|
+
| Unmarked events, logs, errors, measurements, and traces | Passive |
|
|
811
|
+
| Unmarked HTTP and XHR requests | Passive |
|
|
812
|
+
| Unmarked session, startup, ANR, frame, console, and performance telemetry | Passive |
|
|
813
|
+
|
|
814
|
+
Passive telemetry still checks whether the session has expired, but it does not
|
|
815
|
+
keep the session alive. To refresh inactivity for ordinary touches without
|
|
816
|
+
emitting user-action telemetry, wrap the application once with
|
|
817
|
+
`FaroSessionActivityBoundary`:
|
|
818
|
+
|
|
819
|
+
```tsx
|
|
820
|
+
import { FaroSessionActivityBoundary } from '@grafana/faro-react-native';
|
|
821
|
+
|
|
822
|
+
export function App() {
|
|
823
|
+
return (
|
|
824
|
+
<FaroSessionActivityBoundary>
|
|
825
|
+
<AppNavigator />
|
|
826
|
+
</FaroSessionActivityBoundary>
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
The boundary observes touch-start responder negotiation from descendants
|
|
832
|
+
without becoming the responder. This covers standard React Native presses,
|
|
833
|
+
scrolling, dragging, and touches that focus inputs on Android and iOS.
|
|
834
|
+
Continued keyboard input after focus is not another touch. Interactions
|
|
835
|
+
rendered outside the boundary's React Native responder tree, or native and
|
|
836
|
+
accessibility interactions that do not produce a React Native touch event, are
|
|
837
|
+
also not observed. Call `notifySessionActivity()` from those paths. The
|
|
838
|
+
boundary renders a `flex: 1` view for root usage; pass `style` to override its
|
|
839
|
+
layout when wrapping a subtree. Use `withFaroUserAction` or `trackUserAction`
|
|
840
|
+
only when the interaction should also emit user-action telemetry and correlate
|
|
841
|
+
related work.
|
|
781
842
|
|
|
782
843
|
```tsx
|
|
783
844
|
import { initializeFaro, SamplingFunction, SamplingRate } from '@grafana/faro-react-native';
|
|
@@ -790,10 +851,8 @@ initializeFaro({
|
|
|
790
851
|
},
|
|
791
852
|
sessionTracking: {
|
|
792
853
|
enabled: true, // default: true
|
|
793
|
-
persistent: true, // default:
|
|
794
|
-
//
|
|
795
|
-
inactivityTimeout: 15 * 60 * 1000, // default: 15 min
|
|
796
|
-
sessionExpirationTime: 4 * 60 * 60 * 1000, // default: 4 h
|
|
854
|
+
persistent: true, // default: true
|
|
855
|
+
// Inactivity and cold-start linking window (ms):
|
|
797
856
|
maxSessionPersistenceTime: 15 * 60 * 1000, // default: 15 min
|
|
798
857
|
|
|
799
858
|
// Optional: session sampling (omit = all sessions recorded)
|
|
@@ -822,37 +881,78 @@ initializeFaro({
|
|
|
822
881
|
|
|
823
882
|
**Session Types:**
|
|
824
883
|
|
|
825
|
-
- **Persistent Sessions** (`persistent: true
|
|
884
|
+
- **Persistent Sessions** (`persistent: true`, default): A versioned record is stored in MMKV. Every process start creates a new session and links the previous ID when the record is valid. The live session is never resumed across a process start.
|
|
885
|
+
|
|
886
|
+
- **Volatile Sessions** (`persistent: false`): Stored in memory only. Each app launch creates a new session.
|
|
887
|
+
|
|
888
|
+
The persisted record contains only the current and previous session IDs, start and last-activity timestamps, the sampling decision, and a schema version. Session attributes, device state, and overrides remain in memory. Records older than `maxSessionPersistenceTime` are discarded. Unversioned records from earlier SDK versions, corrupt records, and unsupported schema versions are removed and start an unlinked session.
|
|
889
|
+
|
|
890
|
+
Persistent storage is isolated by native process:
|
|
891
|
+
|
|
892
|
+
- On Android, the main process keeps the existing MMKV storage ID. A process declared with `android:process` uses a separate record based on its full process name.
|
|
893
|
+
- On iOS, the host app keeps the existing MMKV storage ID. Each extension uses a separate record based on its `Bundle.main.bundleIdentifier`. Each target that initializes Faro must include the Faro native module and MMKV. Extension persistence requires `react-native-mmkv` v3 or newer so Faro can enable MMKV's multi-process mode; older versions fall back to memory in extensions.
|
|
894
|
+
- Each process maintains its own previous-session link. The `process_name` session attribute identifies which process or extension produced the telemetry.
|
|
895
|
+
|
|
896
|
+
Only one React Native runtime at a time may write a native process's record. An overlapping runtime that has already fallen back remains in memory for its lifetime. After the owning runtime is invalidated, a newly created replacement runtime can claim persistence. The SDK also falls back to memory when native process identity is unavailable, MMKV cannot be initialized safely, or exclusive ownership cannot be established, and logs a warning rather than risking concurrent writes.
|
|
826
897
|
|
|
827
|
-
|
|
898
|
+
A single session shared across Android processes or between an iOS host app and extension is not supported. Configuring an App Group does not merge Faro session chains between a host app and its extensions because their record IDs remain distinct. If multiple host apps share the same App Group, they share Faro's fixed host record ID; only one of those apps may use `persistent: true`, and the others must use `persistent: false`. Shared sessions would require a multi-process-safe store and native writer coordination. Use `persistent: false` for runtimes where an independent persisted chain is not wanted.
|
|
828
899
|
|
|
829
900
|
**Sampling:** Set `sessionTracking.sampling` to a `SamplingRate` (fixed 0–1) or `SamplingFunction` (dynamic, receives `context.meta`). Omit `sampling` to record all sessions. The decision is made once per session.
|
|
830
901
|
|
|
831
|
-
**Defaults:** `persistent=
|
|
902
|
+
**Defaults:** `persistent=true`, `maxSessionPersistenceTime=15min`. The maximum session lifetime is four hours.
|
|
832
903
|
|
|
833
904
|
**Session events:**
|
|
834
905
|
|
|
835
|
-
The SDK emits `session_start` when a new session is created
|
|
906
|
+
The SDK emits `session_start` when a new session is created, including each cold start and when session metadata changes to a new session ID.
|
|
907
|
+
|
|
908
|
+
**Starting a new linked session:**
|
|
909
|
+
|
|
910
|
+
Use `startNewSession()` after changing or clearing the current user at an
|
|
911
|
+
application-defined boundary. It immediately creates a new session, links the
|
|
912
|
+
previous session ID, restarts the lifetime, inactivity, and sampling windows,
|
|
913
|
+
and creates the normal `session_start` event. As with other telemetry, the event
|
|
914
|
+
is not exported when the new session is sampled out. Persistent sessions attempt
|
|
915
|
+
the synchronous MMKV write before the call returns; write failures are logged
|
|
916
|
+
and the new session remains active in memory.
|
|
917
|
+
|
|
918
|
+
```tsx
|
|
919
|
+
import { startNewSession } from '@grafana/faro-react-native';
|
|
920
|
+
|
|
921
|
+
function logout() {
|
|
922
|
+
faro.api.resetUser();
|
|
923
|
+
startNewSession();
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
function switchAccount(nextUserId: string) {
|
|
927
|
+
faro.api.setUser({ id: nextUserId });
|
|
928
|
+
startNewSession();
|
|
929
|
+
}
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
Any active user action is ended before the new session starts so its buffered telemetry
|
|
933
|
+
stays with the previous session. Calls made before Faro initializes, after
|
|
934
|
+
teardown, or while session tracking is disabled have no effect.
|
|
836
935
|
|
|
837
936
|
### Default Session Attributes
|
|
838
937
|
|
|
839
|
-
Every telemetry event automatically includes default session attributes with device and SDK information.
|
|
938
|
+
Every telemetry event automatically includes default session attributes with device and SDK information.
|
|
840
939
|
|
|
841
940
|
**Automatically Collected Attributes:**
|
|
842
941
|
|
|
843
|
-
| Attribute | Description | iOS Example
|
|
844
|
-
| ---------------------- | -------------------- |
|
|
845
|
-
| `faro_sdk_version` | SDK version | `2.0.2`
|
|
846
|
-
| `react_native_version` | React Native version | `0.75.1`
|
|
847
|
-
| `
|
|
848
|
-
| `
|
|
849
|
-
| `
|
|
850
|
-
| `
|
|
851
|
-
| `
|
|
852
|
-
| `
|
|
853
|
-
| `
|
|
854
|
-
| `
|
|
855
|
-
| `
|
|
942
|
+
| Attribute | Description | iOS Example | Android Example |
|
|
943
|
+
| ---------------------- | -------------------- | ---------------- | --------------------- |
|
|
944
|
+
| `faro_sdk_version` | SDK version | `2.0.2` | `2.0.2` |
|
|
945
|
+
| `react_native_version` | React Native version | `0.75.1` | `0.75.1` |
|
|
946
|
+
| `process_name` | Process identity | `com.acme.share` | `com.acme.app:sync` |
|
|
947
|
+
| `device_os` | Operating system | `iOS` | `Android` |
|
|
948
|
+
| `device_os_version` | OS version | `17.0` | `15` |
|
|
949
|
+
| `device_os_detail` | Detailed OS info | `iOS 17.0` | `Android 15 (SDK 35)` |
|
|
950
|
+
| `device_manufacturer` | Manufacturer | `apple` | `samsung` |
|
|
951
|
+
| `device_model` | Raw model identifier | `iPhone16,1` | `SM-A155F` |
|
|
952
|
+
| `device_model_name` | Human-readable model | `iPhone 15 Pro` | `SM-A155F`\* |
|
|
953
|
+
| `device_brand` | Device brand | `iPhone` | `samsung` |
|
|
954
|
+
| `device_is_physical` | Physical or emulator | `true` | `true` |
|
|
955
|
+
| `device_id` | Unique device ID | `uuid` | `uuid` |
|
|
856
956
|
|
|
857
957
|
\*Android does not provide a mapping from model codes to marketing names, so `device_model_name` equals `device_model`.
|
|
858
958
|
|
|
@@ -1067,6 +1167,43 @@ The SDK automatically tracks app startup time from process start to Faro initial
|
|
|
1067
1167
|
| avg
|
|
1068
1168
|
```
|
|
1069
1169
|
|
|
1170
|
+
#### Frame Monitoring (Refresh Rate, Slow & Frozen Frames)
|
|
1171
|
+
|
|
1172
|
+
Enable with `refreshRateVitals: true`. Uses native frame callbacks
|
|
1173
|
+
(`CADisplayLink` on iOS, `Choreographer` on Android).
|
|
1174
|
+
|
|
1175
|
+
**Defaults** (override via `frameMonitoringOptions`):
|
|
1176
|
+
|
|
1177
|
+
- **Frozen frame threshold**: 700ms (aligned with Android Vitals)
|
|
1178
|
+
- **Slow frame target**: 60 FPS (event-based grouping; events ≥50ms count)
|
|
1179
|
+
- **Poll interval**: 30s (`refreshRatePollingInterval`)
|
|
1180
|
+
|
|
1181
|
+
Slow and frozen frames are **polled** on both platforms (no duplicate
|
|
1182
|
+
Android event stream). Refresh rate may also emit on Android between polls
|
|
1183
|
+
when `refreshRateVitals` is enabled.
|
|
1184
|
+
|
|
1185
|
+
**Metrics:**
|
|
1186
|
+
|
|
1187
|
+
| Type | Values | Notes |
|
|
1188
|
+
| ------------------ | ---------------------------------- | ----------------------------------------------------- |
|
|
1189
|
+
| `app_refresh_rate` | `refresh_rate` | Current FPS |
|
|
1190
|
+
| `app_frames_rate` | `slow_frames` | Count of slow frame **events**, not individual frames |
|
|
1191
|
+
| `app_frozen_frame` | `frozen_frames`, `frozen_duration` | Frames above threshold; duration in ms |
|
|
1192
|
+
|
|
1193
|
+
**Configuration example:**
|
|
1194
|
+
|
|
1195
|
+
```tsx
|
|
1196
|
+
initializeFaro({
|
|
1197
|
+
url: 'https://your-faro-collector-url',
|
|
1198
|
+
app: { name: 'my-app', version: '1.0.0' },
|
|
1199
|
+
refreshRateVitals: true,
|
|
1200
|
+
frameMonitoringOptions: {
|
|
1201
|
+
frozenFrameThresholdMs: 700,
|
|
1202
|
+
refreshRatePollingInterval: 30000,
|
|
1203
|
+
},
|
|
1204
|
+
});
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1070
1207
|
#### Performance Best Practices
|
|
1071
1208
|
|
|
1072
1209
|
**For Production:**
|
|
@@ -1163,13 +1300,13 @@ The SDK collects the following device information synchronously:
|
|
|
1163
1300
|
|
|
1164
1301
|
## Device Information
|
|
1165
1302
|
|
|
1166
|
-
The SDK automatically collects device information and sends it as **session attributes** with every telemetry event.
|
|
1303
|
+
The SDK automatically collects device information and sends it as **session attributes** with every telemetry event.
|
|
1167
1304
|
|
|
1168
1305
|
### Session Attributes
|
|
1169
1306
|
|
|
1170
|
-
All device information is sent as session attributes (not browser meta)
|
|
1307
|
+
All device information is sent as session attributes (not browser meta):
|
|
1171
1308
|
|
|
1172
|
-
**Core Attributes
|
|
1309
|
+
**Core Attributes:**
|
|
1173
1310
|
|
|
1174
1311
|
- `faro_sdk_version` - SDK version (e.g., "1.0.0")
|
|
1175
1312
|
- `react_native_version` - React Native version (e.g., "0.75.1")
|
|
@@ -1244,7 +1381,7 @@ These attributes are automatically collected during Faro initialization and incl
|
|
|
1244
1381
|
- Session attributes are included with every telemetry event
|
|
1245
1382
|
- All fields are optional and gracefully handle permission errors
|
|
1246
1383
|
- The React Native SDK sends an empty `page` meta field to override faro-core's default web-specific page meta
|
|
1247
|
-
- Screen tracking is handled via `view` meta instead of `page` meta
|
|
1384
|
+
- Screen tracking is handled via `view` meta instead of `page` meta
|
|
1248
1385
|
- Battery, carrier, and low power mode info may not be available on all devices/OS versions
|
|
1249
1386
|
|
|
1250
1387
|
## TypeScript
|
|
@@ -1270,12 +1407,20 @@ See the [demo](../../demo) directory for a complete example application.
|
|
|
1270
1407
|
- `faro.api.pushMeasurement(measurement: Measurement)` - Track performance
|
|
1271
1408
|
- `faro.api.setUser(user: User)` - Identify users
|
|
1272
1409
|
- `faro.api.resetUser()` - Clear user identification
|
|
1410
|
+
- `startNewSession()` - Top-level API that starts a new session linked to the current session
|
|
1273
1411
|
|
|
1274
1412
|
### User Actions API
|
|
1275
1413
|
|
|
1276
1414
|
- `withFaroUserAction<P>(Component, defaultActionName)` - HOC for tracking component interactions
|
|
1277
1415
|
- `trackUserAction(actionName, context?)` - Manual user action tracking
|
|
1278
1416
|
|
|
1417
|
+
### Session Activity API
|
|
1418
|
+
|
|
1419
|
+
- `FaroSessionActivityBoundary` - Refresh session inactivity for touch starts
|
|
1420
|
+
inside a React Native responder subtree without emitting user-action telemetry
|
|
1421
|
+
- `notifySessionActivity()` - Refresh session inactivity for supported
|
|
1422
|
+
interactions outside the boundary
|
|
1423
|
+
|
|
1279
1424
|
### Error Boundary API
|
|
1280
1425
|
|
|
1281
1426
|
- `FaroErrorBoundary` - React component for catching and reporting component errors
|
|
@@ -1369,6 +1514,7 @@ console.debug('New event', {
|
|
|
1369
1514
|
### React Components
|
|
1370
1515
|
|
|
1371
1516
|
- `FaroErrorBoundary` - Error boundary component for catching React errors
|
|
1517
|
+
- `FaroSessionActivityBoundary` - Touch activity boundary for session inactivity
|
|
1372
1518
|
- `withFaroErrorBoundary` - HOC for wrapping components with error boundary
|
|
1373
1519
|
|
|
1374
1520
|
## Future Enhancements
|
package/android/build.gradle
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
buildscript {
|
|
2
|
+
// Follow the consumer app's Kotlin version. Pinning our own would ship a
|
|
3
|
+
// stdlib the app's compiler cannot read: Kotlin 1.9.x rejects 2.2 metadata,
|
|
4
|
+
// and our peer range still admits react-native >=0.70.0. The fallback only
|
|
5
|
+
// applies to apps whose root buildscript sets no kotlinVersion.
|
|
6
|
+
ext.faroKotlinVersion = rootProject.ext.has('kotlinVersion')
|
|
7
|
+
? rootProject.ext.get('kotlinVersion')
|
|
8
|
+
: '1.9.25'
|
|
9
|
+
|
|
2
10
|
repositories {
|
|
3
11
|
google()
|
|
4
12
|
mavenCentral()
|
|
@@ -6,8 +14,8 @@ buildscript {
|
|
|
6
14
|
|
|
7
15
|
dependencies {
|
|
8
16
|
classpath 'com.android.tools.build:gradle:7.4.2'
|
|
9
|
-
classpath
|
|
10
|
-
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.
|
|
17
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$faroKotlinVersion"
|
|
18
|
+
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.10.0'
|
|
11
19
|
}
|
|
12
20
|
}
|
|
13
21
|
|
|
@@ -17,20 +25,17 @@ apply plugin: 'com.google.protobuf'
|
|
|
17
25
|
|
|
18
26
|
android {
|
|
19
27
|
namespace 'com.grafana.faro.reactnative'
|
|
20
|
-
compileSdkVersion
|
|
28
|
+
compileSdkVersion 34
|
|
21
29
|
|
|
22
30
|
defaultConfig {
|
|
23
31
|
minSdkVersion 21
|
|
24
|
-
targetSdkVersion
|
|
32
|
+
targetSdkVersion 34
|
|
25
33
|
consumerProguardFiles 'consumer-proguard-rules.pro'
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
sourceSets {
|
|
29
37
|
main {
|
|
30
38
|
java.srcDirs = ['src/main/java']
|
|
31
|
-
proto {
|
|
32
|
-
srcDir 'src/main/proto'
|
|
33
|
-
}
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
41
|
|
|
@@ -45,7 +50,7 @@ android {
|
|
|
45
50
|
|
|
46
51
|
protobuf {
|
|
47
52
|
protoc {
|
|
48
|
-
artifact = 'com.google.protobuf:protoc:3.25.
|
|
53
|
+
artifact = 'com.google.protobuf:protoc:3.25.9'
|
|
49
54
|
}
|
|
50
55
|
generateProtoTasks {
|
|
51
56
|
all().each { task ->
|
|
@@ -66,12 +71,12 @@ repositories {
|
|
|
66
71
|
dependencies {
|
|
67
72
|
//noinspection GradleDynamicVersion
|
|
68
73
|
implementation 'com.facebook.react:react-native:+'
|
|
69
|
-
implementation
|
|
70
|
-
implementation 'com.google.protobuf:protobuf-javalite:3.25.
|
|
74
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$faroKotlinVersion"
|
|
75
|
+
implementation 'com.google.protobuf:protobuf-javalite:3.25.9'
|
|
71
76
|
|
|
72
77
|
testImplementation 'junit:junit:4.13.2'
|
|
73
|
-
testImplementation 'org.robolectric:robolectric:4.
|
|
74
|
-
testImplementation 'androidx.test:core:1.
|
|
78
|
+
testImplementation 'org.robolectric:robolectric:4.17'
|
|
79
|
+
testImplementation 'androidx.test:core:1.7.0'
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
/* ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package com.grafana.faro.reactnative
|
|
2
|
+
|
|
3
|
+
import java.security.MessageDigest
|
|
4
|
+
|
|
5
|
+
internal object FaroCrashIds {
|
|
6
|
+
private const val SCHEMA_VERSION = 1
|
|
7
|
+
|
|
8
|
+
fun sessionContextId(
|
|
9
|
+
sessionId: String,
|
|
10
|
+
activatedAtMs: Long,
|
|
11
|
+
pid: Int,
|
|
12
|
+
processName: String,
|
|
13
|
+
): String {
|
|
14
|
+
return digest("context", sessionId, activatedAtMs, pid, processName)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fun reportId(
|
|
18
|
+
packageName: String,
|
|
19
|
+
timestampMs: Long,
|
|
20
|
+
pid: Int,
|
|
21
|
+
processName: String,
|
|
22
|
+
): String {
|
|
23
|
+
return digest("report", packageName, timestampMs, pid, processName)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private fun digest(kind: String, vararg parts: Any): String {
|
|
27
|
+
val input = buildString {
|
|
28
|
+
append(SCHEMA_VERSION)
|
|
29
|
+
append('|')
|
|
30
|
+
append(kind)
|
|
31
|
+
for (part in parts) {
|
|
32
|
+
val value = part.toString()
|
|
33
|
+
append('|')
|
|
34
|
+
append(value.length)
|
|
35
|
+
append(':')
|
|
36
|
+
append(value)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
val hash = MessageDigest.getInstance("SHA-256")
|
|
40
|
+
.digest(input.toByteArray(Charsets.UTF_8))
|
|
41
|
+
.joinToString("") { byte -> "%02x".format(byte.toInt() and 0xff) }
|
|
42
|
+
return "v$SCHEMA_VERSION:$hash"
|
|
43
|
+
}
|
|
44
|
+
}
|