diff --git a/explorer/src/components/account/TokenAccountSection.tsx b/explorer/src/components/account/TokenAccountSection.tsx
index 535e1a8ddf..44721cd3b7 100644
--- a/explorer/src/components/account/TokenAccountSection.tsx
+++ b/explorer/src/components/account/TokenAccountSection.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import * as Sentry from "@sentry/react";
import { Account, useFetchAccountInfo } from "providers/accounts";
import {
TokenAccount,
@@ -15,6 +14,7 @@ import { TokenRegistry } from "tokenRegistry";
import { useCluster } from "providers/cluster";
import { normalizeTokenAmount } from "utils";
import { addressLabel } from "utils/tx";
+import { reportError } from "utils/sentry";
export function TokenAccountSection({
account,
@@ -39,10 +39,8 @@ export function TokenAccountSection({
}
}
} catch (err) {
- Sentry.captureException(err, {
- tags: {
- address: account.pubkey.toBase58(),
- },
+ reportError(err, {
+ address: account.pubkey.toBase58(),
});
}
return ;
diff --git a/explorer/src/components/instruction/SerumDetailsCard.tsx b/explorer/src/components/instruction/SerumDetailsCard.tsx
index 202c8e7aa8..5ed94524e5 100644
--- a/explorer/src/components/instruction/SerumDetailsCard.tsx
+++ b/explorer/src/components/instruction/SerumDetailsCard.tsx
@@ -1,9 +1,9 @@
import React from "react";
-import * as Sentry from "@sentry/react";
import { TransactionInstruction, SignatureResult } from "@solana/web3.js";
import { InstructionCard } from "./InstructionCard";
import { parseSerumInstructionTitle } from "utils/tx";
import { useCluster } from "providers/cluster";
+import { reportError } from "utils/sentry";
export function SerumDetailsCard({
ix,
@@ -22,11 +22,9 @@ export function SerumDetailsCard({
try {
title = parseSerumInstructionTitle(ix);
} catch (error) {
- Sentry.captureException(error, {
- tags: {
- url: url,
- signature: signature,
- },
+ reportError(error, {
+ url: url,
+ signature: signature,
});
}
diff --git a/explorer/src/components/instruction/token/TokenDetailsCard.tsx b/explorer/src/components/instruction/token/TokenDetailsCard.tsx
index 8f8b069498..4677a445e8 100644
--- a/explorer/src/components/instruction/token/TokenDetailsCard.tsx
+++ b/explorer/src/components/instruction/token/TokenDetailsCard.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import * as Sentry from "@sentry/react";
import { coerce } from "superstruct";
import {
SignatureResult,
@@ -19,6 +18,7 @@ import {
useFetchAccountInfo,
} from "providers/accounts";
import { normalizeTokenAmount } from "utils";
+import { reportError } from "utils/sentry";
type DetailsProps = {
tx: ParsedTransaction;
@@ -36,10 +36,8 @@ 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],
- },
+ reportError(err, {
+ signature: props.tx.signatures[0],
});
return ;
}
diff --git a/explorer/src/index.tsx b/explorer/src/index.tsx
index 3bda904599..68f45863ed 100644
--- a/explorer/src/index.tsx
+++ b/explorer/src/index.tsx
@@ -12,10 +12,12 @@ 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",
-});
+if (process.env.NODE_ENV === "production") {
+ Sentry.init({
+ dsn:
+ "https://5efdc15b4828434fbe949b5daed472be@o434108.ingest.sentry.io/5390542",
+ });
+}
ReactDOM.render(
diff --git a/explorer/src/providers/accounts/history.tsx b/explorer/src/providers/accounts/history.tsx
index 391d6b9364..14558d38ac 100644
--- a/explorer/src/providers/accounts/history.tsx
+++ b/explorer/src/providers/accounts/history.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import * as Sentry from "@sentry/react";
import {
PublicKey,
ConfirmedSignatureInfo,
@@ -9,6 +8,7 @@ import {
import { useCluster, Cluster } from "../cluster";
import * as Cache from "providers/cache";
import { ActionType, FetchStatus } from "providers/cache";
+import { reportError } from "utils/sentry";
type AccountHistory = {
fetched: ConfirmedSignatureInfo[];
@@ -104,7 +104,7 @@ async function fetchAccountHistory(
status = FetchStatus.Fetched;
} catch (error) {
if (cluster !== Cluster.Custom) {
- Sentry.captureException(error, { tags: { url } });
+ reportError(error, { url });
}
status = FetchStatus.FetchFailed;
}
diff --git a/explorer/src/providers/accounts/index.tsx b/explorer/src/providers/accounts/index.tsx
index 78b4c92f72..8f72caef03 100644
--- a/explorer/src/providers/accounts/index.tsx
+++ b/explorer/src/providers/accounts/index.tsx
@@ -1,5 +1,4 @@
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, Cluster } from "../cluster";
@@ -15,6 +14,7 @@ import {
} from "validators/accounts/token";
import * as Cache from "providers/cache";
import { ActionType, FetchStatus } from "providers/cache";
+import { reportError } from "utils/sentry";
export { useAccountHistory } from "./history";
export type StakeProgramData = {
@@ -117,9 +117,7 @@ async function fetchAccountInfo(
parsed,
};
} catch (err) {
- Sentry.captureException(err, {
- tags: { url, address: pubkey.toBase58() },
- });
+ reportError(err, { url, address: pubkey.toBase58() });
// TODO store error state in Account info
}
} else if ("parsed" in result.data) {
@@ -133,9 +131,7 @@ async function fetchAccountInfo(
parsed,
};
} catch (err) {
- Sentry.captureException(err, {
- tags: { url, address: pubkey.toBase58() },
- });
+ reportError(err, { url, address: pubkey.toBase58() });
// TODO store error state in Account info
}
}
@@ -152,7 +148,7 @@ async function fetchAccountInfo(
fetchStatus = FetchStatus.Fetched;
} catch (error) {
if (cluster !== Cluster.Custom) {
- Sentry.captureException(error, { tags: { url } });
+ reportError(error, { url });
}
fetchStatus = FetchStatus.FetchFailed;
}
@@ -200,9 +196,7 @@ export function useMintAccountInfo(
return coerce(data.parsed.info, MintAccountInfo);
} catch (err) {
- Sentry.captureException(err, {
- tags: { address },
- });
+ reportError(err, { address });
}
}
@@ -221,9 +215,7 @@ export function useTokenAccountInfo(
return coerce(data.parsed.info, TokenAccountInfo);
} catch (err) {
- Sentry.captureException(err, {
- tags: { address },
- });
+ reportError(err, { address });
}
}
diff --git a/explorer/src/providers/accounts/tokens.tsx b/explorer/src/providers/accounts/tokens.tsx
index 9932771a71..d25b87ebfe 100644
--- a/explorer/src/providers/accounts/tokens.tsx
+++ b/explorer/src/providers/accounts/tokens.tsx
@@ -1,11 +1,11 @@
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";
import { TokenAccountInfo } from "validators/accounts/token";
import { useCluster, Cluster } from "../cluster";
import { coerce } from "superstruct";
+import { reportError } from "utils/sentry";
export type TokenInfoWithPubkey = {
info: TokenAccountInfo;
@@ -75,7 +75,7 @@ async function fetchAccountTokens(
status = FetchStatus.Fetched;
} catch (error) {
if (cluster !== Cluster.Custom) {
- Sentry.captureException(error, { tags: { url } });
+ reportError(error, { url });
}
status = FetchStatus.FetchFailed;
}
diff --git a/explorer/src/providers/cluster.tsx b/explorer/src/providers/cluster.tsx
index 99177df960..95c2416f9c 100644
--- a/explorer/src/providers/cluster.tsx
+++ b/explorer/src/providers/cluster.tsx
@@ -1,8 +1,8 @@
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";
+import { reportError } from "utils/sentry";
export enum ClusterStatus {
Connected,
@@ -184,9 +184,7 @@ async function updateCluster(
});
} catch (error) {
if (cluster !== Cluster.Custom) {
- Sentry.captureException(error, {
- tags: { clusterUrl: clusterUrl(cluster, customUrl) },
- });
+ reportError(error, { 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 00cae42692..2ef8f875cc 100644
--- a/explorer/src/providers/mints/largest.tsx
+++ b/explorer/src/providers/mints/largest.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import * as Sentry from "@sentry/react";
import { useCluster, Cluster } from "providers/cluster";
import * as Cache from "providers/cache";
import { ActionType, FetchStatus } from "providers/cache";
@@ -12,6 +11,7 @@ import {
import { TokenAccountInfo, TokenAccount } from "validators/accounts/token";
import { ParsedInfo } from "validators";
import { coerce } from "superstruct";
+import { reportError } from "utils/sentry";
type LargestAccounts = {
largest: TokenAccountBalancePairWithOwner[];
@@ -89,7 +89,7 @@ async function fetchLargestAccounts(
}
} catch (error) {
if (cluster !== Cluster.Custom) {
- Sentry.captureException(error, { tags: { url } });
+ reportError(error, { url });
}
}
return account;
@@ -100,7 +100,7 @@ async function fetchLargestAccounts(
fetchStatus = FetchStatus.Fetched;
} catch (error) {
if (cluster !== Cluster.Custom) {
- Sentry.captureException(error, { tags: { url } });
+ reportError(error, { url });
}
fetchStatus = FetchStatus.FetchFailed;
}
diff --git a/explorer/src/providers/richList.tsx b/explorer/src/providers/richList.tsx
index b3f59b94d8..8293d25884 100644
--- a/explorer/src/providers/richList.tsx
+++ b/explorer/src/providers/richList.tsx
@@ -1,8 +1,8 @@
import React from "react";
-import * as Sentry from "@sentry/react";
import { AccountBalancePair, Connection } from "@solana/web3.js";
import { useCluster, ClusterStatus, Cluster } from "./cluster";
+import { reportError } from "utils/sentry";
export enum Status {
Idle,
@@ -72,7 +72,7 @@ async function fetch(dispatch: Dispatch, cluster: Cluster, url: string) {
});
} catch (err) {
if (cluster !== Cluster.Custom) {
- Sentry.captureException(err, { tags: { url } });
+ reportError(err, { url });
}
dispatch("Failed to fetch top accounts");
}
diff --git a/explorer/src/providers/supply.tsx b/explorer/src/providers/supply.tsx
index b456cac330..36e7361d89 100644
--- a/explorer/src/providers/supply.tsx
+++ b/explorer/src/providers/supply.tsx
@@ -1,8 +1,8 @@
import React from "react";
-import * as Sentry from "@sentry/react";
import { Supply, Connection } from "@solana/web3.js";
import { useCluster, ClusterStatus, Cluster } from "./cluster";
+import { reportError } from "utils/sentry";
export enum Status {
Idle,
@@ -53,7 +53,7 @@ async function fetch(dispatch: Dispatch, cluster: Cluster, url: string) {
});
} catch (err) {
if (cluster !== Cluster.Custom) {
- Sentry.captureException(err, { tags: { url } });
+ reportError(err, { url });
}
dispatch("Failed to fetch supply");
}
diff --git a/explorer/src/providers/transactions/details.tsx b/explorer/src/providers/transactions/details.tsx
index 5fc1e66f83..6e65970530 100644
--- a/explorer/src/providers/transactions/details.tsx
+++ b/explorer/src/providers/transactions/details.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import * as Sentry from "@sentry/react";
import {
Connection,
TransactionSignature,
@@ -8,6 +7,7 @@ import {
import { useCluster, Cluster } from "../cluster";
import * as Cache from "providers/cache";
import { ActionType, FetchStatus } from "providers/cache";
+import { reportError } from "utils/sentry";
export interface Details {
transaction?: ParsedConfirmedTransaction | null;
@@ -61,7 +61,7 @@ async function fetchDetails(
fetchStatus = FetchStatus.Fetched;
} catch (error) {
if (cluster !== Cluster.Custom) {
- Sentry.captureException(error, { tags: { url } });
+ reportError(error, { url });
}
fetchStatus = FetchStatus.FetchFailed;
}
diff --git a/explorer/src/providers/transactions/index.tsx b/explorer/src/providers/transactions/index.tsx
index 44975a5a4c..13bc8c3d80 100644
--- a/explorer/src/providers/transactions/index.tsx
+++ b/explorer/src/providers/transactions/index.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import * as Sentry from "@sentry/react";
import {
TransactionSignature,
Connection,
@@ -9,6 +8,7 @@ import { useCluster, Cluster } from "../cluster";
import { DetailsProvider } from "./details";
import * as Cache from "providers/cache";
import { ActionType, FetchStatus } from "providers/cache";
+import { reportError } from "utils/sentry";
export { useTransactionDetails } from "./details";
export type Confirmations = number | "max";
@@ -80,9 +80,7 @@ export async function fetchTransactionStatus(
blockTime = await connection.getBlockTime(value.slot);
} catch (error) {
if (cluster === Cluster.MainnetBeta) {
- Sentry.captureException(error, {
- tags: { slot: `${value.slot}` },
- });
+ reportError(error, { slot: `${value.slot}` });
}
}
let timestamp: Timestamp = blockTime !== null ? blockTime : "unavailable";
@@ -105,7 +103,7 @@ export async function fetchTransactionStatus(
fetchStatus = FetchStatus.Fetched;
} catch (error) {
if (cluster !== Cluster.Custom) {
- Sentry.captureException(error, { tags: { url } });
+ reportError(error, { url });
}
fetchStatus = FetchStatus.FetchFailed;
}
diff --git a/explorer/src/utils/sentry.ts b/explorer/src/utils/sentry.ts
new file mode 100644
index 0000000000..31c45bb054
--- /dev/null
+++ b/explorer/src/utils/sentry.ts
@@ -0,0 +1,18 @@
+import * as Sentry from "@sentry/react";
+
+type Tags =
+ | {
+ [key: string]: string;
+ }
+ | undefined;
+
+export function reportError(err: Error, tags: Tags) {
+ console.error(err);
+ try {
+ Sentry.captureException(err, {
+ tags,
+ });
+ } catch (err) {
+ // Sentry can fail if error rate limit is reached
+ }
+}