diff --git a/jest/setupMockFullstoryLib.ts b/jest/setupMockFullstoryLib.ts index 6fd0495e5ab0..82226627dfbb 100644 --- a/jest/setupMockFullstoryLib.ts +++ b/jest/setupMockFullstoryLib.ts @@ -17,11 +17,12 @@ export default function mockFSLibrary() { Page: FSPage, getChatFSClass: jest.fn(), init: jest.fn(), - onReady: jest.fn(), + onReady: jest.fn().mockResolvedValue(undefined), consent: jest.fn(), identify: jest.fn(), consentAndIdentify: jest.fn(), anonymize: jest.fn(), + getSessionId: jest.fn(), }; }); } diff --git a/src/CONST/index.ts b/src/CONST/index.ts index cf0c6368090a..b173002440fe 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -1610,6 +1610,9 @@ const CONST = { SHOW_HOVER_PREVIEW_ANIMATION_DURATION: 250, ACTIVITY_INDICATOR_TIMEOUT: 10000, }, + TELEMETRY: { + CONTEXT_FULLSTORY: 'Fullstory', + }, PRIORITY_MODE: { GSD: 'gsd', DEFAULT: 'default', diff --git a/src/Expensify.tsx b/src/Expensify.tsx index 5d392d350201..85c6e51515ee 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -43,6 +43,8 @@ import './libs/registerPaginationConfig'; import setCrashlyticsUserId from './libs/setCrashlyticsUserId'; import StartupTimer from './libs/StartupTimer'; // This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection +import './libs/TelemetrySynchronizer'; +// This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection import './libs/UnreadIndicatorUpdater'; import Visibility from './libs/Visibility'; import ONYXKEYS from './ONYXKEYS'; diff --git a/src/libs/Fullstory/index.native.ts b/src/libs/Fullstory/index.native.ts index 21fa6bb44aac..a88d82056f32 100644 --- a/src/libs/Fullstory/index.native.ts +++ b/src/libs/Fullstory/index.native.ts @@ -48,6 +48,10 @@ const FS: Fullstory = { }, anonymize: () => FullStory.anonymize(), + + getSessionId: () => { + return FullStory.getCurrentSession(); + }, }; export default FS; diff --git a/src/libs/Fullstory/index.ts b/src/libs/Fullstory/index.ts index ac2d941fb610..0f0cf0bea05a 100644 --- a/src/libs/Fullstory/index.ts +++ b/src/libs/Fullstory/index.ts @@ -87,6 +87,10 @@ const FS: Fullstory = { }, anonymize: () => FullStory(CONST.FULLSTORY.OPERATION.SET_IDENTITY, {anonymous: true}), + + getSessionId: () => { + return FullStory('getSessionAsync', {format: 'id'}); + }, }; export default FS; diff --git a/src/libs/Fullstory/types.ts b/src/libs/Fullstory/types.ts index 14d06b270f46..4c1901c8a43b 100644 --- a/src/libs/Fullstory/types.ts +++ b/src/libs/Fullstory/types.ts @@ -66,6 +66,11 @@ type Fullstory = { * Sets the identity as anonymous using the Fullstory library. */ anonymize: () => void; + + /** + * Returns the current Fullstory session ID. + */ + getSessionId: () => Promise; }; /** diff --git a/src/libs/TelemetrySynchronizer.ts b/src/libs/TelemetrySynchronizer.ts new file mode 100644 index 000000000000..43a1cfdaea8c --- /dev/null +++ b/src/libs/TelemetrySynchronizer.ts @@ -0,0 +1,19 @@ +/** + * This file contains the logic for sending additional data to Sentry. + * + * It uses Onyx.connectWithoutView as nothing here is related to the UI. We only send data to external provider and want to keep this outside of the render loop. + */ +import * as Sentry from '@sentry/react-native'; +import CONST from '@src/CONST'; +import FS from './Fullstory'; + +/** + * Connect to FullStory to retrieve session id from it. We want to link FullStory with Sentry for easier debugging. + */ +FS.onReady().then(async () => { + const sessionId = await FS.getSessionId(); + if (!sessionId) { + return; + } + Sentry.setContext(CONST.TELEMETRY.CONTEXT_FULLSTORY, {sessionId}); +});