From 665470407ebf7d038a819f502ff680dd6101f836 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Wed, 28 Aug 2024 10:51:17 +0100 Subject: [PATCH] perf: add trace for UI startup (#26636) Support use of `trace` utility function in non-asynchronous contexts. Remove `getMetaMetricsEnabled` check. Generate default ID if omitted when starting and ending traces. --- app/scripts/lib/createTracingMiddleware.ts | 10 +- app/scripts/lib/ppom/ppom-middleware.ts | 28 +-- app/scripts/lib/transaction/util.ts | 6 +- app/scripts/ui.js | 37 +++- shared/lib/trace.test.ts | 152 +++++++++------- shared/lib/trace.ts | 171 +++++++++++------- ui/index.js | 93 ++++++---- .../confirm-transaction.component.js | 6 +- .../developer-options-tab/sentry-test.tsx | 8 +- 9 files changed, 322 insertions(+), 189 deletions(-) diff --git a/app/scripts/lib/createTracingMiddleware.ts b/app/scripts/lib/createTracingMiddleware.ts index a886b5c75860..99e0a73795b1 100644 --- a/app/scripts/lib/createTracingMiddleware.ts +++ b/app/scripts/lib/createTracingMiddleware.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { MESSAGE_TYPE } from '../../../shared/constants/app'; -import { trace } from '../../../shared/lib/trace'; +import { trace, TraceName } from '../../../shared/lib/trace'; export default function createTracingMiddleware() { return async function tracingMiddleware( @@ -14,12 +14,16 @@ export default function createTracingMiddleware() { if (method === MESSAGE_TYPE.ETH_SEND_TRANSACTION) { req.traceContext = await trace({ - name: 'Transaction', + name: TraceName.Transaction, id, tags: { source: 'dapp' }, }); - await trace({ name: 'Middleware', id, parentContext: req.traceContext }); + await trace({ + name: TraceName.Middleware, + id, + parentContext: req.traceContext, + }); } next(); diff --git a/app/scripts/lib/ppom/ppom-middleware.ts b/app/scripts/lib/ppom/ppom-middleware.ts index 9c32c7c9e3ba..c8f82265af4e 100644 --- a/app/scripts/lib/ppom/ppom-middleware.ts +++ b/app/scripts/lib/ppom/ppom-middleware.ts @@ -15,7 +15,7 @@ import { LOADING_SECURITY_ALERT_RESPONSE, SECURITY_PROVIDER_SUPPORTED_CHAIN_IDS, } from '../../../../shared/constants/security-provider'; -import { trace, TraceContext } from '../../../../shared/lib/trace'; +import { trace, TraceContext, TraceName } from '../../../../shared/lib/trace'; import { generateSecurityAlertId, handlePPOMError, @@ -92,19 +92,21 @@ export function createPPOMMiddleware< const securityAlertId = generateSecurityAlertId(); - trace({ name: 'PPOM Validation', parentContext: req.traceContext }, () => - validateRequestWithPPOM({ - ppomController, - request: req, - securityAlertId, - chainId, - }).then((securityAlertResponse) => { - updateSecurityAlertResponse( - req.method, + trace( + { name: TraceName.PPOMValidation, parentContext: req.traceContext }, + () => + validateRequestWithPPOM({ + ppomController, + request: req, securityAlertId, - securityAlertResponse, - ); - }), + chainId, + }).then((securityAlertResponse) => { + updateSecurityAlertResponse( + req.method, + securityAlertId, + securityAlertResponse, + ); + }), ); const loadingSecurityAlertResponse: SecurityAlertResponse = { diff --git a/app/scripts/lib/transaction/util.ts b/app/scripts/lib/transaction/util.ts index 0b1dd5db7747..af5d63fa200c 100644 --- a/app/scripts/lib/transaction/util.ts +++ b/app/scripts/lib/transaction/util.ts @@ -24,7 +24,7 @@ import { SECURITY_PROVIDER_EXCLUDED_TRANSACTION_TYPES, SECURITY_PROVIDER_SUPPORTED_CHAIN_IDS, } from '../../../../shared/constants/security-provider'; -import { endTrace } from '../../../../shared/lib/trace'; +import { endTrace, TraceName } from '../../../../shared/lib/trace'; export type AddTransactionOptions = NonNullable< Parameters[1] @@ -76,7 +76,7 @@ export async function addDappTransaction( securityAlertResponse, }; - endTrace({ name: 'Middleware', id: actionId }); + endTrace({ name: TraceName.Middleware, id: actionId }); const { waitForHash } = await addTransactionOrUserOperation({ ...request, @@ -88,7 +88,7 @@ export async function addDappTransaction( const hash = (await waitForHash()) as string; - endTrace({ name: 'Transaction', id: actionId }); + endTrace({ name: TraceName.Transaction, id: actionId }); return hash; } diff --git a/app/scripts/ui.js b/app/scripts/ui.js index eb88cbed7ec5..4b5deae61a6c 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -24,6 +24,7 @@ import { isManifestV3 } from '../../shared/modules/mv3.utils'; import { checkForLastErrorAndLog } from '../../shared/modules/browser-runtime.utils'; import { SUPPORT_LINK } from '../../shared/lib/ui-utils'; import { getErrorHtml } from '../../shared/lib/error-utils'; +import { endTrace, trace, TraceName } from '../../shared/lib/trace'; import ExtensionPlatform from './platforms/extension'; import { setupMultiplex } from './lib/stream-utils'; import { getEnvironmentType, getPlatform } from './lib/util'; @@ -43,6 +44,24 @@ let extensionPort; start().catch(log.error); async function start() { + const startTime = performance.now(); + + const traceContext = trace({ + name: TraceName.UIStartup, + startTime: performance.timeOrigin, + }); + + trace({ + name: TraceName.LoadScripts, + startTime: performance.timeOrigin, + parentContext: traceContext, + }); + + endTrace({ + name: 'Load Scripts', + timestamp: performance.timeOrigin + startTime, + }); + // create platform global global.platform = new ExtensionPlatform(); @@ -74,6 +93,7 @@ async function start() { // in later version we might try to improve it by reviving same streams. updateUiStreams(); } else { + endTrace({ name: TraceName.BackgroundConnect }); initializeUiWithTab(activeTab); } await loadPhishingWarningPage(); @@ -189,18 +209,30 @@ async function start() { extensionPort.onMessage.addListener(messageListener); extensionPort.onDisconnect.addListener(resetExtensionStreamAndListeners); + + trace({ + name: TraceName.BackgroundConnect, + parentContext: traceContext, + }); } else { const messageListener = async (message) => { if (message?.data?.method === 'startUISync') { + endTrace({ name: TraceName.BackgroundConnect }); initializeUiWithTab(activeTab); extensionPort.onMessage.removeListener(messageListener); } }; + extensionPort.onMessage.addListener(messageListener); + + trace({ + name: TraceName.BackgroundConnect, + parentContext: traceContext, + }); } function initializeUiWithTab(tab) { - initializeUi(tab, connectionStream, (err, store) => { + initializeUi(tab, connectionStream, traceContext, (err, store) => { if (err) { // if there's an error, store will be = metamaskState displayCriticalError('troubleStarting', err, store); @@ -276,7 +308,7 @@ async function queryCurrentActiveTab(windowType) { return { id, title, origin, protocol, url }; } -function initializeUi(activeTab, connectionStream, cb) { +function initializeUi(activeTab, connectionStream, traceContext, cb) { connectToAccountManager(connectionStream, (err, backgroundConnection) => { if (err) { cb(err, null); @@ -288,6 +320,7 @@ function initializeUi(activeTab, connectionStream, cb) { activeTab, container, backgroundConnection, + traceContext, }, cb, ); diff --git a/shared/lib/trace.test.ts b/shared/lib/trace.test.ts index a46fac0d02a0..fc3294924698 100644 --- a/shared/lib/trace.test.ts +++ b/shared/lib/trace.test.ts @@ -4,7 +4,7 @@ import { startSpanManual, withIsolationScope, } from '@sentry/browser'; -import { endTrace, trace } from './trace'; +import { endTrace, trace, TraceName } from './trace'; jest.mock('@sentry/browser', () => ({ withIsolationScope: jest.fn(), @@ -12,7 +12,7 @@ jest.mock('@sentry/browser', () => ({ startSpanManual: jest.fn(), })); -const NAME_MOCK = 'testName'; +const NAME_MOCK = TraceName.Transaction; const ID_MOCK = 'testId'; const PARENT_CONTEXT_MOCK = {} as Span; @@ -28,12 +28,6 @@ const DATA_MOCK = { data3: 123, }; -function mockGetMetaMetricsEnabled(enabled: boolean) { - global.sentry = { - getMetaMetricsEnabled: () => Promise.resolve(enabled), - }; -} - describe('Trace', () => { const startSpanMock = jest.mocked(startSpan); const startSpanManualMock = jest.mocked(startSpanManual); @@ -52,53 +46,30 @@ describe('Trace', () => { }); describe('trace', () => { - // @ts-expect-error This function is missing from the Mocha type definitions - it.each([ - ['enabled', true], - ['disabled', false], - ])( - 'executes callback if Sentry is %s', - async (_: string, sentryEnabled: boolean) => { - let callbackExecuted = false; - - mockGetMetaMetricsEnabled(sentryEnabled); - - await trace({ name: NAME_MOCK }, async () => { - callbackExecuted = true; - }); - - expect(callbackExecuted).toBe(true); - }, - ); + it('executes callback', () => { + let callbackExecuted = false; - // @ts-expect-error This function is missing from the Mocha type definitions - it.each([ - ['enabled', true], - ['disabled', false], - ])( - 'returns value from callback if Sentry is %s', - async (_: string, sentryEnabled: boolean) => { - mockGetMetaMetricsEnabled(sentryEnabled); - - const result = await trace({ name: NAME_MOCK }, async () => { - return true; - }); - - expect(result).toBe(true); - }, - ); + trace({ name: NAME_MOCK }, () => { + callbackExecuted = true; + }); - it('invokes Sentry if callback provided and metrics enabled', async () => { - mockGetMetaMetricsEnabled(true); + expect(callbackExecuted).toBe(true); + }); + + it('returns value from callback', () => { + const result = trace({ name: NAME_MOCK }, () => true); + expect(result).toBe(true); + }); - await trace( + it('invokes Sentry if callback provided', () => { + trace( { name: NAME_MOCK, tags: TAGS_MOCK, data: DATA_MOCK, parentContext: PARENT_CONTEXT_MOCK, }, - async () => Promise.resolve(), + () => true, ); expect(withIsolationScopeMock).toHaveBeenCalledTimes(1); @@ -109,6 +80,7 @@ describe('Trace', () => { name: NAME_MOCK, parentSpan: PARENT_CONTEXT_MOCK, attributes: DATA_MOCK, + op: 'custom', }, expect.any(Function), ); @@ -117,10 +89,8 @@ describe('Trace', () => { expect(setTagsMock).toHaveBeenCalledWith(TAGS_MOCK); }); - it('invokes Sentry if no callback provided and metrics enabled', async () => { - mockGetMetaMetricsEnabled(true); - - await trace({ + it('invokes Sentry if no callback provided', () => { + trace({ id: ID_MOCK, name: NAME_MOCK, tags: TAGS_MOCK, @@ -136,6 +106,7 @@ describe('Trace', () => { name: NAME_MOCK, parentSpan: PARENT_CONTEXT_MOCK, attributes: DATA_MOCK, + op: 'custom', }, expect.any(Function), ); @@ -144,24 +115,37 @@ describe('Trace', () => { expect(setTagsMock).toHaveBeenCalledWith(TAGS_MOCK); }); - it('does not invoke Sentry if no callback provided and no ID', async () => { - mockGetMetaMetricsEnabled(true); - - await trace({ + it('invokes Sentry if no callback provided with custom start time', () => { + trace({ + id: ID_MOCK, name: NAME_MOCK, tags: TAGS_MOCK, data: DATA_MOCK, parentContext: PARENT_CONTEXT_MOCK, + startTime: 123, }); - expect(withIsolationScopeMock).toHaveBeenCalledTimes(0); - expect(startSpanManualMock).toHaveBeenCalledTimes(0); - expect(setTagsMock).toHaveBeenCalledTimes(0); + expect(withIsolationScopeMock).toHaveBeenCalledTimes(1); + + expect(startSpanManualMock).toHaveBeenCalledTimes(1); + expect(startSpanManualMock).toHaveBeenCalledWith( + { + name: NAME_MOCK, + parentSpan: PARENT_CONTEXT_MOCK, + attributes: DATA_MOCK, + op: 'custom', + startTime: 123, + }, + expect.any(Function), + ); + + expect(setTagsMock).toHaveBeenCalledTimes(1); + expect(setTagsMock).toHaveBeenCalledWith(TAGS_MOCK); }); }); describe('endTrace', () => { - it('ends Sentry span matching name and ID', async () => { + it('ends Sentry span matching name and specified ID', () => { const spanEndMock = jest.fn(); const spanMock = { end: spanEndMock } as unknown as Span; @@ -171,7 +155,7 @@ describe('Trace', () => { }), ); - await trace({ + trace({ name: NAME_MOCK, id: ID_MOCK, tags: TAGS_MOCK, @@ -184,7 +168,53 @@ describe('Trace', () => { expect(spanEndMock).toHaveBeenCalledTimes(1); }); - it('does not end Sentry span if name and ID does not match', async () => { + it('ends Sentry span matching name and default ID', () => { + const spanEndMock = jest.fn(); + const spanMock = { end: spanEndMock } as unknown as Span; + + startSpanManualMock.mockImplementationOnce((_, fn) => + fn(spanMock, () => { + // Intentionally empty + }), + ); + + trace({ + name: NAME_MOCK, + tags: TAGS_MOCK, + data: DATA_MOCK, + parentContext: PARENT_CONTEXT_MOCK, + }); + + endTrace({ name: NAME_MOCK }); + + expect(spanEndMock).toHaveBeenCalledTimes(1); + }); + + it('ends Sentry span with custom timestamp', () => { + const spanEndMock = jest.fn(); + const spanMock = { end: spanEndMock } as unknown as Span; + + startSpanManualMock.mockImplementationOnce((_, fn) => + fn(spanMock, () => { + // Intentionally empty + }), + ); + + trace({ + name: NAME_MOCK, + id: ID_MOCK, + tags: TAGS_MOCK, + data: DATA_MOCK, + parentContext: PARENT_CONTEXT_MOCK, + }); + + endTrace({ name: NAME_MOCK, id: ID_MOCK, timestamp: 123 }); + + expect(spanEndMock).toHaveBeenCalledTimes(1); + expect(spanEndMock).toHaveBeenCalledWith(123); + }); + + it('does not end Sentry span if name and ID does not match', () => { const spanEndMock = jest.fn(); const spanMock = { end: spanEndMock } as unknown as Span; @@ -194,7 +224,7 @@ describe('Trace', () => { }), ); - await trace({ + trace({ name: NAME_MOCK, id: ID_MOCK, tags: TAGS_MOCK, diff --git a/shared/lib/trace.ts b/shared/lib/trace.ts index d80282f95a04..b9f59a2f2353 100644 --- a/shared/lib/trace.ts +++ b/shared/lib/trace.ts @@ -3,8 +3,28 @@ import { Primitive, StartSpanOptions } from '@sentry/types'; import { createModuleLogger } from '@metamask/utils'; import { log as sentryLogger } from '../../app/scripts/lib/setupSentry'; +export enum TraceName { + BackgroundConnect = 'Background Connect', + DeveloperTest = 'Developer Test', + FirstRender = 'First Render', + GetState = 'Get State', + InitialActions = 'Initial Actions', + LoadScripts = 'Load Scripts', + Middleware = 'Middleware', + NestedTest1 = 'Nested Test 1', + NestedTest2 = 'Nested Test 2', + NotificationDisplay = 'Notification Display', + PPOMValidation = 'PPOM Validation', + SetupStore = 'Setup Store', + Transaction = 'Transaction', + UIStartup = 'UI Startup', +} + const log = createModuleLogger(sentryLogger, 'trace'); +const ID_DEFAULT = 'default'; +const OP_DEFAULT = 'custom'; + const tracesByKey: Map = new Map(); type PendingTrace = { @@ -15,45 +35,41 @@ type PendingTrace = { export type TraceContext = unknown; -export type TraceCallback = (context?: TraceContext) => Promise; +export type TraceCallback = (context?: TraceContext) => T; export type TraceRequest = { data?: Record; id?: string; - name: string; + name: TraceName; parentContext?: TraceContext; + startTime?: number; tags?: Record; }; export type EndTraceRequest = { - id: string; - name: string; + id?: string; + name: TraceName; timestamp?: number; }; -export async function trace( - request: TraceRequest, - fn: TraceCallback, -): Promise; +export function trace(request: TraceRequest, fn: TraceCallback): T; -export async function trace(request: TraceRequest): Promise; +export function trace(request: TraceRequest): TraceContext; -export async function trace( +export function trace( request: TraceRequest, fn?: TraceCallback, -): Promise { - const isSentryEnabled = ((await globalThis.sentry?.getMetaMetricsEnabled()) ?? - false) as boolean; - +): T | TraceContext { if (!fn) { - return await startTrace(request, isSentryEnabled); + return startTrace(request); } - return await traceCallback(request, fn, isSentryEnabled); + return traceCallback(request, fn); } export function endTrace(request: EndTraceRequest) { - const { id, name, timestamp } = request; + const { name, timestamp } = request; + const id = getTraceId(request); const key = getTraceKey(request); const pendingTrace = tracesByKey.get(key); @@ -73,54 +89,41 @@ export function endTrace(request: EndTraceRequest) { log('Finished trace', name, id, duration, { request: pendingRequest }); } -async function traceCallback( - request: TraceRequest, - fn: TraceCallback, - isSentryEnabled: boolean, -): Promise { +function traceCallback(request: TraceRequest, fn: TraceCallback): T { const { name } = request; - const callback = async (span: Sentry.Span | null) => { + const callback = (span: Sentry.Span | null) => { log('Starting trace', name, request); const start = Date.now(); - let error; - - try { - return await fn(span); - } catch (currentError) { - error = currentError; - throw currentError; - } finally { - const end = Date.now(); - const duration = end - start; - - log('Finished trace', name, duration, { error, request }); - } + let error: unknown; + + return tryCatchMaybePromise( + () => fn(span), + (currentError) => { + error = currentError; + throw currentError; + }, + () => { + const end = Date.now(); + const duration = end - start; + + log('Finished trace', name, duration, { error, request }); + }, + ) as T; }; - if (!isSentryEnabled) { - return await callback(null); - } - - return await startSpan(request, (spanOptions) => + return startSpan(request, (spanOptions) => Sentry.startSpan(spanOptions, callback), ); } -async function startTrace( - request: TraceRequest, - isSentryEnabled: boolean, -): Promise { - const { id, name } = request; - const startTime = getPerformanceTimestamp(); - - if (!id) { - log('No trace ID provided', name, request); - return undefined; - } +function startTrace(request: TraceRequest): TraceContext { + const { name, startTime: requestStartTime } = request; + const startTime = requestStartTime ?? getPerformanceTimestamp(); + const id = getTraceId(request); - const callback = async (span: Sentry.Span | null) => { + const callback = (span: Sentry.Span | null) => { const end = (timestamp?: number) => { span?.end(timestamp); }; @@ -134,35 +137,73 @@ async function startTrace( return span; }; - if (!isSentryEnabled) { - return await callback(null); - } - - return await startSpan(request, (spanOptions) => + return startSpan(request, (spanOptions) => Sentry.startSpanManual(spanOptions, callback), ); } -async function startSpan( +function startSpan( request: TraceRequest, - callback: (spanOptions: StartSpanOptions) => Promise, + callback: (spanOptions: StartSpanOptions) => T, ) { - const { data: attributes, name, parentContext, tags } = request; + const { data: attributes, name, parentContext, startTime, tags } = request; const parentSpan = (parentContext ?? null) as Sentry.Span | null; - const spanOptions = { name, parentSpan, attributes }; - return await Sentry.withIsolationScope(async (scope) => { + const spanOptions: StartSpanOptions = { + attributes, + name, + op: OP_DEFAULT, + parentSpan, + startTime, + }; + + return Sentry.withIsolationScope((scope) => { scope.setTags(tags as Record); - return await callback(spanOptions); + return callback(spanOptions); }); } +function getTraceId(request: TraceRequest) { + return request.id ?? ID_DEFAULT; +} + function getTraceKey(request: TraceRequest) { - const { id, name } = request; + const { name } = request; + const id = getTraceId(request); + return [name, id].join(':'); } function getPerformanceTimestamp(): number { return performance.timeOrigin + performance.now(); } + +function tryCatchMaybePromise( + tryFn: () => T, + catchFn: (error: unknown) => void, + finallyFn: () => void, +): T | undefined { + let isPromise = false; + + try { + const result = tryFn() as T; + + if (result instanceof Promise) { + isPromise = true; + return result.catch(catchFn).finally(finallyFn) as T; + } + + return result; + } catch (error) { + if (!isPromise) { + catchFn(error); + } + } finally { + if (!isPromise) { + finallyFn(); + } + } + + return undefined; +} diff --git a/ui/index.js b/ui/index.js index 907fcea66b89..51d23a38c497 100644 --- a/ui/index.js +++ b/ui/index.js @@ -13,6 +13,7 @@ import { ENVIRONMENT_TYPE_POPUP } from '../shared/constants/app'; import { COPY_OPTIONS } from '../shared/constants/copy'; import switchDirection from '../shared/lib/switch-direction'; import { setupLocale } from '../shared/lib/error-utils'; +import { endTrace, trace, TraceName } from '../shared/lib/trace'; import * as actions from './store/actions'; import configureStore from './store/store'; import { @@ -58,10 +59,17 @@ export const updateBackgroundConnection = (backgroundConnection) => { }; export default function launchMetamaskUi(opts, cb) { - const { backgroundConnection } = opts; + const { backgroundConnection, traceContext } = opts; + + trace({ + name: TraceName.GetState, + parentContext: traceContext, + }); // check if we are unlocked first backgroundConnection.getState(function (err, metamaskState) { + endTrace({ name: TraceName.GetState }); + if (err) { cb( err, @@ -72,6 +80,7 @@ export default function launchMetamaskUi(opts, cb) { ); return; } + startApp(metamaskState, backgroundConnection, opts).then((store) => { setupStateHooks(store); cb(null, store); @@ -177,10 +186,12 @@ export async function setupInitialStore( } async function startApp(metamaskState, backgroundConnection, opts) { - const store = await setupInitialStore( - metamaskState, - backgroundConnection, - opts.activeTab, + const { traceContext } = opts; + + const store = await trace( + { name: TraceName.SetupStore, parentContext: traceContext }, + () => + setupInitialStore(metamaskState, backgroundConnection, opts.activeTab), ); // global metamask api - used by tooling @@ -196,40 +207,48 @@ async function startApp(metamaskState, backgroundConnection, opts) { }, }; - // This block autoswitches chains based on the last chain used - // for a given dapp, when there are no pending confimrations - // This allows the user to be connected on one chain - // for one dapp, and automatically change for another - const state = store.getState(); - const networkIdToSwitchTo = getNetworkToAutomaticallySwitchTo(state); - if (networkIdToSwitchTo) { - await store.dispatch( - actions.automaticallySwitchNetwork( - networkIdToSwitchTo, - getOriginOfCurrentTab(state), - ), - ); - } else if (getSwitchedNetworkDetails(state)) { - // It's possible that old details could exist if the user - // opened the toast but then didn't close it - // Clear out any existing switchedNetworkDetails - // if the user didn't just change the dapp network - await store.dispatch(actions.clearSwitchedNetworkDetails()); - } + await trace( + { name: TraceName.InitialActions, parentContext: traceContext }, + async () => { + // This block autoswitches chains based on the last chain used + // for a given dapp, when there are no pending confimrations + // This allows the user to be connected on one chain + // for one dapp, and automatically change for another + const state = store.getState(); + const networkIdToSwitchTo = getNetworkToAutomaticallySwitchTo(state); + if (networkIdToSwitchTo) { + await store.dispatch( + actions.automaticallySwitchNetwork( + networkIdToSwitchTo, + getOriginOfCurrentTab(state), + ), + ); + } else if (getSwitchedNetworkDetails(state)) { + // It's possible that old details could exist if the user + // opened the toast but then didn't close it + // Clear out any existing switchedNetworkDetails + // if the user didn't just change the dapp network + await store.dispatch(actions.clearSwitchedNetworkDetails()); + } + + // Register this window as the current popup + // and set in background state + if ( + getUseRequestQueue(state) && + getEnvironmentType() === ENVIRONMENT_TYPE_POPUP + ) { + const thisPopupId = Date.now(); + global.metamask.id = thisPopupId; + await store.dispatch(actions.setCurrentExtensionPopupId(thisPopupId)); + } + }, + ); - // Register this window as the current popup - // and set in background state - if ( - getUseRequestQueue(state) && - getEnvironmentType() === ENVIRONMENT_TYPE_POPUP - ) { - const thisPopupId = Date.now(); - global.metamask.id = thisPopupId; - await store.dispatch(actions.setCurrentExtensionPopupId(thisPopupId)); - } + trace({ name: TraceName.FirstRender, parentContext: traceContext }, () => + render(, opts.container), + ); - // start app - render(, opts.container); + endTrace({ name: TraceName.UIStartup }); return store; } diff --git a/ui/pages/confirmations/confirm-transaction/confirm-transaction.component.js b/ui/pages/confirmations/confirm-transaction/confirm-transaction.component.js index 2bc83ad5992d..cb740dd9a99a 100644 --- a/ui/pages/confirmations/confirm-transaction/confirm-transaction.component.js +++ b/ui/pages/confirmations/confirm-transaction/confirm-transaction.component.js @@ -49,6 +49,7 @@ import Confirm from '../confirm/confirm'; import useCurrentConfirmation from '../hooks/useCurrentConfirmation'; import { getEnvironmentType } from '../../../../app/scripts/lib/util'; import { useAsyncResult } from '../../../hooks/useAsyncResult'; +import { TraceName } from '../../../../shared/lib/trace'; import ConfirmTokenTransactionSwitch from './confirm-token-transaction-switch'; const ConfirmTransaction = () => { @@ -102,7 +103,10 @@ const ConfirmTransaction = () => { return undefined; } - return await endBackgroundTrace({ name: 'Notification Display', id }); + return await endBackgroundTrace({ + name: TraceName.NotificationDisplay, + id, + }); }, [id, isNotification]); const transactionId = id; diff --git a/ui/pages/settings/developer-options-tab/sentry-test.tsx b/ui/pages/settings/developer-options-tab/sentry-test.tsx index ab9a7702fcb5..f8e2d67f96d2 100644 --- a/ui/pages/settings/developer-options-tab/sentry-test.tsx +++ b/ui/pages/settings/developer-options-tab/sentry-test.tsx @@ -15,7 +15,7 @@ import { IconColor, JustifyContent, } from '../../../helpers/constants/design-system'; -import { trace } from '../../../../shared/lib/trace'; +import { trace, TraceName } from '../../../../shared/lib/trace'; import { useI18nContext } from '../../../hooks/useI18nContext'; export function SentryTest() { @@ -78,14 +78,14 @@ function GenerateTrace() { const handleClick = useCallback(async () => { await trace( { - name: 'Developer Test', + name: TraceName.DeveloperTest, data: { 'test.data.number': 123 }, tags: { 'test.tag.number': 123 }, }, async (context) => { await trace( { - name: 'Nested Test 1', + name: TraceName.NestedTest1, data: { 'test.data.boolean': true }, tags: { 'test.tag.boolean': true }, parentContext: context, @@ -95,7 +95,7 @@ function GenerateTrace() { await trace( { - name: 'Nested Test 2', + name: TraceName.NestedTest2, data: { 'test.data.string': 'test' }, tags: { 'test.tag.string': 'test' }, parentContext: context,