Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
8ecf0b2
Revert "feat: codefence Account Watcher for flask (#27543)"
MajorLift Oct 23, 2024
9924b50
Add trace names for account list item and account overview tab
MajorLift Oct 24, 2024
a4c46b7
Add trace calls for `AccountListItem` span
MajorLift Oct 24, 2024
394d487
Add trace calls for `AccountOverviewTab` span
MajorLift Oct 24, 2024
39cc6f2
Abort `AccountListItem` span if account tab is switched
MajorLift Oct 24, 2024
656dfdb
Abort `AccountOverviewTab` span if account tab is switched before cur…
MajorLift Oct 25, 2024
9f90b84
Abort `AccountOverviewTab` span if new account is selected in account…
MajorLift Oct 25, 2024
04d0694
Abort `AccountListItem` span if new account is selected in account li…
MajorLift Oct 28, 2024
ccc6a34
Revert "Revert "feat: codefence Account Watcher for flask (#27543)""
MajorLift Oct 28, 2024
e9b9aef
Remove `AccountOverviewTab`, `AccountListItem` spans
MajorLift Oct 30, 2024
c53f8bb
Define custom spans `AccountOverview{AssetList,Nfts,Activity}Tab`
MajorLift Oct 30, 2024
b9fa09e
Place `endTrace` calls for new custom spans in corresponding `Account…
MajorLift Oct 30, 2024
b79a95e
Define utility functions `{start,end}Traces` for batch handling of tr…
MajorLift Oct 30, 2024
b5046fd
Define new redux selector `getDefaultHomeActiveTabName`
MajorLift Oct 30, 2024
694e73d
Trigger and terminate custom spans when clicking on account list item…
MajorLift Oct 30, 2024
c0f9811
`endTrace` calls for "Tokens" and "Nfts" tab conditionally trigger wh…
MajorLift Oct 30, 2024
21bbcf6
Trigger `AccountOverviewAssetListTab` span when detected token select…
MajorLift Oct 30, 2024
4fa73c1
Nfts tab span termination also requires `nftsStillFetchingIndication`…
MajorLift Nov 1, 2024
a5c2ae2
Define types, constants for account overview tabs and replace `fromTa…
MajorLift Nov 1, 2024
6bbef8e
Revert "Define utility functions `{start,end}Traces` for batch handli…
MajorLift Nov 1, 2024
26b2031
Merge branch 'develop' into jongsun/perf/trace/241009-account-watcher
MajorLift Nov 1, 2024
f49728b
Linter fixes
MajorLift Nov 1, 2024
0d914ec
Align types for `defaultHomeActiveTabName`
MajorLift Nov 1, 2024
9c33083
Fix import order
MajorLift Nov 1, 2024
cfcc492
Remove `AccountOverviewTabKeys` enum union type
MajorLift Nov 6, 2024
df17187
Move `detectNfts` dispatch call out of component library and into `ac…
MajorLift Nov 6, 2024
f3c989b
Add `endTrace` call for case where `NftsTab` displays the empty banner
MajorLift Nov 11, 2024
3790fc4
Merge branch 'develop' into jongsun/perf/trace/241009-account-watcher
MajorLift Nov 11, 2024
8c9638f
feat: Add support for adding tags in `endTrace` calls
MajorLift Nov 11, 2024
ed5dcab
Add jsdoc comment for `AccountList` span
MajorLift Nov 5, 2024
1329fdb
Add support for custom span operation names
MajorLift Nov 6, 2024
945a5b5
Add custom span operation `'custom.ui.component_load'`
MajorLift Nov 11, 2024
c73b201
Define utility functions `{start,end}Traces` for batch handling of tr…
MajorLift Oct 30, 2024
f55315e
Add `ui.event.abort` tags to `endTrace` calls
MajorLift Nov 11, 2024
e292805
Add missing `ui.event.abort` tag
MajorLift Nov 11, 2024
7662a32
Add `FMP` spans for tokens and NFTs tabs
MajorLift Nov 11, 2024
1c80ed2
Add trace calls for detected token selection popover
MajorLift Nov 11, 2024
c1e1012
Linter fixes
MajorLift Nov 11, 2024
fa73d06
Refactor tokens tab custom spans to measure FCP, FMP
MajorLift Nov 11, 2024
d10461c
Fix logic for triggering nft tabs spans `endTrace` calls
MajorLift Nov 6, 2024
1f25af3
Ensure traces don't terminate while `nftsLoading` is true
MajorLift Nov 6, 2024
12a68ee
Consolidate `useEffect` for `NftsTab` when empty nfts banner is displ…
MajorLift Nov 11, 2024
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
7 changes: 5 additions & 2 deletions app/scripts/controllers/app-state-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ORIGIN_METAMASK,
POLLING_TOKEN_ENVIRONMENT_TYPES,
} from '../../../shared/constants/app';
import { AccountOverviewTabKey } from '../../../shared/constants/app-state';
import { AppStateController } from './app-state-controller';
import type {
AllowedActions,
Expand Down Expand Up @@ -209,9 +210,11 @@ describe('AppStateController', () => {

describe('setDefaultHomeActiveTabName', () => {
it('sets the default home tab name', () => {
appStateController.setDefaultHomeActiveTabName('testTabName');
appStateController.setDefaultHomeActiveTabName(
AccountOverviewTabKey.Activity,
);
expect(appStateController.store.getState().defaultHomeActiveTabName).toBe(
'testTabName',
AccountOverviewTabKey.Activity,
);
});
});
Expand Down
7 changes: 5 additions & 2 deletions app/scripts/controllers/app-state-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
import { DEFAULT_AUTO_LOCK_TIME_LIMIT } from '../../../shared/constants/preferences';
import { LastInteractedConfirmationInfo } from '../../../shared/types/confirm';
import { SecurityAlertResponse } from '../lib/ppom/types';
import { AccountOverviewTabKey } from '../../../shared/constants/app-state';
import type {
Preferences,
PreferencesControllerGetStateAction,
Expand All @@ -35,7 +36,7 @@ import type {
export type AppStateControllerState = {
timeoutMinutes: number;
connectedStatusPopoverHasBeenShown: boolean;
defaultHomeActiveTabName: string | null;
defaultHomeActiveTabName: AccountOverviewTabKey | null;
browserEnvironment: Record<string, string>;
popupGasPollTokens: string[];
notificationGasPollTokens: string[];
Expand Down Expand Up @@ -326,7 +327,9 @@ export class AppStateController extends EventEmitter {
*
* @param defaultHomeActiveTabName - the tab name
*/
setDefaultHomeActiveTabName(defaultHomeActiveTabName: string | null): void {
setDefaultHomeActiveTabName(
defaultHomeActiveTabName: AccountOverviewTabKey | null,
): void {
this.store.updateState({
defaultHomeActiveTabName,
});
Expand Down
26 changes: 26 additions & 0 deletions shared/constants/app-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { TraceName } from '../lib/trace';
import { MetaMetricsEventName } from './metametrics';

export enum AccountOverviewTabKey {
Tokens = 'tokens',
Nfts = 'nfts',
Activity = 'activity',
}

export const ACCOUNT_OVERVIEW_TAB_KEY_TO_METAMETRICS_EVENT_NAME_MAP = {
[AccountOverviewTabKey.Tokens]: MetaMetricsEventName.TokenScreenOpened,
[AccountOverviewTabKey.Nfts]: MetaMetricsEventName.NftScreenOpened,
[AccountOverviewTabKey.Activity]: MetaMetricsEventName.ActivityScreenOpened,
} as const;

export const ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAMES_ARRAY_MAP = {
[AccountOverviewTabKey.Tokens]: [
TraceName.AccountOverviewAssetListTab,
TraceName.AccountOverviewAssetListTabFCP,
],
[AccountOverviewTabKey.Nfts]: [
TraceName.AccountOverviewNftsTab,
TraceName.AccountOverviewNftsTabFMP,
],
[AccountOverviewTabKey.Activity]: [TraceName.AccountOverviewActivityTab],
} as const;
67 changes: 66 additions & 1 deletion shared/lib/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,30 @@ import { log as sentryLogger } from '../../app/scripts/lib/setupSentry';
* The supported trace names.
*/
export enum TraceName {
/**
* `AccountList` component renders (FCP).
*/
AccountList = 'Account List',
/**
* `TokenList` component renders (FCP).
*/
AccountOverviewAssetListTabFCP = 'Account Overview - Asset List Tab - First Contentful Paint',
/**
* `TokenList` component loading message disappears (FMP).
*/
AccountOverviewAssetListTab = 'Account Overview - Asset List Tab',
/**
* `NftsTab` component loading spinner disappears or no-Nfts banner renders.
*/
AccountOverviewNftsTabFMP = 'Account Overview - Nfts Tab - First Meaningful Paint',
/**
* `NftsTab` component fully loads, including all resources.
*/
AccountOverviewNftsTab = 'Account Overview - Nfts Tab',
/**
* `TransactionList` component renders (FCP).
*/
AccountOverviewActivityTab = 'Account Overview - Activity Tab',
BackgroundConnect = 'Background Connect',
DeveloperTest = 'Developer Test',
FirstRender = 'First Render',
Expand All @@ -27,6 +50,10 @@ export enum TraceName {
UIStartup = 'UI Startup',
}

export enum TraceOperation {
ComponentLoad = 'custom.ui.component_load',
}

const log = createModuleLogger(sentryLogger, 'trace');

const ID_DEFAULT = 'default';
Expand Down Expand Up @@ -90,6 +117,11 @@ export type TraceRequest = {
* Custom tags to associate with the trace.
*/
tags?: Record<string, number | string | boolean>;

/**
* Custom operation name to associate with the trace.
*/
op?: TraceOperation | typeof OP_DEFAULT;
};

/**
Expand All @@ -111,6 +143,10 @@ export type EndTraceRequest = {
* Override the end time of the trace.
*/
timestamp?: number;
/**
* Custom tags to associate with the trace.
*/
tags?: Record<string, number | string | boolean>;
};

export function trace<T>(request: TraceRequest, fn: TraceCallback<T>): T;
Expand Down Expand Up @@ -155,6 +191,13 @@ export function endTrace(request: EndTraceRequest) {
return;
}

if ('tags' in request) {
pendingTrace.request.tags = Object.assign(
pendingTrace.request.tags ?? {},
request.tags,
);
}

pendingTrace.end(timestamp);

tracesByKey.delete(key);
Expand All @@ -165,6 +208,17 @@ export function endTrace(request: EndTraceRequest) {
logTrace(pendingRequest, startTime, endTime);
}

/**
* End multiple pending traces.
*
* @param requests - The data necessary to identify and end the pending traces.
*/
export function endTraces(...requests: EndTraceRequest[]) {
for (const request of requests) {
endTrace(request);
}
}

function traceCallback<T>(request: TraceRequest, fn: TraceCallback<T>): T {
const { name } = request;

Expand Down Expand Up @@ -224,6 +278,17 @@ function startTrace(request: TraceRequest): TraceContext {
);
}

/**
* Start multiple traces.
*
* @param requests - The data necessary to identify and start the pending traces.
*/
export function startTraces(...requests: EndTraceRequest[]) {
for (const request of requests) {
startTrace(request);
}
}

function startSpan<T>(
request: TraceRequest,
callback: (spanOptions: StartSpanOptions) => T,
Expand All @@ -234,7 +299,7 @@ function startSpan<T>(
const spanOptions: StartSpanOptions = {
attributes,
name,
op: OP_DEFAULT,
op: request.op ?? OP_DEFAULT,
parentSpan,
startTime,
};
Expand Down
14 changes: 14 additions & 0 deletions ui/components/app/assets/nfts/nfts-tab/nfts-tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
} from '../../../../../../shared/constants/metametrics';
import { getCurrentLocale } from '../../../../../ducks/locale/locale';
import Spinner from '../../../../ui/spinner';
import { endTrace, TraceName } from '../../../../../../shared/lib/trace';

export default function NftsTab() {
const useNftDetection = useSelector(getUseNftDetection);
Expand Down Expand Up @@ -84,6 +85,8 @@ export default function NftsTab() {
referrer: ORIGIN_METAMASK,
},
});
endTrace({ name: TraceName.AccountOverviewNftsTabFMP });
endTrace({ name: TraceName.AccountOverviewNftsTab });
}, [
nftsLoading,
showNftBanner,
Expand All @@ -93,6 +96,17 @@ export default function NftsTab() {
currentLocale,
]);

useEffect(() => {
if (nftsLoading) {
return;
}
if (nftsStillFetchingIndication) {
endTrace({ name: TraceName.AccountOverviewNftsTabFMP });
} else {
endTrace({ name: TraceName.AccountOverviewNftsTab });
}
}, [nftsLoading, nftsStillFetchingIndication]);

if (!hasAnyNfts && nftsStillFetchingIndication) {
return (
<Box className="nfts-tab__loading">
Expand Down
13 changes: 12 additions & 1 deletion ui/components/app/assets/token-list/token-list.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactNode, useMemo } from 'react';
import React, { ReactNode, useEffect, useMemo } from 'react';
import { shallowEqual, useSelector } from 'react-redux';
import TokenCell from '../token-cell';
import { useI18nContext } from '../../../../hooks/useI18nContext';
Expand All @@ -19,6 +19,7 @@ import {
import { useAccountTotalFiatBalance } from '../../../../hooks/useAccountTotalFiatBalance';
import { getConversionRate } from '../../../../ducks/metamask/metamask';
import { useNativeTokenBalance } from '../asset-list/native-token/use-native-token-balance';
import { endTrace, TraceName } from '../../../../../shared/lib/trace';

type TokenListProps = {
onTokenClick: (arg: string) => void;
Expand Down Expand Up @@ -66,6 +67,16 @@ export default function TokenList({
contractExchangeRates,
]);

useEffect(() => {
endTrace({ name: TraceName.AccountOverviewAssetListTabFCP });
}, []);

useEffect(() => {
if (!loading) {
endTrace({ name: TraceName.AccountOverviewAssetListTab });
}
}, [loading]);

return loading ? (
<Box
display={Display.Flex}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ import Popover from '../../../ui/popover';
import Box from '../../../ui/box';
import Button from '../../../ui/button';
import DetectedTokenDetails from '../detected-token-details/detected-token-details';
import {
trace,
endTrace,
TraceOperation,
} from '../../../../../shared/lib/trace';
import {
ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAMES_ARRAY_MAP,
AccountOverviewTabKey,
} from '../../../../../shared/constants/app-state';

const DetectedTokenSelectionPopover = ({
tokensListDetected,
Expand Down Expand Up @@ -64,7 +73,15 @@ const DetectedTokenSelectionPopover = ({
<Button
className="detected-token-selection-popover__import-button"
type="primary"
onClick={onImport}
onClick={() => {
for (const traceName of ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAMES_ARRAY_MAP[
AccountOverviewTabKey.Tokens
]) {
endTrace({ name: traceName, tags: { 'ui.event.abort': true } });
trace({ name: traceName, op: TraceOperation.ComponentLoad });
}
onImport();
}}
disabled={selectedTokens.length === 0}
>
{t('importWithCount', [`(${selectedTokens.length})`])}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {
useCallback,
Fragment,
useContext,
useEffect,
} from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
Expand Down Expand Up @@ -53,6 +54,7 @@ import { getMultichainAccountUrl } from '../../../helpers/utils/multichain/block
import { MetaMetricsContext } from '../../../contexts/metametrics';
import { useMultichainSelector } from '../../../hooks/useMultichainSelector';
import { getMultichainNetwork } from '../../../selectors/multichain';
import { endTrace, TraceName } from '../../../../shared/lib/trace';

const PAGE_INCREMENT = 10;

Expand Down Expand Up @@ -258,6 +260,11 @@ export default function TransactionList({
// Check if the current account is a bitcoin account
const isBitcoinAccount = useSelector(isSelectedInternalAccountBtc);
const trackEvent = useContext(MetaMetricsContext);

useEffect(() => {
endTrace({ name: TraceName.AccountOverviewActivityTab });
}, []);

const multichainNetwork = useMultichainSelector(
getMultichainNetwork,
selectedAccount,
Expand Down
21 changes: 20 additions & 1 deletion ui/components/multichain/account-list-menu/account-list-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import {
getOriginOfCurrentTab,
getSelectedInternalAccount,
getUpdatedAndSortedAccounts,
getDefaultHomeActiveTabName,
///: BEGIN:ONLY_INCLUDE_IF(solana)
getIsSolanaSupportEnabled,
///: END:ONLY_INCLUDE_IF
Expand Down Expand Up @@ -114,7 +115,16 @@ import {
AccountConnections,
MergedInternalAccount,
} from '../../../selectors/selectors.types';
import { endTrace, TraceName } from '../../../../shared/lib/trace';
import {
endTrace,
trace,
TraceName,
TraceOperation,
} from '../../../../shared/lib/trace';
import {
AccountOverviewTabKey,
ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAMES_ARRAY_MAP,
} from '../../../../shared/constants/app-state';
///: BEGIN:ONLY_INCLUDE_IF(solana)
import {
SOLANA_WALLET_NAME,
Expand Down Expand Up @@ -251,6 +261,9 @@ export const AccountListMenu = ({
),
[updatedAccountsList, allowedAccountTypes],
);
const defaultHomeActiveTabName: AccountOverviewTabKey = useSelector(
getDefaultHomeActiveTabName,
);
///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps)
const addSnapAccountEnabled = useSelector(getIsAddSnapAccountEnabled);
///: END:ONLY_INCLUDE_IF
Expand Down Expand Up @@ -340,6 +353,12 @@ export const AccountListMenu = ({
location: 'Main Menu',
},
});
for (const traceName of ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAMES_ARRAY_MAP[
defaultHomeActiveTabName
]) {
endTrace({ name: traceName, tags: { 'ui.event.abort': true } });
trace({ name: traceName, op: TraceOperation.ComponentLoad });
}
dispatch(setSelectedAccount(account.address));
};
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from './account-overview-btc';

const defaultProps: AccountOverviewBtcProps = {
defaultHomeActiveTabName: '',
defaultHomeActiveTabName: null,
onTabClick: jest.fn(),
setBasicFunctionalityModalOpen: jest.fn(),
onSupportLinkClick: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('AccountOverviewEth', () => {
});
it('shows all tabs', () => {
const { queryByTestId } = render({
defaultHomeActiveTabName: '',
defaultHomeActiveTabName: null,
onTabClick: jest.fn(),
setBasicFunctionalityModalOpen: jest.fn(),
onSupportLinkClick: jest.fn(),
Expand Down
Loading