Skip to content

Commit c831c6f

Browse files
authored
chore: add sentry tracing to ai market insights (#26583)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Adds Sentry performance tracing to Market Insights to measure load times for two key user flows: MarketInsightsEntryCardLoad — Measures the time from when a token details page starts rendering to when the Market Insights entry card mounts. Uses the asset's CAIP-19 ID as the trace id so rapid token switching doesn't cause trace collisions. MarketInsightsViewLoad — Measures the time from when the user taps the entry card to when the full Market Insights view renders with report data. Includes an unmount cleanup to end the trace if the user navigates away before the report loads. Both traces use a new TraceOperation.MarketInsightsLoad (market_insights.load) operation for easy filtering in Sentry. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk instrumentation-only change, but it touches token details rendering and navigation flows and could create noisy traces if the start/end pairing is missed in edge cases. > > **Overview** > Adds two new Sentry traces for Market Insights load performance: `MarketInsightsEntryCardLoad` (token details render -> entry card mount) and `MarketInsightsViewLoad` (entry card tap -> report displayed). > > Starts traces from `AssetOverviewContent` using a new `TraceOperation.MarketInsightsLoad`, passes `caip19Id` into `MarketInsightsEntryCard` to end the matching trace on mount, and ends the view-load trace in `MarketInsightsView` once report data is available. Updates the entry card prop types and tests to include the required `caip19Id`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8f6ebb8. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 095fd84 commit c831c6f

6 files changed

Lines changed: 51 additions & 1 deletion

File tree

app/components/UI/MarketInsights/Views/MarketInsightsView/MarketInsightsView.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import type {
5050
MarketInsightsTrend,
5151
} from '@metamask/ai-controllers';
5252
import { selectMarketInsightsEnabled } from '../../../../../selectors/featureFlagController/marketInsights';
53+
import { endTrace, TraceName } from '../../../../../util/trace';
5354
import { Skeleton } from '../../../../../component-library/components/Skeleton';
5455
import { MetaMetricsEvents } from '../../../../hooks/useMetrics';
5556
import {
@@ -476,6 +477,8 @@ const MarketInsightsView: React.FC = () => {
476477
return;
477478
}
478479

480+
endTrace({ name: TraceName.MarketInsightsViewLoad });
481+
479482
const event = createEventBuilder(MetaMetricsEvents.MARKET_INSIGHTS_VIEWED)
480483
.addProperties({
481484
caip19: caip19Id,

app/components/UI/MarketInsights/components/MarketInsightsEntryCard/MarketInsightsEntryCard.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import { Image } from 'react-native';
33
import { fireEvent } from '@testing-library/react-native';
4+
import type { CaipAssetType } from '@metamask/utils';
45
import renderWithProvider from '../../../../../util/test/renderWithProvider';
56
import MarketInsightsEntryCard from './MarketInsightsEntryCard';
67

@@ -20,6 +21,7 @@ describe('MarketInsightsEntryCard', () => {
2021
report={report as never}
2122
timeAgo="3m ago"
2223
onPress={mockPress}
24+
caip19Id={'eip155:1/erc20:0xtest' as CaipAssetType}
2325
testID="market-insights-entry-card"
2426
/>,
2527
);
@@ -61,6 +63,7 @@ describe('MarketInsightsEntryCard', () => {
6163
report={report as never}
6264
timeAgo="1m ago"
6365
onPress={jest.fn()}
66+
caip19Id={'eip155:1/erc20:0xtest' as CaipAssetType}
6467
testID="market-insights-entry-card"
6568
/>,
6669
);

app/components/UI/MarketInsights/components/MarketInsightsEntryCard/MarketInsightsEntryCard.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
import type { MarketInsightsSource } from '@metamask/ai-controllers';
1818
import { strings } from '../../../../../../locales/i18n';
1919
import type { MarketInsightsEntryCardProps } from './MarketInsightsEntryCard.types';
20+
import { endTrace, TraceName } from '../../../../../util/trace';
2021
import { getFaviconUrl } from '../../utils/marketInsightsFormatting';
2122

2223
const MAX_VISIBLE_SOURCE_LOGOS = 3;
@@ -104,10 +105,20 @@ const MarketInsightsEntryCard: React.FC<MarketInsightsEntryCardProps> = ({
104105
report,
105106
timeAgo,
106107
onPress,
108+
caip19Id,
107109
testID,
108110
}) => {
109111
const tw = useTailwind();
110112

113+
useEffect(() => {
114+
// End the trace started by the parent (AssetOverviewContent) to measure
115+
// how long it takes for the entry card to mount after navigation.
116+
endTrace({
117+
name: TraceName.MarketInsightsEntryCardLoad,
118+
id: caip19Id,
119+
});
120+
}, [caip19Id]);
121+
111122
return (
112123
<Pressable
113124
onPress={onPress}

app/components/UI/MarketInsights/components/MarketInsightsEntryCard/MarketInsightsEntryCard.types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { MarketInsightsReport } from '@metamask/ai-controllers';
2+
import type { CaipAssetType } from '@metamask/utils';
23

34
export interface MarketInsightsEntryCardProps {
45
/** The market insights report data */
@@ -7,6 +8,8 @@ export interface MarketInsightsEntryCardProps {
78
timeAgo: string;
89
/** Callback when the card is pressed to open the full view */
910
onPress: () => void;
11+
/** The CAIP-19 asset ID, used to match the trace started by the parent */
12+
caip19Id: CaipAssetType;
1013
/** Optional test ID */
1114
testID?: string;
1215
}

app/components/UI/TokenDetails/components/AssetOverviewContent.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import { IconName } from '../../../../component-library/components/Icons/Icon';
6868
import { useRWAToken } from '../../Bridge/hooks/useRWAToken';
6969
import { BridgeToken } from '../../Bridge/types';
7070
import { useAnalytics } from '../../../hooks/useAnalytics/useAnalytics';
71+
import { trace, TraceName, TraceOperation } from '../../../../util/trace';
7172

7273
const styleSheet = (params: { theme: Theme }) => {
7374
const { theme } = params;
@@ -309,6 +310,23 @@ const AssetOverviewContent: React.FC<AssetOverviewContentProps> = ({
309310
marketInsightsReport,
310311
]);
311312

313+
// Start the entry card trace synchronously during render so it is registered
314+
// in the trace map before any child useEffect (where endTrace fires) runs.
315+
// Using a ref guard ensures we only start one trace per unique asset.
316+
const entryCardTraceStartedRef = useRef<string | null>(null);
317+
if (
318+
isMarketInsightsEnabled &&
319+
marketInsightsCaip19Id &&
320+
entryCardTraceStartedRef.current !== marketInsightsCaip19Id
321+
) {
322+
entryCardTraceStartedRef.current = marketInsightsCaip19Id;
323+
trace({
324+
name: TraceName.MarketInsightsEntryCardLoad,
325+
op: TraceOperation.MarketInsightsLoad,
326+
id: marketInsightsCaip19Id,
327+
});
328+
}
329+
312330
const goToBrowserUrl = (url: string) => {
313331
const [screen, params] = createWebviewNavDetails({
314332
url,
@@ -318,6 +336,10 @@ const AssetOverviewContent: React.FC<AssetOverviewContentProps> = ({
318336

319337
const handleMarketInsightsPress = useCallback(() => {
320338
if (marketInsightsCaip19Id) {
339+
trace({
340+
name: TraceName.MarketInsightsViewLoad,
341+
op: TraceOperation.MarketInsightsLoad,
342+
});
321343
const event = createEventBuilder(MetaMetricsEvents.MARKET_INSIGHTS_OPENED)
322344
.addProperties({
323345
caip19: marketInsightsCaip19Id,
@@ -502,12 +524,15 @@ const AssetOverviewContent: React.FC<AssetOverviewContentProps> = ({
502524
)
503525
///: END:ONLY_INCLUDE_IF
504526
}
505-
{isMarketInsightsEnabled && marketInsightsReport ? (
527+
{isMarketInsightsEnabled &&
528+
marketInsightsReport &&
529+
marketInsightsCaip19Id ? (
506530
<View style={styles.marketInsightsWrapper}>
507531
<MarketInsightsEntryCard
508532
report={marketInsightsReport}
509533
timeAgo={marketInsightsTimeAgo}
510534
onPress={handleMarketInsightsPress}
535+
caip19Id={marketInsightsCaip19Id}
511536
testID="market-insights-entry-card"
512537
/>
513538
</View>

app/util/trace.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ export enum TraceName {
207207
MusdConversionNavigation = 'mUSD Conversion Navigation',
208208
MusdConversionQuote = 'mUSD Conversion Quote',
209209
MusdConversionConfirm = 'mUSD Conversion Confirm',
210+
// Market Insights
211+
MarketInsightsEntryCardLoad = 'Market Insights Entry Card Load',
212+
MarketInsightsViewLoad = 'Market Insights View Load',
210213
}
211214

212215
export enum TraceOperation {
@@ -255,6 +258,8 @@ export enum TraceOperation {
255258
// mUSD Conversion
256259
MusdConversionOperation = 'musd.conversion.operation',
257260
MusdConversionDataFetch = 'musd.conversion.data_fetch',
261+
// Market Insights
262+
MarketInsightsLoad = 'market_insights.load',
258263
}
259264

260265
const ID_DEFAULT = 'default';

0 commit comments

Comments
 (0)