From 4773e13ef714bbdb259f663fe2043a7c10c6bfc2 Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Fri, 14 Aug 2020 17:54:21 +0800 Subject: [PATCH] Explorer: add error reporting (#11627) --- explorer/package-lock.json | 70 +++++++++++++++++++ explorer/package.json | 1 + .../account/TokenAccountSection.tsx | 9 ++- .../stake/AuthorizeDetailsCard.tsx | 1 - .../instruction/token/TokenDetailsCard.tsx | 6 ++ explorer/src/index.tsx | 12 ++-- explorer/src/providers/accounts/history.tsx | 3 +- explorer/src/providers/accounts/index.tsx | 10 ++- explorer/src/providers/accounts/tokens.tsx | 2 + explorer/src/providers/cluster.tsx | 5 +- explorer/src/providers/mints/largest.tsx | 2 + explorer/src/providers/mints/supply.tsx | 2 + explorer/src/providers/richList.tsx | 3 +- explorer/src/providers/supply.tsx | 3 +- .../src/providers/transactions/details.tsx | 3 +- explorer/src/providers/transactions/index.tsx | 10 +-- 16 files changed, 120 insertions(+), 22 deletions(-) diff --git a/explorer/package-lock.json b/explorer/package-lock.json index dc372d0d3b..fa55bec5db 100644 --- a/explorer/package-lock.json +++ b/explorer/package-lock.json @@ -2649,6 +2649,76 @@ "resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.2.tgz", "integrity": "sha512-zLtOIToct1EBTbwldkMJsXC2eCsmWOOP7z6UG0M/sCgnPExtIjvVMCpPESvPnMbQzDZytXVy0nvMbUuK2gZs2A==" }, + "@sentry/browser": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.21.1.tgz", + "integrity": "sha512-sUxsW545klZxJE4iBAYQ8SuVS85HTOGNmIIIZWFUogB5oW3O0L+nJluXEqf/pHU82LnjDIzqsWCYQ0cRUaeYow==", + "requires": { + "@sentry/core": "5.21.1", + "@sentry/types": "5.21.1", + "@sentry/utils": "5.21.1", + "tslib": "^1.9.3" + } + }, + "@sentry/core": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.21.1.tgz", + "integrity": "sha512-Luulwx3GLUiY0gmHOhU+4eSga28Ce8DwoBcRq9GkGuhPu9r80057d5urxrDLp/leIZBXVvpY7tvmSN/rMtvF9w==", + "requires": { + "@sentry/hub": "5.21.1", + "@sentry/minimal": "5.21.1", + "@sentry/types": "5.21.1", + "@sentry/utils": "5.21.1", + "tslib": "^1.9.3" + } + }, + "@sentry/hub": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.21.1.tgz", + "integrity": "sha512-x5i9Ggi5ZYMhBYL5kyTu2fUJ6owjKH2tgJL3UExoZdRyZkbLAFZb+DtfSnteWgQ6wriGfgPD3r/hAIEdaomk2A==", + "requires": { + "@sentry/types": "5.21.1", + "@sentry/utils": "5.21.1", + "tslib": "^1.9.3" + } + }, + "@sentry/minimal": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.21.1.tgz", + "integrity": "sha512-OBVPASZ+mcXMKajvJon9RjEZ+ny3+VGhOI66acoP1hmYxKvji1OC2bYEuP1r4qtHxWVLAdV7qFj3EQ9ckErZmQ==", + "requires": { + "@sentry/hub": "5.21.1", + "@sentry/types": "5.21.1", + "tslib": "^1.9.3" + } + }, + "@sentry/react": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@sentry/react/-/react-5.21.1.tgz", + "integrity": "sha512-e60erzdQOwZ88+j6Hi1AnRlxex7ZmwQPGSoFjtihQJR3Xv9Esj5DBKVrWu6Z/QCDxTc8uaX08XjUyhse2YyutQ==", + "requires": { + "@sentry/browser": "5.21.1", + "@sentry/minimal": "5.21.1", + "@sentry/types": "5.21.1", + "@sentry/utils": "5.21.1", + "hoist-non-react-statics": "^3.3.2", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.21.1.tgz", + "integrity": "sha512-hFN4aDduMpjj6vZSIIp+9kSr8MglcKO/UmbuUXN6hKLewhxt+Zj2wjXN7ulSs5OK5mjXP9QLA5YJvVQsl2//qw==" + }, + "@sentry/utils": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.21.1.tgz", + "integrity": "sha512-p5vPuc7+GfOmW8CXxWd0samS77Q00YrN8q5TC/ztF8nBhEF18GiMeWAdQnlSwt3iWal3q3gSSrbF4c9guIugng==", + "requires": { + "@sentry/types": "5.21.1", + "tslib": "^1.9.3" + } + }, "@solana/web3.js": { "version": "0.70.3", "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-0.70.3.tgz", diff --git a/explorer/package.json b/explorer/package.json index 534e2ad89f..43a2b867a6 100644 --- a/explorer/package.json +++ b/explorer/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "@react-hook/debounce": "^3.0.0", + "@sentry/react": "^5.21.1", "@solana/web3.js": "^0.70.3", "@testing-library/jest-dom": "^5.11.3", "@testing-library/react": "^10.4.8", diff --git a/explorer/src/components/account/TokenAccountSection.tsx b/explorer/src/components/account/TokenAccountSection.tsx index 99a2f9a4bd..a8444686f6 100644 --- a/explorer/src/components/account/TokenAccountSection.tsx +++ b/explorer/src/components/account/TokenAccountSection.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { Account, useFetchAccountInfo } from "providers/accounts"; import { TokenAccount, @@ -37,7 +38,13 @@ export function TokenAccountSection({ return ; } } - } catch (err) {} + } catch (err) { + Sentry.captureException(err, { + tags: { + address: account.pubkey.toBase58(), + }, + }); + } return ; } diff --git a/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx b/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx index c76389d1e8..012d0f611d 100644 --- a/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx +++ b/explorer/src/components/instruction/stake/AuthorizeDetailsCard.tsx @@ -20,7 +20,6 @@ export function AuthorizeDetailsCard(props: { try { params = StakeInstruction.decodeAuthorize(ix); } catch (err) { - console.error(err); return ; } diff --git a/explorer/src/components/instruction/token/TokenDetailsCard.tsx b/explorer/src/components/instruction/token/TokenDetailsCard.tsx index a21dbcd1f6..d1634d2938 100644 --- a/explorer/src/components/instruction/token/TokenDetailsCard.tsx +++ b/explorer/src/components/instruction/token/TokenDetailsCard.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { coerce } from "superstruct"; import { SignatureResult, @@ -29,6 +30,11 @@ export function TokenDetailsCard(props: DetailsProps) { const coerced = coerce(info, IX_STRUCTS[type] as any); return ; } catch (err) { + Sentry.captureException(err, { + tags: { + signature: props.tx.signatures[0], + }, + }); return ; } } diff --git a/explorer/src/index.tsx b/explorer/src/index.tsx index d1716cd4a7..3bda904599 100644 --- a/explorer/src/index.tsx +++ b/explorer/src/index.tsx @@ -1,9 +1,9 @@ import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter as Router } from "react-router-dom"; +import * as Sentry from "@sentry/react"; import "./scss/theme-dark.scss"; import App from "./App"; -import * as serviceWorker from "./serviceWorker"; import { ClusterProvider } from "./providers/cluster"; import { RichListProvider } from "./providers/richList"; import { SupplyProvider } from "./providers/supply"; @@ -12,6 +12,11 @@ import { AccountsProvider } from "./providers/accounts"; import { StatsProvider } from "providers/stats"; import { MintsProvider } from "providers/mints"; +Sentry.init({ + dsn: + "https://5efdc15b4828434fbe949b5daed472be@o434108.ingest.sentry.io/5390542", +}); + ReactDOM.render( @@ -32,8 +37,3 @@ ReactDOM.render( , document.getElementById("root") ); - -// If you want your app to work offline and load faster, you can change -// unregister() to register() below. Note this comes with some pitfalls. -// Learn more about service workers: https://bit.ly/CRA-PWA -serviceWorker.unregister(); diff --git a/explorer/src/providers/accounts/history.tsx b/explorer/src/providers/accounts/history.tsx index 306b0557f0..f66faecc96 100644 --- a/explorer/src/providers/accounts/history.tsx +++ b/explorer/src/providers/accounts/history.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { PublicKey, ConfirmedSignatureInfo, @@ -101,7 +102,7 @@ async function fetchAccountHistory( }; status = FetchStatus.Fetched; } catch (error) { - console.error("Failed to fetch account history", error); + Sentry.captureException(error, { tags: { url } }); status = FetchStatus.FetchFailed; } dispatch({ diff --git a/explorer/src/providers/accounts/index.tsx b/explorer/src/providers/accounts/index.tsx index 1118988f22..a0f9e3ecad 100644 --- a/explorer/src/providers/accounts/index.tsx +++ b/explorer/src/providers/accounts/index.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { StakeAccount as StakeAccountWasm } from "solana-sdk-wasm"; import { PublicKey, Connection, StakeProgram } from "@solana/web3.js"; import { useCluster } from "../cluster"; @@ -111,7 +112,9 @@ async function fetchAccountInfo( parsed, }; } catch (err) { - console.error("Failed to parse stake account", err); + Sentry.captureException(err, { + tags: { url, address: pubkey.toBase58() }, + }); // TODO store error state in Account info } } else if ("parsed" in result.data) { @@ -124,6 +127,9 @@ async function fetchAccountInfo( parsed, }; } catch (err) { + Sentry.captureException(err, { + tags: { url, address: pubkey.toBase58() }, + }); // TODO store error state in Account info } } @@ -139,7 +145,7 @@ async function fetchAccountInfo( data = { pubkey, lamports, details }; fetchStatus = FetchStatus.Fetched; } catch (error) { - console.error("Failed to fetch account info", error); + Sentry.captureException(error, { tags: { url } }); fetchStatus = FetchStatus.FetchFailed; } dispatch({ diff --git a/explorer/src/providers/accounts/tokens.tsx b/explorer/src/providers/accounts/tokens.tsx index 3f2ee369ae..eb27f43b4b 100644 --- a/explorer/src/providers/accounts/tokens.tsx +++ b/explorer/src/providers/accounts/tokens.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { Connection, PublicKey } from "@solana/web3.js"; import * as Cache from "providers/cache"; import { ActionType, FetchStatus } from "providers/cache"; @@ -72,6 +73,7 @@ async function fetchAccountTokens( }; status = FetchStatus.Fetched; } catch (error) { + Sentry.captureException(error, { tags: { url } }); status = FetchStatus.FetchFailed; } dispatch({ type: ActionType.Update, url, status, data, key }); diff --git a/explorer/src/providers/cluster.tsx b/explorer/src/providers/cluster.tsx index ee7cc1b1b4..9591e5d5ec 100644 --- a/explorer/src/providers/cluster.tsx +++ b/explorer/src/providers/cluster.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { clusterApiUrl, Connection } from "@solana/web3.js"; import { useQuery } from "../utils/url"; import { useHistory, useLocation } from "react-router-dom"; @@ -182,7 +183,9 @@ async function updateCluster( firstAvailableBlock, }); } catch (error) { - console.error("Failed to update cluster", error); + Sentry.captureException(error, { + tags: { clusterUrl: clusterUrl(cluster, customUrl) }, + }); dispatch({ status: ClusterStatus.Failure, cluster, customUrl }); } } diff --git a/explorer/src/providers/mints/largest.tsx b/explorer/src/providers/mints/largest.tsx index bfacaf0ba0..7595abf68e 100644 --- a/explorer/src/providers/mints/largest.tsx +++ b/explorer/src/providers/mints/largest.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { useCluster } from "providers/cluster"; import * as Cache from "providers/cache"; import { ActionType, FetchStatus } from "providers/cache"; @@ -59,6 +60,7 @@ async function fetchLargestAccounts( }; fetchStatus = FetchStatus.Fetched; } catch (error) { + Sentry.captureException(error, { tags: { url } }); fetchStatus = FetchStatus.FetchFailed; } dispatch({ diff --git a/explorer/src/providers/mints/supply.tsx b/explorer/src/providers/mints/supply.tsx index bd51070c50..1d3a45ee03 100644 --- a/explorer/src/providers/mints/supply.tsx +++ b/explorer/src/providers/mints/supply.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { useCluster } from "providers/cluster"; import * as Cache from "providers/cache"; import { ActionType, FetchStatus } from "providers/cache"; @@ -44,6 +45,7 @@ async function fetchSupply(dispatch: Dispatch, pubkey: PublicKey, url: string) { fetchStatus = FetchStatus.Fetched; } catch (error) { + Sentry.captureException(error, { tags: { url } }); fetchStatus = FetchStatus.FetchFailed; } dispatch({ diff --git a/explorer/src/providers/richList.tsx b/explorer/src/providers/richList.tsx index fdb0d7b58e..ecfa8c0457 100644 --- a/explorer/src/providers/richList.tsx +++ b/explorer/src/providers/richList.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { AccountBalancePair, Connection } from "@solana/web3.js"; import { useCluster, ClusterStatus } from "./cluster"; @@ -70,7 +71,7 @@ async function fetch(dispatch: Dispatch, url: string) { return { total, circulating, nonCirculating }; }); } catch (err) { - console.error("Failed to fetch", err); + Sentry.captureException(err, { tags: { url } }); dispatch("Failed to fetch top accounts"); } } diff --git a/explorer/src/providers/supply.tsx b/explorer/src/providers/supply.tsx index c601efd830..e7a6bad709 100644 --- a/explorer/src/providers/supply.tsx +++ b/explorer/src/providers/supply.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { Supply, Connection } from "@solana/web3.js"; import { useCluster, ClusterStatus } from "./cluster"; @@ -50,7 +51,7 @@ async function fetch(dispatch: Dispatch, url: string) { return supply; }); } catch (err) { - console.error("Failed to fetch", err); + Sentry.captureException(err, { tags: { url } }); dispatch("Failed to fetch supply"); } } diff --git a/explorer/src/providers/transactions/details.tsx b/explorer/src/providers/transactions/details.tsx index 77e1fbbf4c..623f36e77a 100644 --- a/explorer/src/providers/transactions/details.tsx +++ b/explorer/src/providers/transactions/details.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { Connection, TransactionSignature, @@ -63,7 +64,7 @@ async function fetchDetails( ); fetchStatus = FetchStatus.Fetched; } catch (error) { - console.error("Failed to fetch confirmed transaction", error); + Sentry.captureException(error, { tags: { url } }); fetchStatus = FetchStatus.FetchFailed; } } diff --git a/explorer/src/providers/transactions/index.tsx b/explorer/src/providers/transactions/index.tsx index 764b4e0040..5f65974f31 100644 --- a/explorer/src/providers/transactions/index.tsx +++ b/explorer/src/providers/transactions/index.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as Sentry from "@sentry/react"; import { TransactionSignature, Connection, @@ -85,12 +86,7 @@ export async function fetchTransactionStatus( try { blockTime = await connection.getBlockTime(value.slot); } catch (error) { - console.error( - "Failed to fetch block time for slot ", - value.slot, - ":", - error - ); + Sentry.captureException(error, { tags: { slot: `${value.slot}` } }); } let timestamp: Timestamp = blockTime !== null ? blockTime : "unavailable"; @@ -112,7 +108,7 @@ export async function fetchTransactionStatus( data = { signature, info }; fetchStatus = FetchStatus.Fetched; } catch (error) { - console.error("Failed to fetch transaction status", error); + Sentry.captureException(error, { tags: { url } }); fetchStatus = FetchStatus.FetchFailed; } }