1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-30 16:18:07 +01:00
metamask-extension/app/scripts/lib/setupSentry.js
Mark Stacey 345ed9f6f2
Add build type to Sentry environment (#12441)
The build type (i.e. the distribution) is now included in the Sentry
environment during setup, for all builds except the "main" build. This
will allow us to track Flask and beta errors separately from other
errors.

A constant was created for the build types. The equivalent constant in
our build scripts was updated to match it more closely, for
consistency. We can't use the same constant in both places because our
shared constants are in modules that use ES6 exports, and our build
script does not yet support ES6 exports.

The singular `BuildType` was used rather than `BuildTypes` to match our
naming conventions elsewhere for enums. We name them like classes or
types, rather than like a collection.

Relates to #11896
2021-10-25 14:27:30 -02:30

184 lines
5.2 KiB
JavaScript

import * as Sentry from '@sentry/browser';
import { Dedupe, ExtraErrorData } from '@sentry/integrations';
import { BuildType } from '../../../shared/constants/app';
import extractEthjsErrorMessage from './extractEthjsErrorMessage';
/* eslint-disable prefer-destructuring */
// Destructuring breaks the inlining of the environment variables
const METAMASK_DEBUG = process.env.METAMASK_DEBUG;
const METAMASK_ENVIRONMENT = process.env.METAMASK_ENVIRONMENT;
const SENTRY_DSN_DEV = process.env.SENTRY_DSN_DEV;
const METAMASK_BUILD_TYPE = process.env.METAMASK_BUILD_TYPE;
/* eslint-enable prefer-destructuring */
// 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_STATE = {
gas: true,
history: true,
metamask: {
alertEnabledness: true,
completedOnboarding: true,
connectedStatusPopoverHasBeenShown: true,
conversionDate: true,
conversionRate: true,
currentBlockGasLimit: true,
currentCurrency: true,
currentLocale: true,
customNonceValue: true,
defaultHomeActiveTabName: true,
featureFlags: true,
firstTimeFlowType: true,
forgottenPassword: true,
incomingTxLastFetchedBlockByChainId: true,
ipfsGateway: true,
isAccountMenuOpen: true,
isInitialized: true,
isUnlocked: true,
metaMetricsId: true,
nativeCurrency: true,
network: true,
nextNonce: true,
participateInMetaMetrics: true,
preferences: true,
provider: {
nickname: true,
ticker: true,
type: true,
},
seedPhraseBackedUp: true,
showRestorePrompt: true,
threeBoxDisabled: true,
threeBoxLastUpdated: true,
threeBoxSynced: true,
threeBoxSyncingAllowed: true,
unapprovedDecryptMsgCount: true,
unapprovedEncryptionPublicKeyMsgCount: true,
unapprovedMsgCount: true,
unapprovedPersonalMsgCount: true,
unapprovedTypedMessagesCount: true,
useBlockie: true,
useNonceField: true,
usePhishDetect: true,
welcomeScreenSeen: true,
},
unconnectedAccount: true,
};
export default function setupSentry({ release, getState }) {
let sentryTarget;
if (METAMASK_DEBUG) {
return undefined;
} else if (METAMASK_ENVIRONMENT === 'production') {
if (!process.env.SENTRY_DSN) {
throw new Error(
`Missing SENTRY_DSN environment variable in production environment`,
);
}
console.log(
`Setting up Sentry Remote Error Reporting for '${METAMASK_ENVIRONMENT}': SENTRY_DSN`,
);
sentryTarget = process.env.SENTRY_DSN;
} else {
console.log(
`Setting up Sentry Remote Error Reporting for '${METAMASK_ENVIRONMENT}': SENTRY_DSN_DEV`,
);
sentryTarget = SENTRY_DSN_DEV;
}
const environment =
METAMASK_BUILD_TYPE === BuildType.main
? METAMASK_ENVIRONMENT
: `${METAMASK_ENVIRONMENT}-${METAMASK_BUILD_TYPE}`;
Sentry.init({
dsn: sentryTarget,
debug: METAMASK_DEBUG,
environment,
integrations: [new Dedupe(), new ExtraErrorData()],
release,
beforeSend: (report) => rewriteReport(report),
});
function rewriteReport(report) {
try {
// simplify certain complex error messages (e.g. Ethjs)
simplifyErrorMessages(report);
// modify report urls
rewriteReportUrls(report);
// append app state
if (getState) {
const appState = getState();
if (!report.extra) {
report.extra = {};
}
report.extra.appState = appState;
}
} catch (err) {
console.warn(err);
}
return report;
}
return Sentry;
}
function simplifyErrorMessages(report) {
rewriteErrorMessages(report, (errorMessage) => {
// simplify ethjs error messages
let simplifiedErrorMessage = extractEthjsErrorMessage(errorMessage);
// simplify 'Transaction Failed: known transaction'
if (
simplifiedErrorMessage.indexOf(
'Transaction Failed: known transaction',
) === 0
) {
// cut the hash from the error message
simplifiedErrorMessage = 'Transaction Failed: known transaction';
}
return simplifiedErrorMessage;
});
}
function rewriteErrorMessages(report, rewriteFn) {
// rewrite top level message
if (typeof report.message === 'string') {
report.message = rewriteFn(report.message);
}
// rewrite each exception message
if (report.exception && report.exception.values) {
report.exception.values.forEach((item) => {
if (typeof item.value === 'string') {
item.value = rewriteFn(item.value);
}
});
}
}
function rewriteReportUrls(report) {
// update request url
report.request.url = toMetamaskUrl(report.request.url);
// update exception stack trace
if (report.exception && report.exception.values) {
report.exception.values.forEach((item) => {
if (item.stacktrace) {
item.stacktrace.frames.forEach((frame) => {
frame.filename = toMetamaskUrl(frame.filename);
});
}
});
}
}
function toMetamaskUrl(origUrl) {
const filePath = origUrl.split(window.location.origin)[1];
if (!filePath) {
return origUrl;
}
const metamaskUrl = `metamask${filePath}`;
return metamaskUrl;
}