Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1658,6 +1658,7 @@ const CONST = {
CONTEXT_FULLSTORY: 'Fullstory',
CONTEXT_POLICIES: 'Policies',
TAG_ACTIVE_POLICY: 'active_policy_id',
// Span names
SPAN_OPEN_REPORT: 'ManualOpenReport',
SPAN_APP_STARTUP: 'ManualAppStartup',
SPAN_NAVIGATE_TO_REPORTS_TAB: 'ManualNavigateToReportsTab',
Expand All @@ -1667,11 +1668,14 @@ const CONST = {
SPAN_OPEN_SEARCH_ROUTER: 'ManualOpenSearchRouter',
SPAN_OPEN_CREATE_EXPENSE: 'ManualOpenCreateExpense',
SPAN_SEND_MESSAGE: 'ManualSendMessage',
// Attribute names
ATTRIBUTE_IOU_TYPE: 'iou_type',
ATTRIBUTE_IOU_REQUEST_TYPE: 'iou_request_type',
ATTRIBUTE_REPORT_ID: 'report_id',
ATTRIBUTE_SOURCE_ROUTE: 'source_route',
ATTRIBUTE_MESSAGE_LENGTH: 'message_length',
ATTRIBUTE_CANCELED: 'canceled',
ATTRIBUTE_ROUTE_FROM: 'route_from',
ATTRIBUTE_ROUTE_TO: 'route_to',
},
PRIORITY_MODE: {
GSD: 'gsd',
Expand Down
5 changes: 5 additions & 0 deletions src/components/LHNOptionsList/OptionRowLHN.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import DisplayNames from '@components/DisplayNames';
import Hoverable from '@components/Hoverable';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';

Check warning on line 7 in src/components/LHNOptionsList/OptionRowLHN.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'@components/Icon/Expensicons' import is restricted from being used by a pattern. Direct imports from Icon/Expensicons are deprecated. Please use lazy loading hooks instead. Use `useMemoizedLazyExpensifyIcons` from @hooks/useLazyAsset. See docs/LAZY_ICONS_AND_ILLUSTRATIONS.md for details

Check warning on line 7 in src/components/LHNOptionsList/OptionRowLHN.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'@components/Icon/Expensicons' import is restricted from being used. Direct imports from @components/Icon/Expensicons are deprecated. Please use lazy loading hooks instead. Use `useMemoizedLazyExpensifyIcons` from @hooks/useLazyAsset. See docs/LAZY_ICONS_AND_ILLUSTRATIONS.md for details
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import {useSession} from '@components/OnyxListItemProvider';
import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
Expand All @@ -26,6 +26,7 @@
import Performance from '@libs/Performance';
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
import {isAdminRoom, isChatUsedForOnboarding as isChatUsedForOnboardingReportUtils, isConciergeChatReport, isGroupChat, isOneOnOneChat, isSystemChat} from '@libs/ReportUtils';
import {startSpan} from '@libs/telemetry/activeSpans';
import TextWithEmojiFragment from '@pages/home/report/comment/TextWithEmojiFragment';
import {showContextMenu} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
import FreeTrial from '@pages/settings/Subscription/FreeTrial';
Expand Down Expand Up @@ -169,6 +170,10 @@
const onOptionPress = (event: GestureResponderEvent | KeyboardEvent | undefined) => {
Performance.markStart(CONST.TIMING.OPEN_REPORT);
Timing.start(CONST.TIMING.OPEN_REPORT);
startSpan(`${CONST.TELEMETRY.SPAN_OPEN_REPORT}_${reportID}`, {
name: 'OptionRowLHN',
op: CONST.TELEMETRY.SPAN_OPEN_REPORT,
});

event?.preventDefault();
// Enable Composer to focus on clicking the same chat after opening the context menu.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {PortalHost} from '@gorhom/portal';
import React, {useCallback, useMemo} from 'react';
import React, {useCallback, useEffect, useMemo} from 'react';
import {InteractionManager, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import HeaderGap from '@components/HeaderGap';
Expand All @@ -23,6 +23,7 @@ import navigationRef from '@libs/Navigation/navigationRef';
import {getFilteredReportActionsForReportView, getOneTransactionThreadReportID, isMoneyRequestAction, isSentMoneyReportAction} from '@libs/ReportActionsUtils';
import {canEditReportAction, getReportOfflinePendingActionAndErrors, isReportTransactionThread} from '@libs/ReportUtils';
import {buildCannedSearchQuery} from '@libs/SearchQueryUtils';
import {cancelSpan} from '@libs/telemetry/activeSpans';
import Navigation from '@navigation/Navigation';
import ReportActionsView from '@pages/home/report/ReportActionsView';
import ReportFooter from '@pages/home/report/ReportFooter';
Expand Down Expand Up @@ -164,6 +165,11 @@ function MoneyRequestReportView({report, policy, reportMetadata, shouldDisplayRe
[backToRoute, isLoadingInitialReportActions, isTransactionThreadView, parentReportAction, policy, report, reportActions, transactionThreadReportID],
);

// We need to cancel telemetry span when user leaves the screen before full report data is loaded
useEffect(() => {
return () => cancelSpan(`${CONST.TELEMETRY.SPAN_OPEN_REPORT}_${reportID}`);
}, [reportID]);

if (!!(isLoadingInitialReportActions && reportActions.length === 0 && !isOffline) || shouldWaitForTransactions) {
return <InitialLoadingSkeleton styles={styles} />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import ConfirmModal from '@components/ConfirmModal';
import {DelegateNoAccessContext} from '@components/DelegateNoAccessModalProvider';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';

Check warning on line 14 in src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'@components/Icon/Expensicons' import is restricted from being used by a pattern. Direct imports from Icon/Expensicons are deprecated. Please use lazy loading hooks instead. Use `useMemoizedLazyExpensifyIcons` from @hooks/useLazyAsset. See docs/LAZY_ICONS_AND_ILLUSTRATIONS.md for details

Check warning on line 14 in src/components/ReportActionItem/MoneyRequestReportPreview/MoneyRequestReportPreviewContent.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'@components/Icon/Expensicons' import is restricted from being used. Direct imports from @components/Icon/Expensicons are deprecated. Please use lazy loading hooks instead. Use `useMemoizedLazyExpensifyIcons` from @hooks/useLazyAsset. See docs/LAZY_ICONS_AND_ILLUSTRATIONS.md for details
import type {PaymentMethod} from '@components/KYCWall/types';
import MoneyReportHeaderStatusBarSkeleton from '@components/MoneyReportHeaderStatusBarSkeleton';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
Expand Down Expand Up @@ -75,6 +75,7 @@
isWaitingForSubmissionFromCurrentUser as isWaitingForSubmissionFromCurrentUserReportUtils,
} from '@libs/ReportUtils';
import shouldAdjustScroll from '@libs/shouldAdjustScroll';
import {startSpan} from '@libs/telemetry/activeSpans';
import {hasPendingUI, isManagedCardTransaction, isPending} from '@libs/TransactionUtils';
import colors from '@styles/theme/colors';
import variables from '@styles/variables';
Expand Down Expand Up @@ -481,6 +482,10 @@
}
Performance.markStart(CONST.TIMING.OPEN_REPORT_FROM_PREVIEW);
Timing.start(CONST.TIMING.OPEN_REPORT_FROM_PREVIEW);
startSpan(`${CONST.TELEMETRY.SPAN_OPEN_REPORT}_${iouReportID}`, {
name: 'MoneyRequestReportPreviewContent',
op: CONST.TELEMETRY.SPAN_OPEN_REPORT,
});
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(iouReportID, undefined, undefined, Navigation.getActiveRoute()));
}, [iouReportID]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import FS from '@libs/Fullstory';
import Performance from '@libs/Performance';
import {getIOUActionForReportID, isSplitBillAction as isSplitBillActionReportActionsUtils, isTrackExpenseAction as isTrackExpenseActionReportActionsUtils} from '@libs/ReportActionsUtils';
import {isIOUReport} from '@libs/ReportUtils';
import {startSpan} from '@libs/telemetry/activeSpans';
import Navigation from '@navigation/Navigation';
import {contextMenuRef} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
import Timing from '@userActions/Timing';
Expand Down Expand Up @@ -106,6 +107,10 @@ function MoneyRequestReportPreview({

Performance.markStart(CONST.TIMING.OPEN_REPORT_FROM_PREVIEW);
Timing.start(CONST.TIMING.OPEN_REPORT_FROM_PREVIEW);
startSpan(`${CONST.TELEMETRY.SPAN_OPEN_REPORT}_${iouReportID}`, {
name: 'MoneyRequestReportPreview',
op: CONST.TELEMETRY.SPAN_OPEN_REPORT,
});
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(iouReportID, undefined, undefined, Navigation.getActiveRoute()));
}, [iouReportID]);

Expand Down
6 changes: 5 additions & 1 deletion src/components/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import {
shouldShowEmptyState,
shouldShowYear as shouldShowYearUtil,
} from '@libs/SearchUIUtils';
import {endSpan} from '@libs/telemetry/activeSpans';
import {endSpan, startSpan} from '@libs/telemetry/activeSpans';
import {isOnHold, isTransactionPendingDelete, mergeProhibitedViolations, shouldShowViolation} from '@libs/TransactionUtils';
import Navigation, {navigationRef} from '@navigation/Navigation';
import type {SearchFullscreenNavigatorParamList} from '@navigation/types';
Expand Down Expand Up @@ -730,6 +730,10 @@ function Search({

Performance.markStart(CONST.TIMING.OPEN_REPORT_SEARCH);
Timing.start(CONST.TIMING.OPEN_REPORT_SEARCH);
startSpan(`${CONST.TELEMETRY.SPAN_OPEN_REPORT}_${reportID}`, {
name: 'Search',
op: CONST.TELEMETRY.SPAN_OPEN_REPORT,
});

if (isTransactionGroupListItemType(item)) {
const firstTransaction = item.transactions.at(0);
Expand Down
30 changes: 19 additions & 11 deletions src/libs/Navigation/Navigation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {findFocusedRoute, getActionFromState} from '@react-navigation/core';
import type {EventArg, NavigationAction, NavigationContainerEventMap, NavigationState} from '@react-navigation/native';
import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native';
import {Str} from 'expensify-common';
// eslint-disable-next-line you-dont-need-lodash-underscore/omit
import omit from 'lodash/omit';
import {InteractionManager} from 'react-native';
Expand All @@ -10,7 +11,7 @@ import type {Writable} from 'type-fest';
import getIsNarrowLayout from '@libs/getIsNarrowLayout';
import Log from '@libs/Log';
import {shallowCompare} from '@libs/ObjectUtils';
import {startSpan} from '@libs/telemetry/activeSpans';
import {getSpan, startSpan} from '@libs/telemetry/activeSpans';
import CONST from '@src/CONST';
import NAVIGATORS from '@src/NAVIGATORS';
import ONYXKEYS from '@src/ONYXKEYS';
Expand Down Expand Up @@ -198,16 +199,23 @@ function navigate(route: Route, options?: LinkToOptions) {

// Start a Sentry span for report navigation
if (route.startsWith('r/') || route.startsWith('search/r/')) {
const reportIDMatch = route.match(/^(?:search\/)?r\/(\w+)/);
if (reportIDMatch?.at(1)) {
const reportID = reportIDMatch.at(1);
const spanName = route.startsWith('r/') ? '/r/*' : '/search/r/*';
startSpan(`${CONST.TELEMETRY.SPAN_OPEN_REPORT}_${reportID}`, {
name: spanName,
op: CONST.TELEMETRY.SPAN_OPEN_REPORT,
attributes: {
reportID,
},
const routePath = Str.cutAfter(route, '?');
const reportIDMatch = routePath.match(/^(?:search\/)?r\/(\d+)(?:\/\d+)?$/);
const reportID = reportIDMatch?.at(1);
if (reportID) {
const spanId = `${CONST.TELEMETRY.SPAN_OPEN_REPORT}_${reportID}`;
let span = getSpan(spanId);
if (!span) {
const spanName = route.startsWith('r/') ? '/r/*' : '/search/r/*';
span = startSpan(spanId, {
name: spanName,
op: CONST.TELEMETRY.SPAN_OPEN_REPORT,
});
}
span.setAttributes({
[CONST.TELEMETRY.ATTRIBUTE_REPORT_ID]: reportID,
[CONST.TELEMETRY.ATTRIBUTE_ROUTE_FROM]: getActiveRouteWithoutParams(),
[CONST.TELEMETRY.ATTRIBUTE_ROUTE_TO]: Str.cutAfter(routePath, '?'),
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@
};

let allPersonalDetails: OnyxTypes.PersonalDetailsList = {};
Onyx.connect({

Check warning on line 712 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => {
allPersonalDetails = value ?? {};
Expand Down Expand Up @@ -801,7 +801,7 @@
};

let allTransactions: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
Onyx.connect({

Check warning on line 804 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.TRANSACTION,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -815,7 +815,7 @@
});

let allTransactionDrafts: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
Onyx.connect({

Check warning on line 818 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -824,7 +824,7 @@
});

let allTransactionViolations: NonNullable<OnyxCollection<OnyxTypes.TransactionViolations>> = {};
Onyx.connect({

Check warning on line 827 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -838,7 +838,7 @@
});

let allNextSteps: NonNullable<OnyxCollection<OnyxTypes.ReportNextStepDeprecated>> = {};
Onyx.connect({

Check warning on line 841 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.NEXT_STEP,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -847,7 +847,7 @@
});

const allPolicies: OnyxCollection<OnyxTypes.Policy> = {};
Onyx.connect({

Check warning on line 850 in src/libs/actions/IOU.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY,
callback: (val, key) => {
if (!key) {
Expand Down Expand Up @@ -1151,7 +1151,7 @@
[CONST.TELEMETRY.ATTRIBUTE_IOU_TYPE]: iouType,
[CONST.TELEMETRY.ATTRIBUTE_IOU_REQUEST_TYPE]: requestType ?? 'unknown',
[CONST.TELEMETRY.ATTRIBUTE_REPORT_ID]: reportID,
[CONST.TELEMETRY.ATTRIBUTE_SOURCE_ROUTE]: sourceRoute || 'unknown',
[CONST.TELEMETRY.ATTRIBUTE_ROUTE_FROM]: sourceRoute || 'unknown',
},
});
clearMoneyRequest(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, skipConfirmation, draftTransactions);
Expand Down
19 changes: 17 additions & 2 deletions src/libs/telemetry/activeSpans.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type {StartSpanOptions} from '@sentry/core';
import * as Sentry from '@sentry/react-native';
import CONST from '@src/CONST';

const activeSpans = new Map<string, ReturnType<typeof Sentry.startInactiveSpan>>();

function startSpan(spanId: string, options: StartSpanOptions) {
// End any existing span for this name
endSpan(spanId);
cancelSpan(spanId);

const span = Sentry.startInactiveSpan(options);

Expand All @@ -22,8 +23,22 @@ function endSpan(spanId: string) {
if (!span) {
return;
}
span.setStatus({code: 1});
span.end();
activeSpans.delete(spanId);
}

export {startSpan, endSpan};
function cancelSpan(spanId: string) {
const span = activeSpans.get(spanId);
span?.setAttribute(CONST.TELEMETRY.ATTRIBUTE_CANCELED, true);
// In Sentry there are only OK or ERROR status codes.
// We treat canceled spans as OK so we have ability to properly track spans that are not finished at all (their status would be different)
span?.setStatus({code: 1});
endSpan(spanId);
}

function getSpan(spanId: string) {
return activeSpans.get(spanId);
}

export {startSpan, endSpan, getSpan, cancelSpan};
4 changes: 4 additions & 0 deletions src/pages/home/ReportScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ import {
isTaskReport,
isValidReportIDFromPath,
} from '@libs/ReportUtils';
import {cancelSpan} from '@libs/telemetry/activeSpans';
import {isNumeric} from '@libs/ValidationUtils';
import type {ReportsSplitNavigatorParamList, SearchReportParamList} from '@navigation/types';
import {setShouldShowComposeInput} from '@userActions/Composer';
Expand Down Expand Up @@ -602,6 +603,9 @@ function ReportScreen({route, navigation}: ReportScreenProps) {

return () => {
skipOpenReportListener.remove();

// We need to cancel telemetry span when user leaves the screen before full report data is loaded
cancelSpan(`${CONST.TELEMETRY.SPAN_OPEN_REPORT}_${reportID}`);
};
}, [reportID]);

Expand Down
Loading