Skip to content

Commit

Permalink
Update Logger.error function signature
Browse files Browse the repository at this point in the history
`Logger.error` now expects an actual error object as the first
argument. This allows us to submit proper Errors with stack traces to
Sentry. The second parameter is an optional set of extra data, which
gets attached to the Error and is viewable on Sentry in the "Additional
Data" section of the error report.

Unfortunately any messages added to contextualize errors had to be
submitted as extra data instead of as a wrapper Error. Wrapper error
types provide for a richer debugging experience in general, because
you get additional context for the error plus an additional stack trace
to help trace the flow of the error. Sentry even has an Integration
meant to facilitate this pattern, the `LinkedErrors` integration.
But unfortunately that integration doesn't seem to work with React
Native, so that option was off the table.
  • Loading branch information
Gudahtt committed Mar 6, 2020
1 parent f9072c1 commit b9e928c
Show file tree
Hide file tree
Showing 18 changed files with 57 additions and 54 deletions.
4 changes: 2 additions & 2 deletions app/components/UI/AccountList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class AccountList extends PureComponent {
} catch (e) {
// Restore to the previous index in case anything goes wrong
this.mounted && this.setState({ selectedAccountIndex: previousIndex });
Logger.error('error while trying change the selected account', e); // eslint-disable-line
Logger.error(e, 'error while trying change the selected account'); // eslint-disable-line
}
InteractionManager.runAfterInteractions(() => {
setTimeout(() => {
Expand Down Expand Up @@ -217,7 +217,7 @@ class AccountList extends PureComponent {
this.mounted && this.setState({ orderedAccounts });
} catch (e) {
// Restore to the previous index in case anything goes wrong
Logger.error('error while trying to add a new account', e); // eslint-disable-line
Logger.error(e, 'error while trying to add a new account'); // eslint-disable-line
this.mounted && this.setState({ loading: false });
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ class TransactionDetails extends PureComponent {
}
} catch (e) {
// eslint-disable-next-line no-console
Logger.error(`can't get a block explorer link for network `, networkID, e);
Logger.error(e, { message: `can't get a block explorer link for network `, networkID });
}
};

Expand Down
7 changes: 1 addition & 6 deletions app/components/UI/UrlAutocomplete/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { connect } from 'react-redux';
import WebsiteIcon from '../WebsiteIcon';
import { colors, fontStyles } from '../../../styles/common';
import { getHost } from '../../../util/browser';
import Logger from '../../../util/Logger';

const styles = StyleSheet.create({
wrapper: {
Expand Down Expand Up @@ -130,11 +129,7 @@ class UrlAutocomplete extends PureComponent {
}

updateResults(results) {
try {
this.mounted && this.setState({ results });
} catch (e) {
Logger.error('Autocomplete crash', results);
}
this.mounted && this.setState({ results });
}

onSubmitInput = () => this.props.onSubmit(this.props.input);
Expand Down
2 changes: 1 addition & 1 deletion app/components/Views/Browser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ class Browser extends PureComponent {
resolve(true);
},
error => {
Logger.error(`Error saving tab ${url}`, error);
Logger.error(error, `Error saving tab ${url}`);
reject(error);
}
);
Expand Down
8 changes: 4 additions & 4 deletions app/components/Views/BrowserTab/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,7 @@ export class BrowserTab extends PureComponent {
handleDeeplinks = async ({ error, params }) => {
if (!this.isTabActive()) return false;
if (error) {
Logger.error('Error from Branch: ', error);
Logger.error(error, 'Error from Branch');
return;
}
if (params['+non_branch_link']) {
Expand Down Expand Up @@ -1004,7 +1004,7 @@ export class BrowserTab extends PureComponent {
this.go(fullUrl);
return { url: null };
}
Logger.error('Failed to resolve ENS name', err);
Logger.error(err, 'Failed to resolve ENS name');
Alert.alert(strings('browser.error'), strings('browser.failed_to_resolve_ens_name'));
this.goBack();
}
Expand Down Expand Up @@ -1139,7 +1139,7 @@ export class BrowserTab extends PureComponent {
try {
SearchApi.indexSpotlightItem(item);
} catch (e) {
Logger.error('Error adding to spotlight', e);
Logger.error(e, 'Error adding to spotlight');
}
}
const analyticsEnabled = Analytics.getEnabled();
Expand Down Expand Up @@ -1269,7 +1269,7 @@ export class BrowserTab extends PureComponent {
break;
}
} catch (e) {
Logger.error(`Browser::onMessage on ${this.state.inputValue}`, e.toString());
Logger.error(e, `Browser::onMessage on ${this.state.inputValue}`);
}
};

Expand Down
2 changes: 1 addition & 1 deletion app/components/Views/Entry/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class Entry extends PureComponent {

handleDeeplinks = async ({ error, params }) => {
if (error) {
Logger.error('Error from Branch: ', error);
Logger.error(error, 'Error from Branch');
return;
}
if (params['+non_branch_link']) {
Expand Down
2 changes: 1 addition & 1 deletion app/components/Views/ImportPrivateKeySuccess/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class ImportPrivateKeySuccess extends PureComponent {
const accountsOrdered = allKeyrings.reduce((list, keyring) => list.concat(keyring.accounts), []);
PreferencesController.setSelectedAddress(accountsOrdered[accountsOrdered.length - 1]);
} catch (e) {
Logger.error('Error while refreshing imported pkey', e);
Logger.error(e, 'Error while refreshing imported pkey');
}
InteractionManager.runAfterInteractions(() => {
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
Expand Down
8 changes: 3 additions & 5 deletions app/components/Views/ImportWallet/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,7 @@ class ImportWallet extends PureComponent {
);
}
}
Logger.log('Sync::startSync', firstAttempt);
Logger.log('Sync::startSync', e.toString());
Logger.error('Sync::startSync', e);
Logger.error(e, { message: 'Sync::startSync', firstAttempt });
return false;
}
};
Expand Down Expand Up @@ -315,7 +313,7 @@ class ImportWallet extends PureComponent {
await AsyncStorage.setItem('@MetaMask:biometryChoice', opts.biometryType);
}
} catch (e) {
Logger.error('User cancelled biometrics permission', e);
Logger.error(e, 'User cancelled biometrics permission');
await AsyncStorage.removeItem('@MetaMask:biometryChoice');
await AsyncStorage.setItem('@MetaMask:biometryChoiceDisabled', 'true');
await AsyncStorage.setItem('@MetaMask:passcodeDisabled', 'true');
Expand All @@ -338,7 +336,7 @@ class ImportWallet extends PureComponent {
this.dataToSync = null;
this.props.navigation.push('SyncWithExtensionSuccess');
} catch (e) {
Logger.error('Sync::disconnect', e);
Logger.error(e, 'Sync::disconnect');
Alert.alert(strings('sync_with_extension.error_title'), strings('sync_with_extension.error_message'));
this.setState({ loading: false });
this.props.navigation.goBack();
Expand Down
2 changes: 1 addition & 1 deletion app/components/Views/LockScreen/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class LockScreen extends PureComponent {
if (this.unlockAttempts <= 3) {
this.attemptUnlock();
} else {
Logger.error('Lockscreen:maxAttemptsReached', { attemptNumber: this.unlockAttempts, error });
Logger.error(error, { message: 'Lockscreen:maxAttemptsReached', attemptNumber: this.unlockAttempts });
this.props.navigation.navigate('Login');
}
}
Expand Down
3 changes: 1 addition & 2 deletions app/components/Views/PaymentChannel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,7 @@ class PaymentChannel extends PureComponent {
!this.state.connextStateDisabled &&
Alert.alert(strings('payment_channel.error_title'), strings('payment_channel.error_desc'));
this.setState({ connextStateDisabled: true });
Logger.log('InstaPay:ChainSawError', channelState);
Logger.error('InstaPay:ChainSawError');
Logger.error(new Error('InstaPay:ChainSawError'), { channelState });
}
};

Expand Down
4 changes: 2 additions & 2 deletions app/components/Views/Settings/AdvancedSettings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ class AdvancedSettings extends PureComponent {
url
});
} catch (err) {
Logger.error('State log error', err);
Logger.error(err, 'State log error');
}
};

Expand Down Expand Up @@ -253,7 +253,7 @@ class AdvancedSettings extends PureComponent {
url
});
} catch (err) {
Logger.error('Instapay log error', err);
Logger.error(err, 'Instapay log error');
}
};

Expand Down
2 changes: 1 addition & 1 deletion app/components/Views/Settings/SecuritySettings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ class Settings extends PureComponent {
if (e.message === 'Invalid password') {
Alert.alert(strings('app_settings.invalid_password'), strings('app_settings.invalid_password_message'));
}
Logger.error('SecuritySettings:biometrics', e);
Logger.error(e, 'SecuritySettings:biometrics');
// Return the switch to the previous value
if (type === 'biometrics') {
this.setState({ biometryChoice: !enabled });
Expand Down
8 changes: 3 additions & 5 deletions app/components/Views/SyncWithExtension/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,7 @@ class SyncWithExtension extends PureComponent {
);
}
}
Logger.log('Sync::startSync', firstAttempt);
Logger.log('Sync::startSync', e.toString());
Logger.error('Sync::startSync', e);
Logger.error(e, 'Sync::startSync', { firstAttempt });
return false;
}
};
Expand Down Expand Up @@ -265,7 +263,7 @@ class SyncWithExtension extends PureComponent {
}
await AsyncStorage.setItem('@MetaMask:biometryChoice', this.state.biometryType);
} catch (e) {
Logger.error('User cancelled biometrics permission', e);
Logger.error(e, 'User cancelled biometrics permission');
await AsyncStorage.removeItem('@MetaMask:biometryChoice');
}
}
Expand All @@ -283,7 +281,7 @@ class SyncWithExtension extends PureComponent {
this.dataToSync = null;
this.props.navigation.push('SyncWithExtensionSuccess');
} catch (e) {
Logger.error('Sync::disconnect', e);
Logger.error(e, 'Sync::disconnect');
Alert.alert(strings('sync_with_extension.error_title'), strings('sync_with_extension.error_message'));
this.setState({ loading: false });
this.props.navigation.goBack();
Expand Down
2 changes: 1 addition & 1 deletion app/components/Views/WalletConnectSessions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export default class WalletConnectSessions extends PureComponent {
);
this.loadSessions();
} catch (e) {
Logger.error('WC: Failed to kill session', e);
Logger.error(e, 'WC: Failed to kill session');
}
};

Expand Down
18 changes: 9 additions & 9 deletions app/core/PaymentChannelsClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class PaymentChannelsClient {
this.setState({ blocked: false });
}, 60 * BLOCKED_DEPOSIT_DURATION_MINUTES * 1000);
}
Logger.error('ExternalWallet::sign', e);
Logger.error(e, 'ExternalWallet::sign');
throw e;
}
}
Expand All @@ -179,7 +179,7 @@ class PaymentChannelsClient {
});
} catch (e) {
this.logCurrentState('PC::createClient');
Logger.error('PC::createClient', e);
Logger.error(e, 'PC::createClient');
throw e;
}
}
Expand All @@ -203,7 +203,7 @@ class PaymentChannelsClient {
Logger.log('PC::pollConnextState connext.start succesful');
} catch (e) {
this.logCurrentState('PC::start');
Logger.error('PC::start', e);
Logger.error(e, 'PC::start');
}
// register connext listeners
connext.on('onStateChange', async state => {
Expand All @@ -229,7 +229,7 @@ class PaymentChannelsClient {
}
} catch (e) {
this.logCurrentState('PC::onStateChange');
Logger.error('PC::onStateChange', e);
Logger.error(e, 'PC::onStateChange');
}
});
}
Expand Down Expand Up @@ -265,7 +265,7 @@ class PaymentChannelsClient {
await this.autoSwap();
} catch (e) {
this.logCurrentState('PC::autoswap');
Logger.error('PC::autoswap', e);
Logger.error(e, 'PC::autoswap');
this.setState({ swapPending: false });
}
this.autoswapHandler = setTimeout(() => {
Expand Down Expand Up @@ -380,7 +380,7 @@ class PaymentChannelsClient {
this.setState({ depositPending: true });
} catch (e) {
this.logCurrentState('PC::deposit');
Logger.error('PC::deposit', e);
Logger.error(e, 'PC::deposit');
throw e;
}
};
Expand Down Expand Up @@ -419,7 +419,7 @@ class PaymentChannelsClient {
await connext.buy(data);
} catch (e) {
this.logCurrentState('PC::buy');
Logger.error('PC::buy', e);
Logger.error(e, 'PC::buy');
}
};

Expand All @@ -443,7 +443,7 @@ class PaymentChannelsClient {
this.setState({ withdrawalPending: true, withdrawalPendingValue: toWei(renderFromWei(balanceTokenUser)) });
} catch (e) {
this.logCurrentState('PC::withdraw');
Logger.error('PC::withdraw', e);
Logger.error(e, 'PC::withdraw');
}
};

Expand Down Expand Up @@ -483,7 +483,7 @@ const instance = {
await client.pollAndSwap();
} catch (e) {
client.logCurrentState('PC::init');
Logger.error('PC::init', e);
Logger.error(e, 'PC::init');
}
}
},
Expand Down
22 changes: 16 additions & 6 deletions app/util/Logger.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

import { addBreadcrumb, captureException } from '@sentry/react-native';
import { addBreadcrumb, captureException, withScope } from '@sentry/react-native';
import AsyncStorage from '@react-native-community/async-storage';

/**
Expand Down Expand Up @@ -32,17 +32,27 @@ export default class Logger {
/**
* console.error wrapper
*
* @param {object} args - data to be logged
* @param {Error} error - error to be logged
* @param {string|object} extra - Extra error info
* @returns - void
*/
static async error(...args) {
static async error(error, extra) {
// Check if user passed accepted opt-in to metrics
const metricsOptIn = await AsyncStorage.getItem('@MetaMask:metricsOptIn');
if (__DEV__) {
args.unshift('[MetaMask DEBUG]:');
console.warn(args); // eslint-disable-line no-console
console.warn('[MetaMask DEBUG]:', error); // eslint-disable-line no-console
} else if (metricsOptIn === 'agreed') {
captureException(args);
if (extra) {
if (typeof extra === 'string') {
extra = { message: extra };
}
withScope(scope => {
scope.setExtras(extra);
captureException(error);
});
} else {
captureException(error);
}
}
}
}
3 changes: 2 additions & 1 deletion app/util/middlewares.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export function createLoggerMiddleware(opts) {
return function loggerMiddleware(/** @type {any} */ req, /** @type {any} */ res, /** @type {Function} */ next) {
next((/** @type {Function} */ cb) => {
if (res.error) {
Logger.error('Error in RPC response:\n', res);
const { error, ...resWithoutError } = res;
Logger.error(error, { message: 'Error in RPC response', res: resWithoutError });
}
if (req.isMetamaskInternal) {
return;
Expand Down
12 changes: 7 additions & 5 deletions app/util/syncWithExtension.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,18 @@ export default class PubNubWrapper {
this.pubnubListener = {
message: ({ channel, message }) => {
if (channel !== this.channelName || !message) {
Logger.log('Sync::message', channel !== this.channelName, !message);
Logger.error('Sync::message', channel !== this.channelName, !message);
Logger.error(new Error('Unrecognized message'), {
thisChannelName: this.channelName,
channel,
message
});
this.timeout = false;
return false;
}
if (message.event === 'error-sync') {
this.timeout = false;
this.disconnectWebsockets();
Logger.error('Sync::error-sync');
Logger.error(new Error('Sync::error-sync'), { channel, message });
onErrorSync();
}
if (message.event === 'syncing-data' && message.currentPkg > this.lastReceivedPkg) {
Expand All @@ -162,8 +165,7 @@ export default class PubNubWrapper {
const data = JSON.parse(this.incomingDataStr);
onSyncingData(data);
} catch (e) {
Logger.log('Sync::parsing', e.toString());
Logger.error('Sync::parsing', e);
Logger.error(e, 'Sync::parsing');
}
}
}
Expand Down

0 comments on commit b9e928c

Please sign in to comment.