@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
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
package com.grafana.faro.reactnative
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import androidx.test.core.app.ApplicationProvider
|
|
5
|
+
import org.junit.Assert.assertEquals
|
|
6
|
+
import org.junit.Assert.assertFalse
|
|
7
|
+
import org.junit.Assert.assertNull
|
|
8
|
+
import org.junit.Assert.assertTrue
|
|
9
|
+
import org.junit.Before
|
|
10
|
+
import org.junit.Test
|
|
11
|
+
import org.junit.runner.RunWith
|
|
12
|
+
import org.robolectric.RobolectricTestRunner
|
|
13
|
+
import org.robolectric.annotation.Config
|
|
14
|
+
|
|
15
|
+
@RunWith(RobolectricTestRunner::class)
|
|
16
|
+
@Config(manifest = Config.NONE, sdk = [30])
|
|
17
|
+
class FaroCrashSessionStoreTest {
|
|
18
|
+
|
|
19
|
+
private lateinit var context: Context
|
|
20
|
+
|
|
21
|
+
@Before
|
|
22
|
+
fun setUp() {
|
|
23
|
+
context = ApplicationProvider.getApplicationContext()
|
|
24
|
+
context.getSharedPreferences(
|
|
25
|
+
"com.grafana.faro.crash_session_store",
|
|
26
|
+
Context.MODE_PRIVATE,
|
|
27
|
+
).edit().clear().commit()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Test
|
|
31
|
+
fun recordSessionContext_preservesFirstActivationForSessionUpdates() {
|
|
32
|
+
recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L)
|
|
33
|
+
recordSession("session-a", activatedAtMs = 2_000L, nowMs = 2_000L)
|
|
34
|
+
|
|
35
|
+
val contexts = FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 2_000L)
|
|
36
|
+
|
|
37
|
+
assertEquals(1, contexts.size)
|
|
38
|
+
assertEquals(1_000L, contexts.single().activatedAtMs)
|
|
39
|
+
assertEquals(2_000L, contexts.single().updatedAtMs)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@Test
|
|
43
|
+
fun findMatchingContext_usesLatestSessionBeforeCrashInSameProcess() {
|
|
44
|
+
recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L)
|
|
45
|
+
recordSession("session-b", activatedAtMs = 3_000L, nowMs = 3_000L)
|
|
46
|
+
|
|
47
|
+
val sessionA = FaroCrashSessionStore.findMatchingContext(
|
|
48
|
+
context,
|
|
49
|
+
crashTimestampMs = 2_000L,
|
|
50
|
+
pid = 101,
|
|
51
|
+
processName = "com.example.app",
|
|
52
|
+
nowMs = 4_000L,
|
|
53
|
+
)
|
|
54
|
+
val sessionB = FaroCrashSessionStore.findMatchingContext(
|
|
55
|
+
context,
|
|
56
|
+
crashTimestampMs = 4_000L,
|
|
57
|
+
pid = 101,
|
|
58
|
+
processName = "com.example.app",
|
|
59
|
+
nowMs = 4_000L,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
assertEquals("session-a", sessionA?.sessionId)
|
|
63
|
+
assertEquals("session-b", sessionB?.sessionId)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@Test
|
|
67
|
+
fun findMatchingContext_doesNotCrossProcessBoundaries() {
|
|
68
|
+
recordSession(
|
|
69
|
+
sessionId = "session-a",
|
|
70
|
+
activatedAtMs = 1_000L,
|
|
71
|
+
nowMs = 1_000L,
|
|
72
|
+
pid = 101,
|
|
73
|
+
)
|
|
74
|
+
recordSession(
|
|
75
|
+
sessionId = "session-b",
|
|
76
|
+
activatedAtMs = 2_000L,
|
|
77
|
+
nowMs = 2_000L,
|
|
78
|
+
pid = 202,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
val match = FaroCrashSessionStore.findMatchingContext(
|
|
82
|
+
context,
|
|
83
|
+
crashTimestampMs = 3_000L,
|
|
84
|
+
pid = 101,
|
|
85
|
+
processName = "com.example.app",
|
|
86
|
+
nowMs = 3_000L,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
assertEquals("session-a", match?.sessionId)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@Test
|
|
93
|
+
fun acknowledgeReports_removesOnlyItsOwnSessionContext() {
|
|
94
|
+
recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L, pid = 101)
|
|
95
|
+
recordSession("session-b", activatedAtMs = 2_000L, nowMs = 2_000L, pid = 202)
|
|
96
|
+
val contexts = FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 3_000L)
|
|
97
|
+
val sessionA = contexts.first { it.sessionId == "session-a" }
|
|
98
|
+
val sessionB = contexts.first { it.sessionId == "session-b" }
|
|
99
|
+
|
|
100
|
+
FaroCrashSessionStore.rememberPendingReport(
|
|
101
|
+
context,
|
|
102
|
+
reportId = "report-a",
|
|
103
|
+
crashTimestampMs = 1_500L,
|
|
104
|
+
sessionContext = sessionA,
|
|
105
|
+
usesPendingTrace = true,
|
|
106
|
+
nowMs = 3_000L,
|
|
107
|
+
)
|
|
108
|
+
FaroCrashSessionStore.rememberPendingReport(
|
|
109
|
+
context,
|
|
110
|
+
reportId = "report-b",
|
|
111
|
+
crashTimestampMs = 2_500L,
|
|
112
|
+
sessionContext = sessionB,
|
|
113
|
+
usesPendingTrace = false,
|
|
114
|
+
nowMs = 3_000L,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
val result = FaroCrashSessionStore.acknowledgeReports(
|
|
118
|
+
context,
|
|
119
|
+
reportIds = listOf("report-a"),
|
|
120
|
+
nowMs = 4_000L,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
val remaining = FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 4_000L)
|
|
124
|
+
assertTrue(result.clearPendingTrace)
|
|
125
|
+
assertTrue(FaroCrashSessionStore.isReportAcknowledged(context, "report-a", nowMs = 4_000L))
|
|
126
|
+
assertFalse(FaroCrashSessionStore.isReportAcknowledged(context, "report-b", nowMs = 4_000L))
|
|
127
|
+
assertEquals(listOf("session-b"), remaining.map { it.sessionId })
|
|
128
|
+
assertEquals(
|
|
129
|
+
"session-b",
|
|
130
|
+
FaroCrashSessionStore.contextForPendingReport(context, "report-b", nowMs = 4_000L)?.sessionId,
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@Test
|
|
135
|
+
fun acknowledgeReports_keepsContextReferencedByAnotherPendingReport() {
|
|
136
|
+
recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L)
|
|
137
|
+
val sessionA = FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 2_000L).single()
|
|
138
|
+
FaroCrashSessionStore.rememberPendingReport(
|
|
139
|
+
context,
|
|
140
|
+
"report-a",
|
|
141
|
+
1_500L,
|
|
142
|
+
sessionA,
|
|
143
|
+
usesPendingTrace = false,
|
|
144
|
+
nowMs = 2_000L,
|
|
145
|
+
)
|
|
146
|
+
FaroCrashSessionStore.rememberPendingReport(
|
|
147
|
+
context,
|
|
148
|
+
"report-b",
|
|
149
|
+
1_600L,
|
|
150
|
+
sessionA,
|
|
151
|
+
usesPendingTrace = false,
|
|
152
|
+
nowMs = 2_000L,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
FaroCrashSessionStore.acknowledgeReports(context, listOf("report-a"), nowMs = 3_000L)
|
|
156
|
+
|
|
157
|
+
assertEquals(
|
|
158
|
+
"session-a",
|
|
159
|
+
FaroCrashSessionStore.contextForPendingReport(context, "report-b", nowMs = 3_000L)?.sessionId,
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@Test
|
|
164
|
+
fun acknowledgeReports_clearsSharedTraceOnlyAfterLastReferencingReport() {
|
|
165
|
+
recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L)
|
|
166
|
+
val sessionA = FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 2_000L).single()
|
|
167
|
+
FaroCrashSessionStore.rememberPendingReport(
|
|
168
|
+
context,
|
|
169
|
+
"report-a",
|
|
170
|
+
1_500L,
|
|
171
|
+
sessionA,
|
|
172
|
+
usesPendingTrace = true,
|
|
173
|
+
nowMs = 2_000L,
|
|
174
|
+
)
|
|
175
|
+
FaroCrashSessionStore.rememberPendingReport(
|
|
176
|
+
context,
|
|
177
|
+
"report-b",
|
|
178
|
+
1_600L,
|
|
179
|
+
sessionA,
|
|
180
|
+
usesPendingTrace = true,
|
|
181
|
+
nowMs = 2_000L,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
val first = FaroCrashSessionStore.acknowledgeReports(context, listOf("report-a"), nowMs = 3_000L)
|
|
185
|
+
val second = FaroCrashSessionStore.acknowledgeReports(context, listOf("report-b"), nowMs = 4_000L)
|
|
186
|
+
|
|
187
|
+
assertTrue(first.persisted)
|
|
188
|
+
assertFalse(first.clearPendingTrace)
|
|
189
|
+
assertTrue(second.persisted)
|
|
190
|
+
assertTrue(second.clearPendingTrace)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@Test
|
|
194
|
+
fun acknowledgeReports_canTombstoneAnIgnoredReportWithoutPendingContext() {
|
|
195
|
+
val result = FaroCrashSessionStore.acknowledgeReports(
|
|
196
|
+
context,
|
|
197
|
+
reportIds = listOf("ignored-report"),
|
|
198
|
+
nowMs = 1_000L,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
assertTrue(result.persisted)
|
|
202
|
+
assertFalse(result.clearPendingTrace)
|
|
203
|
+
assertTrue(FaroCrashSessionStore.isReportAcknowledged(context, "ignored-report", nowMs = 1_000L))
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
@Test
|
|
207
|
+
fun sessionContextExpiresOnlyAfterSevenDayBoundary() {
|
|
208
|
+
val sevenDays = FaroCrashSessionStore.MAX_CONTEXT_AGE_MS
|
|
209
|
+
recordSession("at-boundary", activatedAtMs = 1L, nowMs = 1_000L)
|
|
210
|
+
|
|
211
|
+
assertEquals(
|
|
212
|
+
1,
|
|
213
|
+
FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 1_000L + sevenDays).size,
|
|
214
|
+
)
|
|
215
|
+
assertTrue(
|
|
216
|
+
FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 1_001L + sevenDays).isEmpty(),
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
@Test
|
|
221
|
+
fun malformedStorageDoesNotPreventNewContextFromBeingRecorded() {
|
|
222
|
+
context.getSharedPreferences(
|
|
223
|
+
"com.grafana.faro.crash_session_store",
|
|
224
|
+
Context.MODE_PRIVATE,
|
|
225
|
+
).edit().putString("session_contexts", "not-json").commit()
|
|
226
|
+
|
|
227
|
+
assertTrue(recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L))
|
|
228
|
+
assertEquals(
|
|
229
|
+
"session-a",
|
|
230
|
+
FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 1_000L).single().sessionId,
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
@Test
|
|
235
|
+
fun findMatchingContext_returnsNullWithoutUsableProcessIdentity() {
|
|
236
|
+
recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L)
|
|
237
|
+
|
|
238
|
+
val match = FaroCrashSessionStore.findMatchingContext(
|
|
239
|
+
context,
|
|
240
|
+
crashTimestampMs = 2_000L,
|
|
241
|
+
pid = 0,
|
|
242
|
+
processName = "",
|
|
243
|
+
nowMs = 2_000L,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
assertNull(match)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private fun recordSession(
|
|
250
|
+
sessionId: String,
|
|
251
|
+
activatedAtMs: Long,
|
|
252
|
+
nowMs: Long,
|
|
253
|
+
pid: Int = 101,
|
|
254
|
+
): Boolean {
|
|
255
|
+
return FaroCrashSessionStore.recordSessionContext(
|
|
256
|
+
context = context,
|
|
257
|
+
sessionId = sessionId,
|
|
258
|
+
activatedAtMs = activatedAtMs,
|
|
259
|
+
isSampled = true,
|
|
260
|
+
appVersion = "1.0.0",
|
|
261
|
+
appRelease = "42",
|
|
262
|
+
appBundleId = "com.example.app@42@1.0.0",
|
|
263
|
+
nowMs = nowMs,
|
|
264
|
+
pid = pid,
|
|
265
|
+
processName = "com.example.app",
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
package com.grafana.faro.reactnative
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import androidx.test.core.app.ApplicationProvider
|
|
5
|
+
import org.junit.Assert.assertEquals
|
|
6
|
+
import org.junit.Assert.assertNotNull
|
|
7
|
+
import org.junit.Assert.assertNull
|
|
8
|
+
import org.junit.Before
|
|
9
|
+
import org.junit.Test
|
|
10
|
+
import org.junit.runner.RunWith
|
|
11
|
+
import org.robolectric.RobolectricTestRunner
|
|
12
|
+
import org.robolectric.annotation.Config
|
|
13
|
+
|
|
14
|
+
@RunWith(RobolectricTestRunner::class)
|
|
15
|
+
@Config(manifest = Config.NONE, sdk = [30])
|
|
16
|
+
class FaroCrashTraceCacheTest {
|
|
17
|
+
|
|
18
|
+
private lateinit var context: Context
|
|
19
|
+
|
|
20
|
+
@Before
|
|
21
|
+
fun setUp() {
|
|
22
|
+
context = ApplicationProvider.getApplicationContext()
|
|
23
|
+
context.getSharedPreferences(
|
|
24
|
+
"com.grafana.faro.crash_trace_cache",
|
|
25
|
+
Context.MODE_PRIVATE,
|
|
26
|
+
).edit().clear().commit()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Test
|
|
30
|
+
fun timestampMismatchDoesNotClearTraceForLaterMatchingReport() {
|
|
31
|
+
FaroCrashTraceCache.savePendingCrashTrace(context, "java.lang.RuntimeException", 20_000L)
|
|
32
|
+
val pending = FaroCrashTraceCache.peekPendingCrashTrace(context, 20_001L)
|
|
33
|
+
|
|
34
|
+
assertEquals("", FaroCrashTraceCache.traceForExitTimestamp(context, pending, 1_000L))
|
|
35
|
+
assertNotNull(FaroCrashTraceCache.peekPendingCrashTrace(context, 20_001L))
|
|
36
|
+
assertEquals(
|
|
37
|
+
"java.lang.RuntimeException",
|
|
38
|
+
FaroCrashTraceCache.traceForExitTimestamp(context, pending, 20_000L),
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@Test
|
|
43
|
+
fun traceExpiresAfterReplayWindow() {
|
|
44
|
+
val timestamp = 20_000L
|
|
45
|
+
val replayWindow = FaroCrashSessionStore.MAX_CONTEXT_AGE_MS
|
|
46
|
+
FaroCrashTraceCache.savePendingCrashTrace(context, "java.lang.RuntimeException", timestamp)
|
|
47
|
+
|
|
48
|
+
assertNotNull(FaroCrashTraceCache.peekPendingCrashTrace(context, timestamp + replayWindow))
|
|
49
|
+
assertNull(FaroCrashTraceCache.peekPendingCrashTrace(context, timestamp + replayWindow + 1L))
|
|
50
|
+
assertNull(FaroCrashTraceCache.peekPendingCrashTrace(context, timestamp + replayWindow + 1L))
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
package com.grafana.faro.reactnative
|
|
2
|
+
|
|
3
|
+
import org.junit.After
|
|
4
|
+
import org.junit.Assert.assertEquals
|
|
5
|
+
import org.junit.Assert.assertFalse
|
|
6
|
+
import org.junit.Assert.assertNull
|
|
7
|
+
import org.junit.Assert.assertTrue
|
|
8
|
+
import org.junit.Before
|
|
9
|
+
import org.junit.Test
|
|
10
|
+
|
|
11
|
+
class FaroSessionProcessTest {
|
|
12
|
+
|
|
13
|
+
@Before
|
|
14
|
+
fun setUp() {
|
|
15
|
+
FaroSessionProcess.resetPersistenceClaimForTest()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@After
|
|
19
|
+
fun tearDown() {
|
|
20
|
+
FaroSessionProcess.resetPersistenceClaimForTest()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@Test
|
|
24
|
+
fun normalizeIdentifier_rejectsMissingProcessNames() {
|
|
25
|
+
assertNull(FaroSessionProcess.normalizeIdentifier(null))
|
|
26
|
+
assertNull(FaroSessionProcess.normalizeIdentifier(" "))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Test
|
|
30
|
+
fun normalizeIdentifier_trimsKnownProcessName() {
|
|
31
|
+
assertEquals(
|
|
32
|
+
"com.example.app:worker",
|
|
33
|
+
FaroSessionProcess.normalizeIdentifier(" com.example.app:worker "),
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@Test
|
|
38
|
+
fun identifier_usesThePlatformApiOnAndroidPAndNewer() {
|
|
39
|
+
assertEquals(
|
|
40
|
+
"com.example.app:worker",
|
|
41
|
+
FaroSessionProcess.identifier(
|
|
42
|
+
sdkInt = 28,
|
|
43
|
+
currentProcessName = { "com.example.app:worker" },
|
|
44
|
+
legacyProcessName = { error("legacy lookup should not run") },
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Test
|
|
50
|
+
fun identifier_readsTheNullTerminatedCmdlineBeforeAndroidP() {
|
|
51
|
+
assertEquals(
|
|
52
|
+
"com.example.app:worker",
|
|
53
|
+
FaroSessionProcess.identifier(
|
|
54
|
+
sdkInt = 27,
|
|
55
|
+
currentProcessName = { error("platform lookup should not run") },
|
|
56
|
+
legacyProcessName = { "com.example.app:worker\u0000ignored" },
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@Test
|
|
62
|
+
fun identifier_failsClosedWhenTheProcessNameCannotBeRead() {
|
|
63
|
+
assertNull(
|
|
64
|
+
FaroSessionProcess.identifier(
|
|
65
|
+
sdkInt = 27,
|
|
66
|
+
currentProcessName = { error("platform lookup should not run") },
|
|
67
|
+
legacyProcessName = { throw IllegalStateException("unavailable") },
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@Test
|
|
73
|
+
fun isMainProcess_comparesCurrentProcessWithDeclaredMainProcess() {
|
|
74
|
+
assertEquals(
|
|
75
|
+
true,
|
|
76
|
+
FaroSessionProcess.isMainProcess(
|
|
77
|
+
currentName = "com.example.app",
|
|
78
|
+
declaredMainName = "com.example.app",
|
|
79
|
+
packageName = "com.example.app",
|
|
80
|
+
),
|
|
81
|
+
)
|
|
82
|
+
assertEquals(
|
|
83
|
+
false,
|
|
84
|
+
FaroSessionProcess.isMainProcess(
|
|
85
|
+
currentName = "com.example.app:worker",
|
|
86
|
+
declaredMainName = "com.example.app",
|
|
87
|
+
packageName = "com.example.app",
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@Test
|
|
93
|
+
fun isMainProcess_usesPackageNameWhenMainProcessIsNotDeclared() {
|
|
94
|
+
assertEquals(
|
|
95
|
+
true,
|
|
96
|
+
FaroSessionProcess.isMainProcess(
|
|
97
|
+
currentName = "com.example.app",
|
|
98
|
+
declaredMainName = " ",
|
|
99
|
+
packageName = "com.example.app",
|
|
100
|
+
),
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@Test
|
|
105
|
+
fun isMainProcess_failsClosedWithoutCurrentIdentity() {
|
|
106
|
+
assertNull(
|
|
107
|
+
FaroSessionProcess.isMainProcess(
|
|
108
|
+
currentName = null,
|
|
109
|
+
declaredMainName = "com.example.app",
|
|
110
|
+
packageName = "com.example.app",
|
|
111
|
+
),
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@Test
|
|
116
|
+
fun claimPersistence_allowsOnlyOneOwnerAtATime() {
|
|
117
|
+
val firstOwner = Any()
|
|
118
|
+
val secondOwner = Any()
|
|
119
|
+
|
|
120
|
+
assertTrue(FaroSessionProcess.claimPersistence(firstOwner))
|
|
121
|
+
assertTrue(FaroSessionProcess.claimPersistence(firstOwner))
|
|
122
|
+
assertFalse(FaroSessionProcess.claimPersistence(secondOwner))
|
|
123
|
+
assertFalse(FaroSessionProcess.releasePersistence(secondOwner))
|
|
124
|
+
assertTrue(FaroSessionProcess.releasePersistence(firstOwner))
|
|
125
|
+
assertTrue(FaroSessionProcess.claimPersistence(secondOwner))
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -22,8 +22,7 @@ function toRegExpArray(patterns) {
|
|
|
22
22
|
/**
|
|
23
23
|
* Returns the default set of instrumentations for React Native.
|
|
24
24
|
*
|
|
25
|
-
* Reads all options from the Faro config (single source of truth)
|
|
26
|
-
* Property names are aligned with Flutter SDK FaroConfig:
|
|
25
|
+
* Reads all options from the Faro config (single source of truth):
|
|
27
26
|
* - cpuUsageVitals, memoryUsageVitals, anrTracking, refreshRateVitals
|
|
28
27
|
* - enableCrashReporting, enableErrorReporting
|
|
29
28
|
* - fetchVitalsInterval, ignoreUrls
|
|
@@ -44,7 +43,6 @@ function toRegExpArray(patterns) {
|
|
|
44
43
|
*/
|
|
45
44
|
function getRNInstrumentations(config) {
|
|
46
45
|
if (config === void 0) { config = {}; }
|
|
47
|
-
// Aligned with Flutter SDK FaroConfig defaults
|
|
48
46
|
var
|
|
49
47
|
// Error & crash tracking
|
|
50
48
|
_a = config.enableErrorReporting,
|
|
@@ -67,21 +65,21 @@ function getRNInstrumentations(config) {
|
|
|
67
65
|
// Tracing
|
|
68
66
|
enableTracing = _p === void 0 ? false : _p, _q = config.tracingOptions, tracingOptions = _q === void 0 ? {} : _q;
|
|
69
67
|
var instrumentations = [];
|
|
70
|
-
// Error reporting
|
|
68
|
+
// Error reporting
|
|
71
69
|
if (enableErrorReporting) {
|
|
72
70
|
instrumentations.push(new errors_1.ErrorsInstrumentation({
|
|
73
71
|
releaseBundleFilename: config.releaseBundleFilename,
|
|
74
72
|
}));
|
|
75
73
|
}
|
|
76
|
-
// Console capture
|
|
74
|
+
// Console capture
|
|
77
75
|
if (enableConsoleCapture) {
|
|
78
76
|
instrumentations.push(new console_1.ConsoleInstrumentation());
|
|
79
77
|
}
|
|
80
|
-
// Sessions
|
|
78
|
+
// Sessions
|
|
81
79
|
instrumentations.push(new session_1.SessionInstrumentation());
|
|
82
|
-
// Views
|
|
80
|
+
// Views
|
|
83
81
|
instrumentations.push(new view_1.ViewInstrumentation());
|
|
84
|
-
// App state
|
|
82
|
+
// App state
|
|
85
83
|
instrumentations.push(new appState_1.AppStateInstrumentation());
|
|
86
84
|
// User actions - enabled by default, opt-out via enableUserActions
|
|
87
85
|
if (enableUserActions) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getRNInstrumentations.js","sourceRoot":"","sources":["../../../src/config/getRNInstrumentations.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"getRNInstrumentations.js","sourceRoot":"","sources":["../../../src/config/getRNInstrumentations.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'react-native';\n\nimport type { Instrumentation, Patterns } from '@grafana/faro-core';\n\nimport { ANRInstrumentation } from '../instrumentations/anr';\nimport { AppStateInstrumentation } from '../instrumentations/appState';\nimport { ConsoleInstrumentation } from '../instrumentations/console';\nimport { CrashReportingInstrumentation } from '../instrumentations/crashReporting';\nimport { ErrorsInstrumentation } from '../instrumentations/errors';\nimport { FrameMonitoringInstrumentation } from '../instrumentations/frameMonitoring';\nimport { HttpInstrumentation } from '../instrumentations/http';\nimport { PerformanceInstrumentation } from '../instrumentations/performance';\nimport { SessionInstrumentation } from '../instrumentations/session';\nimport { StartupInstrumentation } from '../instrumentations/startup';\nimport { UserActionInstrumentation } from '../instrumentations/userActions';\nimport { ViewInstrumentation } from '../instrumentations/view';\nimport { XHRInstrumentation } from '../instrumentations/xhr';\n\nimport type { ReactNativeConfig } from './types';\n\n/** Convert Patterns (string | RegExp)[] to RegExp[] for instrumentations that require RegExp[]. */\nfunction toRegExpArray(patterns: Patterns): RegExp[] {\n return patterns.map((p) => (typeof p === 'string' ? new RegExp(p.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')) : p));\n}\n\n/**\n * Returns the default set of instrumentations for React Native.\n *\n * Reads all options from the Faro config (single source of truth):\n * - cpuUsageVitals, memoryUsageVitals, anrTracking, refreshRateVitals\n * - enableCrashReporting, enableErrorReporting\n * - fetchVitalsInterval, ignoreUrls\n *\n * @example\n * ```ts\n * const config: ReactNativeConfig = {\n * app: { name: 'my-app', version: '1.0.0' },\n * cpuUsageVitals: true,\n * memoryUsageVitals: true,\n * anrTracking: true,\n * refreshRateVitals: true,\n * enableCrashReporting: true,\n * fetchVitalsInterval: 30000,\n * instrumentations: getRNInstrumentations(config),\n * };\n * ```\n */\nexport function getRNInstrumentations(config: Partial<ReactNativeConfig> = {}): Instrumentation[] {\n const {\n // Error & crash tracking\n enableErrorReporting = true,\n enableCrashReporting = false,\n anrTracking = false,\n anrOptions = {},\n\n // Performance vitals\n cpuUsageVitals = true,\n memoryUsageVitals = true,\n refreshRateVitals = false,\n fetchVitalsInterval = 30000,\n frameMonitoringOptions = {},\n\n // Network\n ignoreUrls = [],\n enableHttpInstrumentation = {},\n\n // Console and user actions\n enableConsoleCapture = true,\n enableUserActions = true,\n\n // Tracing\n enableTracing = false,\n tracingOptions = {},\n } = config;\n\n const instrumentations: Instrumentation[] = [];\n\n // Error reporting\n if (enableErrorReporting) {\n instrumentations.push(\n new ErrorsInstrumentation({\n releaseBundleFilename: config.releaseBundleFilename,\n })\n );\n }\n\n // Console capture\n if (enableConsoleCapture) {\n instrumentations.push(new ConsoleInstrumentation());\n }\n\n // Sessions\n instrumentations.push(new SessionInstrumentation());\n\n // Views\n instrumentations.push(new ViewInstrumentation());\n\n // App state\n instrumentations.push(new AppStateInstrumentation());\n\n // User actions - enabled by default, opt-out via enableUserActions\n if (enableUserActions) {\n instrumentations.push(new UserActionInstrumentation());\n }\n\n // HTTP/XHR tracking: when tracing is enabled, TracingInstrumentation patches fetch and XHR.\n // When tracing is disabled, add HttpInstrumentation and/or XHRInstrumentation per enableHttpInstrumentation.\n if (!enableTracing) {\n const { fetch: enableFetch = true, xhr: enableXhr = true } = enableHttpInstrumentation;\n const ignoredUrlsRegExp = toRegExpArray(ignoreUrls);\n if (enableFetch) {\n instrumentations.push(new HttpInstrumentation({ ignoredUrls: ignoredUrlsRegExp }));\n }\n if (enableXhr) {\n instrumentations.push(new XHRInstrumentation({ ignoredUrls: ignoredUrlsRegExp }));\n }\n }\n\n // Performance vitals (CPU/memory) - only add if at least one metric is enabled\n if (cpuUsageVitals || memoryUsageVitals) {\n const perfInstrumentation = new PerformanceInstrumentation({\n memoryUsageVitals,\n cpuUsageVitals,\n fetchVitalsInterval,\n });\n instrumentations.push(perfInstrumentation);\n }\n\n // Startup tracking - always enabled\n instrumentations.push(new StartupInstrumentation());\n\n // Frame monitoring: enabled when refreshRateVitals is true\n // The instrumentation reads refreshRateVitals from faro.config (single source of truth)\n if (refreshRateVitals) {\n instrumentations.push(new FrameMonitoringInstrumentation(frameMonitoringOptions));\n }\n\n // ANR detection (Android only)\n if (anrTracking && Platform.OS === 'android') {\n instrumentations.push(new ANRInstrumentation(anrOptions));\n }\n\n // Crash reporting\n if (enableCrashReporting) {\n instrumentations.push(\n new CrashReportingInstrumentation({\n releaseBundleFilename: config.releaseBundleFilename,\n })\n );\n }\n\n if (enableTracing) {\n try {\n const { TracingInstrumentation } = require('@grafana/faro-react-native-tracing');\n instrumentations.push(new TracingInstrumentation(tracingOptions));\n } catch {\n console.warn(\n '[Faro] enableTracing is true but @grafana/faro-react-native-tracing is not installed. ' +\n 'Add it to use tracing: yarn add @grafana/faro-react-native-tracing'\n );\n }\n }\n\n return instrumentations;\n}\n"]}
|
|
@@ -124,12 +124,12 @@ function makeRNConfig(config, preloadedMobileMeta, appSymbolsBundleId) {
|
|
|
124
124
|
var instrumentations = buildInstrumentations(config);
|
|
125
125
|
var installationId = (_c = config.app.installationId) !== null && _c !== void 0 ? _c : preloadedAppMeta === null || preloadedAppMeta === void 0 ? void 0 : preloadedAppMeta.installationId;
|
|
126
126
|
var releaseBundleFilename = config.releaseBundleFilename;
|
|
127
|
-
// Merge bundleId (from config, Metro, or DeviceInfo) with preloaded app meta
|
|
128
127
|
var bundleIdValue = resolveAppBundleId(config.app, (_d = config.app) === null || _d === void 0 ? void 0 : _d.name, appSymbolsBundleId);
|
|
129
|
-
var
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
var app = __assign(__assign(__assign(__assign({}, preloadedAppMeta), config.app), (installationId && { installationId: installationId })), (bundleIdValue && { bundleId: bundleIdValue }));
|
|
129
|
+
// Core merges metadata shallowly. Supply the complete app object so native
|
|
130
|
+
// metadata cannot replace configured fields such as version and environment.
|
|
131
|
+
var appMetasIfPresent = preloadedAppMeta || bundleIdValue ? [{ app: app }] : [];
|
|
132
|
+
return __assign(__assign({ app: app }, (preloadedMobileMeta != null && {
|
|
133
133
|
preloadedMobileMeta: preloadedMobileMeta.meta,
|
|
134
134
|
preloadedSessionDeviceAttributes: preloadedMobileMeta.sessionAttributes,
|
|
135
135
|
})), { dedupe: (_e = config.dedupe) !== null && _e !== void 0 ? _e : true, globalObjectKey: (_f = config.globalObjectKey) !== null && _f !== void 0 ? _f : faro_core_1.defaultGlobalObjectKey, internalLoggerLevel: (_g = config.internalLoggerLevel) !== null && _g !== void 0 ? _g : internalLogger_1.InternalLoggerLevel.ERROR, isolate: (_h = config.isolate) !== null && _h !== void 0 ? _h : false, parseStacktrace: (_j = config.parseStacktrace) !== null && _j !== void 0 ? _j : createParseStacktrace(releaseBundleFilename), paused: (_k = config.paused) !== null && _k !== void 0 ? _k : false, preventGlobalExposure: (_l = config.preventGlobalExposure) !== null && _l !== void 0 ? _l : false, unpatchedConsole: (_m = config.unpatchedConsole) !== null && _m !== void 0 ? _m : faro_core_1.defaultUnpatchedConsole, batching: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makeRNConfig.js","sourceRoot":"","sources":["../../../src/config/makeRNConfig.ts"],"names":[],"mappings":"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","sourcesContent":["import { defaultGlobalObjectKey, defaultUnpatchedConsole } from '@grafana/faro-core';\nimport type { Config, MetaApp } from '@grafana/faro-core';\n\nimport { getStackFramesFromError } from '../instrumentations/errors/stackTraceParser';\nimport type { PreloadedMobileMeta } from '../instrumentations/session/sessionAttributes';\nimport { defaultSessionTrackingConfig } from '../instrumentations/session/sessionManager/sessionConstants';\nimport { InternalLoggerLevel, LogLevel } from '../internalLogger';\nimport { getMetroInjectedBundleId } from '../metas/appBuildIdentity';\nimport { getPageMeta } from '../metas/page';\nimport { getScreenMeta } from '../metas/screen';\nimport { getSdkMeta } from '../metas/sdk';\nimport { ConsoleTransport } from '../transports/console';\nimport { FetchTransport } from '../transports/fetch';\nimport { OfflineTransport } from '../transports/offline';\n\nimport { getRNInstrumentations } from './getRNInstrumentations';\nimport type { ReactNativeConfig, ReactNativeFullConfig } from './types';\n\nconst DEFAULT_OFFLINE_CACHE_MS = 3 * 24 * 60 * 60 * 1000; // 3 days\n\n/**\n * Resolves `meta.app.bundleId` when it is not already supplied by faro-core from\n * the Metro preamble (`registerInitialMetas` / `__faroBundleId_<appName>`).\n *\n * Priority: explicit `config.app.bundleId` → Metro preamble (core) → DeviceInfo\n * fallback (`applicationId@versionCode@versionName`, same shape Gradle/Metro use).\n */\nfunction resolveAppBundleId(\n configApp: MetaApp | undefined,\n appName: string | undefined,\n appSymbolsBundleId?: string\n): string | undefined {\n if (configApp?.bundleId) {\n return configApp.bundleId;\n }\n const metroId = getMetroInjectedBundleId(appName);\n if (metroId) {\n return metroId;\n }\n return appSymbolsBundleId;\n}\n\n/**\n * Builds transports. FetchTransport is always added when url is provided.\n * User can enable offline and console via enableTransports.\n */\nfunction buildTransports(config: ReactNativeConfig): Config['transports'] {\n const { enableTransports = { offline: false, console: false } } = config;\n\n if (!config.url) {\n throw new Error('url is required. Provide the Faro collector URL.');\n }\n\n const builtTransports: Config['transports'] = [];\n\n if (enableTransports.offline) {\n builtTransports.push(\n new OfflineTransport({\n maxCacheDurationMs: DEFAULT_OFFLINE_CACHE_MS,\n })\n );\n }\n\n builtTransports.push(\n new FetchTransport({\n url: config.url,\n apiKey: config.apiKey,\n })\n );\n\n if (enableTransports.console) {\n builtTransports.push(new ConsoleTransport({ level: LogLevel.DEBUG }));\n }\n\n const extraTransports = config.transports ?? [];\n return [...builtTransports, ...extraTransports];\n}\n\n/**\n * Builds instrumentations from config flags.\n */\nfunction buildInstrumentations(config: ReactNativeConfig): Config['instrumentations'] {\n const baseInstrumentations = getRNInstrumentations(config);\n const extraInstrumentations = config.instrumentations ?? [];\n return [...baseInstrumentations, ...extraInstrumentations];\n}\n\n/**\n * React Native stacktrace parser. Uses getStackFramesFromError for RN-specific formats.\n */\nfunction createParseStacktrace(releaseBundleFilename: string | undefined): Config['parseStacktrace'] {\n return (err) => ({\n frames: getStackFramesFromError(err, { releaseBundleFilename }),\n });\n}\n\n/**\n * Creates a full Faro config from React Native flag-based config.\n *\n * Based on flags, builds instrumentations and transports automatically.\n * Client just enables what they need; makeRNConfig does the rest.\n *\n * @param preloadedMobileMeta Device/session fields and structured mobile meta (passed from async `initializeFaro`).\n * @param appSymbolsBundleId Encoded `meta.app.bundleId` for server-side symbol retrace.\n */\nexport function makeRNConfig(\n config: ReactNativeConfig,\n preloadedMobileMeta?: PreloadedMobileMeta,\n appSymbolsBundleId?: string\n): ReactNativeFullConfig {\n const { app: preloadedAppMeta, ...structuredMobileMeta } = preloadedMobileMeta?.meta ?? {};\n const mobileMetas = Object.keys(structuredMobileMeta).length > 0 ? [structuredMobileMeta] : [];\n const defaultMetas = [getSdkMeta(), getPageMeta(), getScreenMeta(), ...mobileMetas];\n const customMetas = config.metas ?? [];\n const transports = buildTransports(config);\n const instrumentations = buildInstrumentations(config);\n const installationId = config.app.installationId ?? preloadedAppMeta?.installationId;\n\n const releaseBundleFilename = config.releaseBundleFilename;\n // Merge bundleId (from config, Metro, or DeviceInfo) with preloaded app meta\n const bundleIdValue = resolveAppBundleId(config.app, config.app?.name, appSymbolsBundleId);\n const appMetasIfPresent =\n preloadedAppMeta || bundleIdValue\n ? [{ app: { ...preloadedAppMeta, ...(bundleIdValue && { bundleId: bundleIdValue }) } }]\n : [];\n\n return {\n app: {\n ...config.app,\n ...(installationId && { installationId }),\n },\n ...(preloadedMobileMeta != null && {\n preloadedMobileMeta: preloadedMobileMeta.meta,\n preloadedSessionDeviceAttributes: preloadedMobileMeta.sessionAttributes,\n }),\n dedupe: config.dedupe ?? true,\n globalObjectKey: config.globalObjectKey ?? defaultGlobalObjectKey,\n internalLoggerLevel: config.internalLoggerLevel ?? InternalLoggerLevel.ERROR,\n isolate: config.isolate ?? false,\n parseStacktrace: config.parseStacktrace ?? createParseStacktrace(releaseBundleFilename),\n paused: config.paused ?? false,\n preventGlobalExposure: config.preventGlobalExposure ?? false,\n unpatchedConsole: config.unpatchedConsole ?? defaultUnpatchedConsole,\n batching: {\n enabled: false,\n sendTimeout: 250,\n itemLimit: 50,\n },\n sessionTracking: {\n ...defaultSessionTrackingConfig,\n ...config.sessionTracking,\n },\n metas: [...defaultMetas, ...customMetas, ...appMetasIfPresent],\n instrumentations,\n transports,\n ignoreUrls: config.ignoreUrls ?? [],\n ignoreErrors: config.ignoreErrors,\n beforeSend: config.beforeSend,\n preserveOriginalError: config.preserveOriginalError,\n userActionsInstrumentation: config.userActionsOptions,\n consoleInstrumentation: config.consoleCaptureOptions,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"makeRNConfig.js","sourceRoot":"","sources":["../../../src/config/makeRNConfig.ts"],"names":[],"mappings":"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","sourcesContent":["import { defaultGlobalObjectKey, defaultUnpatchedConsole } from '@grafana/faro-core';\nimport type { Config, MetaApp } from '@grafana/faro-core';\n\nimport { getStackFramesFromError } from '../instrumentations/errors/stackTraceParser';\nimport type { PreloadedMobileMeta } from '../instrumentations/session/sessionAttributes';\nimport { defaultSessionTrackingConfig } from '../instrumentations/session/sessionManager/sessionConstants';\nimport { InternalLoggerLevel, LogLevel } from '../internalLogger';\nimport { getMetroInjectedBundleId } from '../metas/appBuildIdentity';\nimport { getPageMeta } from '../metas/page';\nimport { getScreenMeta } from '../metas/screen';\nimport { getSdkMeta } from '../metas/sdk';\nimport { ConsoleTransport } from '../transports/console';\nimport { FetchTransport } from '../transports/fetch';\nimport { OfflineTransport } from '../transports/offline';\n\nimport { getRNInstrumentations } from './getRNInstrumentations';\nimport type { ReactNativeConfig, ReactNativeFullConfig } from './types';\n\nconst DEFAULT_OFFLINE_CACHE_MS = 3 * 24 * 60 * 60 * 1000; // 3 days\n\n/**\n * Resolves `meta.app.bundleId` when it is not already supplied by faro-core from\n * the Metro preamble (`registerInitialMetas` / `__faroBundleId_<appName>`).\n *\n * Priority: explicit `config.app.bundleId` → Metro preamble (core) → DeviceInfo\n * fallback (`applicationId@versionCode@versionName`, same shape Gradle/Metro use).\n */\nfunction resolveAppBundleId(\n configApp: MetaApp | undefined,\n appName: string | undefined,\n appSymbolsBundleId?: string\n): string | undefined {\n if (configApp?.bundleId) {\n return configApp.bundleId;\n }\n const metroId = getMetroInjectedBundleId(appName);\n if (metroId) {\n return metroId;\n }\n return appSymbolsBundleId;\n}\n\n/**\n * Builds transports. FetchTransport is always added when url is provided.\n * User can enable offline and console via enableTransports.\n */\nfunction buildTransports(config: ReactNativeConfig): Config['transports'] {\n const { enableTransports = { offline: false, console: false } } = config;\n\n if (!config.url) {\n throw new Error('url is required. Provide the Faro collector URL.');\n }\n\n const builtTransports: Config['transports'] = [];\n\n if (enableTransports.offline) {\n builtTransports.push(\n new OfflineTransport({\n maxCacheDurationMs: DEFAULT_OFFLINE_CACHE_MS,\n })\n );\n }\n\n builtTransports.push(\n new FetchTransport({\n url: config.url,\n apiKey: config.apiKey,\n })\n );\n\n if (enableTransports.console) {\n builtTransports.push(new ConsoleTransport({ level: LogLevel.DEBUG }));\n }\n\n const extraTransports = config.transports ?? [];\n return [...builtTransports, ...extraTransports];\n}\n\n/**\n * Builds instrumentations from config flags.\n */\nfunction buildInstrumentations(config: ReactNativeConfig): Config['instrumentations'] {\n const baseInstrumentations = getRNInstrumentations(config);\n const extraInstrumentations = config.instrumentations ?? [];\n return [...baseInstrumentations, ...extraInstrumentations];\n}\n\n/**\n * React Native stacktrace parser. Uses getStackFramesFromError for RN-specific formats.\n */\nfunction createParseStacktrace(releaseBundleFilename: string | undefined): Config['parseStacktrace'] {\n return (err) => ({\n frames: getStackFramesFromError(err, { releaseBundleFilename }),\n });\n}\n\n/**\n * Creates a full Faro config from React Native flag-based config.\n *\n * Based on flags, builds instrumentations and transports automatically.\n * Client just enables what they need; makeRNConfig does the rest.\n *\n * @param preloadedMobileMeta Device/session fields and structured mobile meta (passed from async `initializeFaro`).\n * @param appSymbolsBundleId Encoded `meta.app.bundleId` for server-side symbol retrace.\n */\nexport function makeRNConfig(\n config: ReactNativeConfig,\n preloadedMobileMeta?: PreloadedMobileMeta,\n appSymbolsBundleId?: string\n): ReactNativeFullConfig {\n const { app: preloadedAppMeta, ...structuredMobileMeta } = preloadedMobileMeta?.meta ?? {};\n const mobileMetas = Object.keys(structuredMobileMeta).length > 0 ? [structuredMobileMeta] : [];\n const defaultMetas = [getSdkMeta(), getPageMeta(), getScreenMeta(), ...mobileMetas];\n const customMetas = config.metas ?? [];\n const transports = buildTransports(config);\n const instrumentations = buildInstrumentations(config);\n const installationId = config.app.installationId ?? preloadedAppMeta?.installationId;\n\n const releaseBundleFilename = config.releaseBundleFilename;\n const bundleIdValue = resolveAppBundleId(config.app, config.app?.name, appSymbolsBundleId);\n const app = {\n ...preloadedAppMeta,\n ...config.app,\n ...(installationId && { installationId }),\n ...(bundleIdValue && { bundleId: bundleIdValue }),\n };\n // Core merges metadata shallowly. Supply the complete app object so native\n // metadata cannot replace configured fields such as version and environment.\n const appMetasIfPresent = preloadedAppMeta || bundleIdValue ? [{ app }] : [];\n\n return {\n app,\n ...(preloadedMobileMeta != null && {\n preloadedMobileMeta: preloadedMobileMeta.meta,\n preloadedSessionDeviceAttributes: preloadedMobileMeta.sessionAttributes,\n }),\n dedupe: config.dedupe ?? true,\n globalObjectKey: config.globalObjectKey ?? defaultGlobalObjectKey,\n internalLoggerLevel: config.internalLoggerLevel ?? InternalLoggerLevel.ERROR,\n isolate: config.isolate ?? false,\n parseStacktrace: config.parseStacktrace ?? createParseStacktrace(releaseBundleFilename),\n paused: config.paused ?? false,\n preventGlobalExposure: config.preventGlobalExposure ?? false,\n unpatchedConsole: config.unpatchedConsole ?? defaultUnpatchedConsole,\n batching: {\n enabled: false,\n sendTimeout: 250,\n itemLimit: 50,\n },\n sessionTracking: {\n ...defaultSessionTrackingConfig,\n ...config.sessionTracking,\n },\n metas: [...defaultMetas, ...customMetas, ...appMetasIfPresent],\n instrumentations,\n transports,\n ignoreUrls: config.ignoreUrls ?? [],\n ignoreErrors: config.ignoreErrors,\n beforeSend: config.beforeSend,\n preserveOriginalError: config.preserveOriginalError,\n userActionsInstrumentation: config.userActionsOptions,\n consoleInstrumentation: config.consoleCaptureOptions,\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sampling.js","sourceRoot":"","sources":["../../../src/config/sampling.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"sampling.js","sourceRoot":"","sources":["../../../src/config/sampling.ts"],"names":[],"mappings":";;;AA4EA;;;;;;;;;;;;GAYG;AACH;IACE;;;;OAIG;IACH,sBAA4B,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAE5C,8BAAO,GAAP,UAAQ,QAAyB;QAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,CAAC;IACH,mBAAC;AAAD,CAAC,AAXD,IAWC;AAXY,oCAAY;AAazB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;IACE;;;;;OAKG;IACH,0BAA6B,EAAwC;QAAxC,OAAE,GAAF,EAAE,CAAsC;IAAG,CAAC;IAEzE,kCAAO,GAAP,UAAQ,OAAwB;QAC9B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IACH,uBAAC;AAAD,CAAC,AAZD,IAYC;AAZY,4CAAgB","sourcesContent":["import type { Meta } from '@grafana/faro-core';\n\n/**\n * Context passed to sampling implementations.\n *\n * Provides access to the current metadata state at SDK initialization time,\n * allowing sampling decisions based on session attributes, user info, app\n * environment, and other metadata.\n *\n * @example\n * ```ts\n * sampling: SamplingFunction((context) => {\n * // Sample all beta users\n * if (context.meta.user?.attributes?.['role'] === 'beta') {\n * return 1;\n * }\n * // Sample 10% of production sessions\n * if (context.meta.app?.environment === 'production') {\n * return 0.1;\n * }\n * return 1;\n * })\n * ```\n */\nexport interface SamplingContext {\n /** The current merged metadata state (session, user, app, sdk, view). */\n meta: Meta;\n}\n\n/**\n * Defines how sessions should be sampled.\n *\n * Implement this interface to provide custom sampling logic. Use one of the\n * built-in implementations:\n * - {@link SamplingRate} for a fixed sampling rate\n * - {@link SamplingFunction} for dynamic sampling based on context\n *\n * @example\n * ```ts\n * // Fixed 10% sampling\n * sessionTracking: {\n * sampling: new SamplingRate(0.1),\n * }\n *\n * // Dynamic sampling based on context\n * sessionTracking: {\n * sampling: new SamplingFunction((context) => {\n * if (context.meta.app?.environment === 'production') {\n * return 0.1;\n * }\n * return 1;\n * }),\n * }\n *\n * // Custom implementation\n * class BetaUserSampling implements Sampling {\n * resolve(context: SamplingContext): number {\n * return context.meta.user?.attributes?.['role'] === 'beta' ? 1 : 0.1;\n * }\n * }\n * sessionTracking: { sampling: new BetaUserSampling() }\n * ```\n */\nexport interface Sampling {\n /**\n * Resolves the sampling rate for the given context.\n *\n * @param context - The current metadata state\n * @returns A value between 0 and 1 (inclusive). Values are clamped to [0, 1].\n * - 1: Sample all sessions (100%)\n * - 0.5: Sample half of sessions (50%)\n * - 0: Sample no sessions (0%)\n */\n resolve(context: SamplingContext): number;\n}\n\n/**\n * Fixed sampling rate.\n *\n * Use this when you want a constant sampling probability regardless of\n * session context.\n *\n * @example\n * ```ts\n * sessionTracking: {\n * sampling: new SamplingRate(0.1), // 10% of sessions\n * }\n * ```\n */\nexport class SamplingRate implements Sampling {\n /**\n * Creates a fixed sampling rate.\n *\n * @param rate - The fixed sampling rate (0 to 1). Values are clamped to [0, 1].\n */\n constructor(public readonly rate: number) {}\n\n resolve(_context: SamplingContext): number {\n return Math.max(0, Math.min(1, this.rate));\n }\n}\n\n/**\n * Dynamic sampling based on context.\n *\n * Use this when you want to make sampling decisions based on session\n * metadata like user attributes, app environment, or other context.\n *\n * @example\n * ```ts\n * sessionTracking: {\n * sampling: new SamplingFunction((context) => {\n * // Sample all beta users\n * if (context.meta.user?.attributes?.['role'] === 'beta') {\n * return 1;\n * }\n * // Sample 10% of production sessions\n * if (context.meta.app?.environment === 'production') {\n * return 0.1;\n * }\n * return 1;\n * }),\n * }\n * ```\n */\nexport class SamplingFunction implements Sampling {\n /**\n * Creates a dynamic sampler with the given function.\n *\n * @param fn - The function that determines the rate based on context.\n * Receives a {@link SamplingContext} and should return a rate between 0 and 1.\n */\n constructor(private readonly fn: (context: SamplingContext) => number) {}\n\n resolve(context: SamplingContext): number {\n return Math.max(0, Math.min(1, this.fn(context)));\n }\n}\n"]}
|