diff --git a/app/scripts/background.js b/app/scripts/background.js index 28e1b301eb1f..856bb057e187 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -58,7 +58,7 @@ import Migrator from './lib/migrator'; import ExtensionPlatform from './platforms/extension'; import LocalStore from './lib/local-store'; import ReadOnlyNetworkStore from './lib/network-store'; -import { SENTRY_BACKGROUND_STATE } from './lib/setupSentry'; +import { SENTRY_BACKGROUND_STATE } from './constants/sentry-state'; import createStreamSink from './lib/createStreamSink'; import NotificationManager, { diff --git a/app/scripts/constants/sentry-state.ts b/app/scripts/constants/sentry-state.ts new file mode 100644 index 000000000000..1a5a87442359 --- /dev/null +++ b/app/scripts/constants/sentry-state.ts @@ -0,0 +1,419 @@ +import { AllProperties } from '../../../shared/modules/object.utils'; + +export const MMI_SENTRY_BACKGROUND_STATE = { + MMIController: { + opts: true, + }, + CustodyController: { + store: true, + }, + MmiConfigurationController: { + store: true, + configurationClient: true, + }, +}; + +// This describes the subset of background controller state attached to errors +// sent to Sentry These properties have some potential to be useful for +// debugging, and they do not contain any identifiable information. +export const SENTRY_BACKGROUND_STATE = { + AccountsController: { + internalAccounts: { + accounts: false, + selectedAccount: false, + }, + }, + AccountTracker: { + accounts: false, + accountsByChainId: false, + currentBlockGasLimit: true, + currentBlockGasLimitByChainId: true, + }, + AddressBookController: { + addressBook: false, + }, + AlertController: { + alertEnabledness: true, + unconnectedAccountAlertShownOrigins: false, + web3ShimUsageOrigins: false, + }, + AnnouncementController: { + announcements: false, + }, + AuthenticationController: { + isSignedIn: false, + }, + NetworkOrderController: { + orderedNetworkList: [], + }, + AccountOrderController: { + pinnedAccountList: [], + hiddenAccountList: [], + }, + AppMetadataController: { + currentAppVersion: true, + currentMigrationVersion: true, + previousAppVersion: true, + previousMigrationVersion: true, + }, + ApprovalController: { + approvalFlows: false, + pendingApprovals: false, + pendingApprovalCount: false, + }, + AppStateController: { + browserEnvironment: true, + connectedStatusPopoverHasBeenShown: true, + currentPopupId: false, + onboardingDate: false, + currentExtensionPopupId: false, + defaultHomeActiveTabName: true, + fullScreenGasPollTokens: true, + hadAdvancedGasFeesSetPriorToMigration92_3: true, + nftsDetectionNoticeDismissed: true, + nftsDropdownState: true, + notificationGasPollTokens: true, + outdatedBrowserWarningLastShown: true, + popupGasPollTokens: true, + qrHardware: true, + recoveryPhraseReminderHasBeenShown: true, + recoveryPhraseReminderLastShown: true, + showBetaHeader: true, + showPermissionsTour: true, + showNetworkBanner: true, + showAccountBanner: true, + switchedNetworkDetails: false, + switchedNetworkNeverShowMessage: false, + showTestnetMessageInDropdown: true, + surveyLinkLastClickedOrClosed: true, + snapsInstallPrivacyWarningShown: true, + termsOfUseLastAgreed: true, + timeoutMinutes: true, + trezorModel: true, + usedNetworks: true, + }, + MultichainBalancesController: { + balances: false, + }, + BridgeController: { + bridgeState: { + bridgeFeatureFlags: { + extensionSupport: false, + }, + }, + }, + CronjobController: { + jobs: false, + }, + CurrencyController: { + currentCurrency: true, + currencyRates: true, + }, + DecryptMessageController: { + unapprovedDecryptMsgs: false, + unapprovedDecryptMsgCount: true, + }, + EncryptionPublicKeyController: { + unapprovedEncryptionPublicKeyMsgs: false, + unapprovedEncryptionPublicKeyMsgCount: true, + }, + EnsController: { + ensResolutionsByAddress: false, + ensEntries: false, + }, + GasFeeController: { + estimatedGasFeeTimeBounds: true, + gasEstimateType: true, + gasFeeEstimates: true, + gasFeeEstimatesByChainId: true, + nonRPCGasFeeApisDisabled: false, + }, + KeyringController: { + isUnlocked: true, + keyrings: false, + }, + LoggingController: { + logs: false, + }, + NotificationServicesController: { + subscriptionAccountsSeen: false, + isMetamaskNotificationsFeatureSeen: false, + isNotificationServicesEnabled: false, + isFeatureAnnouncementsEnabled: false, + metamaskNotificationsList: false, + metamaskNotificationsReadList: false, + isCheckingAccountsPresence: false, + isFetchingMetamaskNotifications: false, + isUpdatingMetamaskNotifications: false, + isUpdatingMetamaskNotificationsAccount: false, + }, + MetaMetricsController: { + eventsBeforeMetricsOptIn: false, + fragments: false, + metaMetricsId: true, + participateInMetaMetrics: true, + previousUserTraits: false, + segmentApiCalls: false, + traits: false, + dataCollectionForMarketing: false, + }, + NameController: { + names: false, + nameSources: false, + useExternalNameSources: false, + }, + NetworkController: { + networkConfigurations: false, + networksMetadata: true, + providerConfig: { + chainId: true, + id: true, + nickname: true, + rpcPrefs: false, + rpcUrl: false, + ticker: true, + type: true, + }, + selectedNetworkClientId: false, + }, + NftController: { + allNftContracts: false, + allNfts: false, + ignoredNfts: false, + }, + NotificationController: { + notifications: false, + }, + OnboardingController: { + completedOnboarding: true, + firstTimeFlowType: true, + onboardingTabs: false, + seedPhraseBackedUp: true, + }, + PPOMController: { + securityAlertsEnabled: false, + storageMetadata: [], + versionInfo: [], + }, + PermissionController: { + subjects: false, + }, + PermissionLogController: { + permissionActivityLog: false, + permissionHistory: false, + }, + PhishingController: {}, + PreferencesController: { + advancedGasFee: true, + currentLocale: true, + dismissSeedBackUpReminder: true, + featureFlags: true, + forgottenPassword: true, + identities: false, + incomingTransactionsPreferences: true, + isIpfsGatewayEnabled: false, + ipfsGateway: false, + knownMethodData: false, + ledgerTransportType: true, + lostIdentities: false, + openSeaEnabled: true, + preferences: { + autoLockTimeLimit: true, + hideZeroBalanceTokens: true, + redesignedConfirmationsEnabled: true, + redesignedTransactionsEnabled: false, + isRedesignedConfirmationsDeveloperEnabled: false, + showExtensionInFullSizeView: true, + showFiatInTestnets: true, + showTestNetworks: true, + smartTransactionsOptInStatus: true, + useNativeCurrencyAsPrimaryCurrency: true, + petnamesEnabled: true, + showConfirmationAdvancedDetails: true, + }, + useExternalServices: false, + selectedAddress: false, + snapRegistryList: false, + theme: true, + signatureSecurityAlertResponses: false, + use4ByteResolution: true, + useAddressBarEnsResolution: true, + useBlockie: true, + useCurrencyRateCheck: true, + useMultiAccountBalanceChecker: true, + useNftDetection: true, + useNonceField: true, + usePhishDetect: true, + useTokenDetection: true, + useRequestQueue: true, + useTransactionSimulations: true, + enableMV3TimestampSave: true, + }, + NotificationServicesPushController: { + fcmToken: false, + }, + MultichainRatesController: { + fiatCurrency: true, + rates: true, + cryptocurrencies: true, + }, + QueuedRequestController: { + queuedRequestCount: true, + }, + SelectedNetworkController: { domains: false }, + SignatureController: { + unapprovedPersonalMsgCount: true, + unapprovedPersonalMsgs: false, + unapprovedTypedMessages: false, + unapprovedTypedMessagesCount: true, + }, + SmartTransactionsController: { + smartTransactionsState: { + fees: { + approvalTxFees: true, + tradeTxFees: true, + }, + liveness: true, + smartTransactions: false, + userOptIn: true, + userOptInV2: true, + }, + }, + SnapController: { + unencryptedSnapStates: false, + snapStates: false, + snaps: false, + }, + SnapInterfaceController: { + interfaces: false, + }, + SnapInsightsController: { + insights: false, + }, + SnapsRegistry: { + database: false, + lastUpdated: false, + databaseUnavailable: false, + }, + SubjectMetadataController: { + subjectMetadata: false, + }, + SwapsController: { + swapsState: { + approveTxId: false, + customApproveTxData: false, + customGasPrice: true, + customMaxFeePerGas: true, + customMaxGas: true, + customMaxPriorityFeePerGas: true, + errorKey: true, + fetchParams: true, + quotes: false, + quotesLastFetched: true, + quotesPollingLimitEnabled: true, + routeState: true, + saveFetchedQuotes: true, + selectedAggId: true, + swapsFeatureFlags: true, + swapsFeatureIsLive: true, + swapsQuotePrefetchingRefreshTime: true, + swapsQuoteRefreshTime: true, + swapsStxBatchStatusRefreshTime: true, + swapsStxStatusDeadline: true, + swapsStxGetTransactionsRefreshTime: true, + swapsStxMaxFeeMultiplier: true, + swapsUserFeeLevel: true, + tokens: false, + topAggId: false, + tradeTxId: false, + }, + }, + TokenDetectionController: { + [AllProperties]: false, + }, + TokenListController: { + preventPollingOnNetworkRestart: true, + tokenList: false, + tokensChainsCache: { + [AllProperties]: false, + }, + }, + TokenRatesController: { + marketData: false, + }, + TokensController: { + allDetectedTokens: { + [AllProperties]: false, + }, + allIgnoredTokens: { + [AllProperties]: false, + }, + allTokens: { + [AllProperties]: false, + }, + detectedTokens: false, + ignoredTokens: false, + tokens: false, + }, + TransactionController: { + transactions: false, + lastFetchedBlockNumbers: false, + methodData: false, + }, + TxController: { + transactions: false, + }, + UserOperationController: { + userOperations: false, + }, + UserStorageController: { + isProfileSyncingEnabled: true, + isProfileSyncingUpdateLoading: false, + }, + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) + ...MMI_SENTRY_BACKGROUND_STATE, + ///: END:ONLY_INCLUDE_IF +}; + +const flattenedBackgroundStateMask = Object.values( + SENTRY_BACKGROUND_STATE, +).reduce((partialBackgroundState, controllerState: object) => { + return { + ...partialBackgroundState, + ...controllerState, + }; +}, {}); + +// This describes the subset of Redux state attached to errors sent to Sentry +// These properties have some potential to be useful for debugging, and they do +// not contain any identifiable information. +export const SENTRY_UI_STATE = { + gas: true, + history: true, + metamask: { + ...flattenedBackgroundStateMask, + // This property comes from the background but isn't in controller state + isInitialized: true, + // These properties are in the `metamask` slice but not in the background state + customNonceValue: true, + isAccountMenuOpen: true, + isNetworkMenuOpen: true, + nextNonce: true, + pendingTokens: false, + welcomeScreenSeen: true, + confirmationExchangeRates: true, + useSafeChainsListValidation: true, + watchEthereumAccountEnabled: false, + bitcoinSupportEnabled: false, + bitcoinTestnetSupportEnabled: false, + ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) + addSnapAccountEnabled: false, + snapsAddSnapAccountModalDismissed: false, + ///: END:ONLY_INCLUDE_IF + switchedNetworkDetails: false, + switchedNetworkNeverShowMessage: false, + newPrivacyPolicyToastClickedOrClosed: false, + newPrivacyPolicyToastShownDate: false, + }, + unconnectedAccount: true, +}; diff --git a/app/scripts/lib/setup-initial-state-hooks.js b/app/scripts/lib/setup-initial-state-hooks.js index d41b5b562029..d0b689c9cb30 100644 --- a/app/scripts/lib/setup-initial-state-hooks.js +++ b/app/scripts/lib/setup-initial-state-hooks.js @@ -1,8 +1,8 @@ import { maskObject } from '../../../shared/modules/object.utils'; import ExtensionPlatform from '../platforms/extension'; +import { SENTRY_BACKGROUND_STATE } from '../constants/sentry-state'; import LocalStore from './local-store'; import ReadOnlyNetworkStore from './network-store'; -import { SENTRY_BACKGROUND_STATE } from './setupSentry'; const platform = new ExtensionPlatform(); diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index aa6e51aa598f..b7a15dfbef9f 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -1,12 +1,13 @@ import * as Sentry from '@sentry/browser'; import { createModuleLogger, createProjectLogger } from '@metamask/utils'; import { logger } from '@sentry/utils'; -import { AllProperties } from '../../../shared/modules/object.utils'; +import browser from 'webextension-polyfill'; import { isManifestV3 } from '../../../shared/modules/mv3.utils'; import extractEthjsErrorMessage from './extractEthjsErrorMessage'; import { filterEvents } from './sentry-filter-events'; const projectLogger = createProjectLogger('sentry'); +let installType = 'unknown'; export const log = createModuleLogger( projectLogger, @@ -34,424 +35,6 @@ export const ERROR_URL_ALLOWLIST = { SEGMENT: 'segment.io', }; -export const MMI_SENTRY_BACKGROUND_STATE = { - MMIController: { - opts: true, - }, - CustodyController: { - store: true, - }, - MmiConfigurationController: { - store: true, - configurationClient: true, - }, -}; - -// This describes the subset of background controller state attached to errors -// sent to Sentry These properties have some potential to be useful for -// debugging, and they do not contain any identifiable information. -export const SENTRY_BACKGROUND_STATE = { - AccountsController: { - internalAccounts: { - accounts: false, - selectedAccount: false, - }, - }, - AccountTracker: { - accounts: false, - accountsByChainId: false, - currentBlockGasLimit: true, - currentBlockGasLimitByChainId: true, - }, - AddressBookController: { - addressBook: false, - }, - AlertController: { - alertEnabledness: true, - unconnectedAccountAlertShownOrigins: false, - web3ShimUsageOrigins: false, - }, - AnnouncementController: { - announcements: false, - }, - AuthenticationController: { - isSignedIn: false, - }, - NetworkOrderController: { - orderedNetworkList: [], - }, - AccountOrderController: { - pinnedAccountList: [], - hiddenAccountList: [], - }, - AppMetadataController: { - currentAppVersion: true, - currentMigrationVersion: true, - previousAppVersion: true, - previousMigrationVersion: true, - }, - ApprovalController: { - approvalFlows: false, - pendingApprovals: false, - pendingApprovalCount: false, - }, - AppStateController: { - browserEnvironment: true, - connectedStatusPopoverHasBeenShown: true, - currentPopupId: false, - onboardingDate: false, - currentExtensionPopupId: false, - defaultHomeActiveTabName: true, - fullScreenGasPollTokens: true, - hadAdvancedGasFeesSetPriorToMigration92_3: true, - nftsDetectionNoticeDismissed: true, - nftsDropdownState: true, - notificationGasPollTokens: true, - outdatedBrowserWarningLastShown: true, - popupGasPollTokens: true, - qrHardware: true, - recoveryPhraseReminderHasBeenShown: true, - recoveryPhraseReminderLastShown: true, - showBetaHeader: true, - showPermissionsTour: true, - showNetworkBanner: true, - showAccountBanner: true, - switchedNetworkDetails: false, - switchedNetworkNeverShowMessage: false, - showTestnetMessageInDropdown: true, - surveyLinkLastClickedOrClosed: true, - snapsInstallPrivacyWarningShown: true, - termsOfUseLastAgreed: true, - timeoutMinutes: true, - trezorModel: true, - usedNetworks: true, - }, - MultichainBalancesController: { - balances: false, - }, - BridgeController: { - bridgeState: { - bridgeFeatureFlags: { - extensionSupport: false, - }, - }, - }, - CronjobController: { - jobs: false, - }, - CurrencyController: { - currentCurrency: true, - currencyRates: true, - }, - DecryptMessageController: { - unapprovedDecryptMsgs: false, - unapprovedDecryptMsgCount: true, - }, - EncryptionPublicKeyController: { - unapprovedEncryptionPublicKeyMsgs: false, - unapprovedEncryptionPublicKeyMsgCount: true, - }, - EnsController: { - ensResolutionsByAddress: false, - ensEntries: false, - }, - GasFeeController: { - estimatedGasFeeTimeBounds: true, - gasEstimateType: true, - gasFeeEstimates: true, - gasFeeEstimatesByChainId: true, - nonRPCGasFeeApisDisabled: false, - }, - KeyringController: { - isUnlocked: true, - keyrings: false, - }, - LoggingController: { - logs: false, - }, - NotificationServicesController: { - subscriptionAccountsSeen: false, - isMetamaskNotificationsFeatureSeen: false, - isNotificationServicesEnabled: false, - isFeatureAnnouncementsEnabled: false, - metamaskNotificationsList: false, - metamaskNotificationsReadList: false, - isCheckingAccountsPresence: false, - isFetchingMetamaskNotifications: false, - isUpdatingMetamaskNotifications: false, - isUpdatingMetamaskNotificationsAccount: false, - }, - MetaMetricsController: { - eventsBeforeMetricsOptIn: false, - fragments: false, - metaMetricsId: true, - participateInMetaMetrics: true, - previousUserTraits: false, - segmentApiCalls: false, - traits: false, - dataCollectionForMarketing: false, - }, - NameController: { - names: false, - nameSources: false, - useExternalNameSources: false, - }, - NetworkController: { - networkConfigurations: false, - networksMetadata: true, - providerConfig: { - chainId: true, - id: true, - nickname: true, - rpcPrefs: false, - rpcUrl: false, - ticker: true, - type: true, - }, - selectedNetworkClientId: false, - }, - NftController: { - allNftContracts: false, - allNfts: false, - ignoredNfts: false, - }, - NotificationController: { - notifications: false, - }, - OnboardingController: { - completedOnboarding: true, - firstTimeFlowType: true, - onboardingTabs: false, - seedPhraseBackedUp: true, - }, - PPOMController: { - securityAlertsEnabled: false, - storageMetadata: [], - versionInfo: [], - }, - PermissionController: { - subjects: false, - }, - PermissionLogController: { - permissionActivityLog: false, - permissionHistory: false, - }, - PhishingController: {}, - PreferencesController: { - advancedGasFee: true, - currentLocale: true, - dismissSeedBackUpReminder: true, - featureFlags: true, - forgottenPassword: true, - identities: false, - incomingTransactionsPreferences: true, - isIpfsGatewayEnabled: false, - ipfsGateway: false, - knownMethodData: false, - ledgerTransportType: true, - lostIdentities: false, - openSeaEnabled: true, - preferences: { - autoLockTimeLimit: true, - hideZeroBalanceTokens: true, - redesignedConfirmationsEnabled: true, - redesignedTransactionsEnabled: false, - isRedesignedConfirmationsDeveloperEnabled: false, - showExtensionInFullSizeView: true, - showFiatInTestnets: true, - showTestNetworks: true, - smartTransactionsOptInStatus: true, - useNativeCurrencyAsPrimaryCurrency: true, - petnamesEnabled: true, - showConfirmationAdvancedDetails: true, - }, - useExternalServices: false, - selectedAddress: false, - snapRegistryList: false, - theme: true, - signatureSecurityAlertResponses: false, - use4ByteResolution: true, - useAddressBarEnsResolution: true, - useBlockie: true, - useCurrencyRateCheck: true, - useMultiAccountBalanceChecker: true, - useNftDetection: true, - useNonceField: true, - usePhishDetect: true, - useTokenDetection: true, - useRequestQueue: true, - useTransactionSimulations: true, - enableMV3TimestampSave: true, - }, - NotificationServicesPushController: { - fcmToken: false, - }, - MultichainRatesController: { - fiatCurrency: true, - rates: true, - cryptocurrencies: true, - }, - QueuedRequestController: { - queuedRequestCount: true, - }, - SelectedNetworkController: { domains: false }, - SignatureController: { - unapprovedPersonalMsgCount: true, - unapprovedPersonalMsgs: false, - unapprovedTypedMessages: false, - unapprovedTypedMessagesCount: true, - }, - SmartTransactionsController: { - smartTransactionsState: { - fees: { - approvalTxFees: true, - tradeTxFees: true, - }, - liveness: true, - smartTransactions: false, - userOptIn: true, - userOptInV2: true, - }, - }, - SnapController: { - unencryptedSnapStates: false, - snapStates: false, - snaps: false, - }, - SnapInterfaceController: { - interfaces: false, - }, - SnapInsightsController: { - insights: false, - }, - SnapsRegistry: { - database: false, - lastUpdated: false, - databaseUnavailable: false, - }, - SubjectMetadataController: { - subjectMetadata: false, - }, - SwapsController: { - swapsState: { - approveTxId: false, - customApproveTxData: false, - customGasPrice: true, - customMaxFeePerGas: true, - customMaxGas: true, - customMaxPriorityFeePerGas: true, - errorKey: true, - fetchParams: true, - quotes: false, - quotesLastFetched: true, - quotesPollingLimitEnabled: true, - routeState: true, - saveFetchedQuotes: true, - selectedAggId: true, - swapsFeatureFlags: true, - swapsFeatureIsLive: true, - swapsQuotePrefetchingRefreshTime: true, - swapsQuoteRefreshTime: true, - swapsStxBatchStatusRefreshTime: true, - swapsStxStatusDeadline: true, - swapsStxGetTransactionsRefreshTime: true, - swapsStxMaxFeeMultiplier: true, - swapsUserFeeLevel: true, - tokens: false, - topAggId: false, - tradeTxId: false, - }, - }, - TokenDetectionController: { - [AllProperties]: false, - }, - TokenListController: { - preventPollingOnNetworkRestart: true, - tokenList: false, - tokensChainsCache: { - [AllProperties]: false, - }, - }, - TokenRatesController: { - marketData: false, - }, - TokensController: { - allDetectedTokens: { - [AllProperties]: false, - }, - allIgnoredTokens: { - [AllProperties]: false, - }, - allTokens: { - [AllProperties]: false, - }, - detectedTokens: false, - ignoredTokens: false, - tokens: false, - }, - TransactionController: { - transactions: false, - lastFetchedBlockNumbers: false, - methodData: false, - }, - TxController: { - transactions: false, - }, - UserOperationController: { - userOperations: false, - }, - UserStorageController: { - isProfileSyncingEnabled: true, - isProfileSyncingUpdateLoading: false, - }, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - ...MMI_SENTRY_BACKGROUND_STATE, - ///: END:ONLY_INCLUDE_IF -}; - -const flattenedBackgroundStateMask = Object.values( - SENTRY_BACKGROUND_STATE, -).reduce((partialBackgroundState, controllerState) => { - return { - ...partialBackgroundState, - ...controllerState, - }; -}, {}); - -// This describes the subset of Redux state attached to errors sent to Sentry -// These properties have some potential to be useful for debugging, and they do -// not contain any identifiable information. -export const SENTRY_UI_STATE = { - gas: true, - history: true, - metamask: { - ...flattenedBackgroundStateMask, - // This property comes from the background but isn't in controller state - isInitialized: true, - // These properties are in the `metamask` slice but not in the background state - customNonceValue: true, - isAccountMenuOpen: true, - isNetworkMenuOpen: true, - nextNonce: true, - pendingTokens: false, - welcomeScreenSeen: true, - confirmationExchangeRates: true, - useSafeChainsListValidation: true, - watchEthereumAccountEnabled: false, - bitcoinSupportEnabled: false, - bitcoinTestnetSupportEnabled: false, - ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) - addSnapAccountEnabled: false, - snapsAddSnapAccountModalDismissed: false, - ///: END:ONLY_INCLUDE_IF - switchedNetworkDetails: false, - switchedNetworkNeverShowMessage: false, - newPrivacyPolicyToastClickedOrClosed: false, - newPrivacyPolicyToastShownDate: false, - }, - unconnectedAccount: true, -}; - export default function setupSentry() { if (!RELEASE) { throw new Error('Missing release'); @@ -464,6 +47,18 @@ export default function setupSentry() { log('Initializing'); + // Normally this would be awaited, but getSelf should be available by the time the report is finalized. + // If it's not, we still get the extensionId, but the installType will default to "unknown" + browser.management + .getSelf() + .then((extensionInfo) => { + if (extensionInfo.installType) { + installType = extensionInfo.installType; + } + }) + .catch((error) => { + log('Error getting extension installType', error); + }); integrateLogging(); setSentryClient(); @@ -754,6 +349,10 @@ export function rewriteReport(report) { } report.extra.appState = appState; + if (browser.runtime && browser.runtime.id) { + report.extra.extensionId = browser.runtime.id; + } + report.extra.installType = installType; } catch (err) { log('Error rewriting report', err); } diff --git a/test/e2e/tests/metrics/errors.spec.js b/test/e2e/tests/metrics/errors.spec.js index 8fcfb94ed2a7..2cd18ec8eb7f 100644 --- a/test/e2e/tests/metrics/errors.spec.js +++ b/test/e2e/tests/metrics/errors.spec.js @@ -5,7 +5,9 @@ const { get, has, set, unset, cloneDeep } = require('lodash'); const { Browser } = require('selenium-webdriver'); const { format } = require('prettier'); const { isObject } = require('@metamask/utils'); -const { SENTRY_UI_STATE } = require('../../../../app/scripts/lib/setupSentry'); +const { + SENTRY_UI_STATE, +} = require('../../../../app/scripts/constants/sentry-state'); const FixtureBuilder = require('../../fixture-builder'); const { convertToHexValue, @@ -308,7 +310,6 @@ describe('Sentry errors', function () { async ({ driver, mockedEndpoint }) => { // we don't wait for the controllers to be loaded await driver.navigate(PAGES.HOME, { waitForControllers: false }); - // Wait for Sentry request await driver.wait(async () => { const isPending = await mockedEndpoint.isPending(); @@ -679,6 +680,7 @@ describe('Sentry errors', function () { const mockTextBody = (await mockedRequest.body.getText()).split('\n'); const mockJsonBody = JSON.parse(mockTextBody[2]); const appState = mockJsonBody?.extra?.appState; + const { extensionId, installType } = mockJsonBody.extra; assert.deepStrictEqual(Object.keys(appState), [ 'browser', 'version', @@ -694,6 +696,11 @@ describe('Sentry errors', function () { appState?.version.length > 0, 'Invalid version state', ); + assert.ok( + typeof extensionId === 'string' && extensionId.length > 0, + `${extensionId} is not a valid extension ID`, + ); + assert.equal(installType, 'development'); await matchesSnapshot({ data: transformBackgroundState(appState.state), snapshot: 'errors-after-init-opt-in-background-state', @@ -770,6 +777,7 @@ describe('Sentry errors', function () { const mockTextBody = (await mockedRequest.body.getText()).split('\n'); const mockJsonBody = JSON.parse(mockTextBody[2]); const appState = mockJsonBody?.extra?.appState; + const { extensionId, installType } = mockJsonBody.extra; assert.deepStrictEqual(Object.keys(appState), [ 'browser', 'version', @@ -785,6 +793,11 @@ describe('Sentry errors', function () { appState?.version.length > 0, 'Invalid version state', ); + assert.ok( + typeof extensionId === 'string' && extensionId.length > 0, + `${extensionId} is not a valid extension ID`, + ); + assert.equal(installType, 'development'); await matchesSnapshot({ data: transformUiState(appState.state), snapshot: 'errors-after-init-opt-in-ui-state', diff --git a/ui/index.js b/ui/index.js index 56362b31de68..7daf0ad28595 100644 --- a/ui/index.js +++ b/ui/index.js @@ -8,7 +8,7 @@ import browser from 'webextension-polyfill'; import { getEnvironmentType } from '../app/scripts/lib/util'; import { AlertTypes } from '../shared/constants/alerts'; import { maskObject } from '../shared/modules/object.utils'; -import { SENTRY_UI_STATE } from '../app/scripts/lib/setupSentry'; +import { SENTRY_UI_STATE } from '../app/scripts/constants/sentry-state'; import { ENVIRONMENT_TYPE_POPUP } from '../shared/constants/app'; import { COPY_OPTIONS } from '../shared/constants/copy'; import switchDirection from '../shared/lib/switch-direction';