Skip to content

Commit

Permalink
Log errors using Sentry (solana-labs#655)
Browse files Browse the repository at this point in the history
* feat: log errors using Sentry

* chore: set VERCEL_ENV

* wip: try to remove env and fix the build

* dont use sentry when building on local machine

* turn off sentry if no auth token in vercel build

* fix auth token check

* fix

* fix: specify vercel env

Co-authored-by: Sebastian Bor <[email protected]>
Co-authored-by: Adrian Brzeziński <[email protected]>
  • Loading branch information
3 people authored May 5, 2022
1 parent 1259659 commit a949439
Show file tree
Hide file tree
Showing 13 changed files with 316 additions and 27 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ yarn-error.log*

# TypeScript cache
*.tsbuildinfo

# Sentry
.sentryclirc
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"cSpell.words": ["Addin", "blockworks", "lamports", "solana"]
"cSpell.words": ["Addin", "blockworks", "lamports", "solana", "VERCEL"]
}
56 changes: 38 additions & 18 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// workaround for ESM module loader errors
// see https://github.com/vercel/next.js/issues/25454
const { withSentryConfig } = require('@sentry/nextjs')
const withTM = require('next-transpile-modules')([
'react-markdown',
'@solana/wallet-adapter-base',
Expand All @@ -10,23 +11,42 @@ const withTM = require('next-transpile-modules')([
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
let config

module.exports = withBundleAnalyzer(
withTM({
webpack: (config, { isServer }) => {
config.experiments = { asyncWebAssembly: true, layers: true }
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack'],
})
if (!isServer) config.resolve.fallback.fs = false
return config
},
env: {
REALM: process.env.REALM,
MAINNET_RPC: process.env.MAINNET_RPC,
DEVNET_RPC: process.env.DEVNET_RPC,
DEFAULT_GOVERNANCE_PROGRAM_ID: process.env.DEFAULT_GOVERNANCE_PROGRAM_ID,
},
// STEP 1: Add transpiler.
config = withTM({
webpack: (config, { isServer }) => {
config.experiments = { asyncWebAssembly: true, layers: true }
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack'],
})
if (!isServer) config.resolve.fallback.fs = false
return config
},
env: {
REALM: process.env.REALM,
MAINNET_RPC: process.env.MAINNET_RPC,
DEVNET_RPC: process.env.DEVNET_RPC,
DEFAULT_GOVERNANCE_PROGRAM_ID: process.env.DEFAULT_GOVERNANCE_PROGRAM_ID,
},
})

// STEP 2: Enable bundle analyzer when `ANALYZE=true`.
config = withBundleAnalyzer(config)

if (process.env.SENTRY_AUTH_TOKEN) {
// STEP 3: Sentry error reporting. MUST COME LAST to work with sourcemaps.
config = withSentryConfig(config, {
// Additional config options for the Sentry Webpack plugin. Keep in mind that
// the following options are set automatically, and overriding them is not
// recommended:
// release, url, org, project, authToken, configFile, stripPrefix,
// urlPrefix, include, ignore
silent: true, // Suppresses all logs
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options.
})
)
}

module.exports = config
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@heroicons/react": "^1.0.1",
"@marinade.finance/marinade-ts-sdk": "^2.0.9",
"@metaplex-foundation/mpl-token-metadata": "^1.2.5",
"@mithraic-labs/serum-remote": "^0.0.1-rc.16",
"@next/bundle-analyzer": "^12.1.5",
"@mithraic-labs/serum-remote": "^0.0.1-rc.16",
"@nfteyez/sol-rayz": "^0.10.2",
Expand All @@ -42,8 +43,9 @@
"@notifi-network/notifi-react-hooks": "^0.12.1",
"@project-serum/anchor": "^0.24.2",
"@project-serum/common": "^0.0.1-beta.3",
"@project-serum/sol-wallet-adapter": "^0.2.6",
"@project-serum/serum": "^0.13.61",
"@project-serum/sol-wallet-adapter": "^0.2.6",
"@sentry/nextjs": "^6.19.7",
"@solana/governance-program-library": "^0.15.2",
"@solana/spl-governance": "^0.0.34",
"@solana/spl-token": "0.1.8",
Expand Down
65 changes: 65 additions & 0 deletions pages/_error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import NextErrorComponent from 'next/error'

import * as Sentry from '@sentry/nextjs'

const MyError = ({ statusCode, hasGetInitialPropsRun, err }) => {
if (!hasGetInitialPropsRun && err) {
// getInitialProps is not called in case of
// https://github.com/vercel/next.js/issues/8592. As a workaround, we pass
// err via _app.js so it can be captured
Sentry.captureException(err)
// Flushing is not required in this case as it only happens on the client
}

return <NextErrorComponent statusCode={statusCode} />
}

MyError.getInitialProps = async (context) => {
const errorInitialProps = await NextErrorComponent.getInitialProps(context)

const { res, err, asPath } = context

// Workaround for https://github.com/vercel/next.js/issues/8592, mark when
// getInitialProps has run
errorInitialProps.hasGetInitialPropsRun = true

// Returning early because we don't want to log 404 errors to Sentry.
if (res?.statusCode === 404) {
return errorInitialProps
}

// Running on the server, the response object (`res`) is available.
//
// Next.js will pass an err on the server if a page's data fetching methods
// threw or returned a Promise that rejected
//
// Running on the client (browser), Next.js will provide an err if:
//
// - a page's `getInitialProps` threw or returned a Promise that rejected
// - an exception was thrown somewhere in the React lifecycle (render,
// componentDidMount, etc) that was caught by Next.js's React Error
// Boundary. Read more about what types of exceptions are caught by Error
// Boundaries: https://reactjs.org/docs/error-boundaries.html

if (err) {
Sentry.captureException(err)

// Flushing before returning is necessary if deploying to Vercel, see
// https://vercel.com/docs/platform/limits#streaming-responses
await Sentry.flush(2000)

return errorInitialProps
}

// If this point is reached, getInitialProps was called without any
// information about what the error might be. This is unexpected and may
// indicate a bug introduced in Next.js, so record it in Sentry
Sentry.captureException(
new Error(`_error.js getInitialProps missing data at path: ${asPath}`)
)
await Sentry.flush(2000)

return errorInitialProps
}

export default MyError
3 changes: 2 additions & 1 deletion pages/api/daoStatistics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { getAllSplGovernanceProgramIds } from './tools/realms'
import BigNumber from 'bignumber.js'
import BN from 'bn.js'
import { WSOL_MINT_PK } from '@components/instructions/tools'
import { withSentry } from '@sentry/nextjs'

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const conn = new Connection(
Expand Down Expand Up @@ -143,4 +144,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).json(daoStatistics)
}

export default handler
export default withSentry(handler)
3 changes: 2 additions & 1 deletion pages/api/daoVoteStatistics.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import {
getGovernanceAccounts,
ProgramAccount,
Expand Down Expand Up @@ -79,4 +80,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).json(daoStatistics)
}

export default handler
export default withSentry(handler)
3 changes: 2 additions & 1 deletion pages/api/hello.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction

import { withSentry } from '@sentry/nextjs'
import { NextApiRequest, NextApiResponse } from 'next'

const handler = (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).json({ name: 'John Doe' })
}

export default handler
export default withSentry(handler)
3 changes: 2 additions & 1 deletion pages/api/splGovernancePrograms.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { withSentry } from '@sentry/nextjs'
import { NextApiRequest, NextApiResponse } from 'next'
import { getAllSplGovernanceProgramIds } from './tools/realms'

Expand All @@ -6,4 +7,4 @@ const handler = (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).json(getAllSplGovernanceProgramIds())
}

export default handler
export default withSentry(handler)
21 changes: 21 additions & 0 deletions sentry.client.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// This file configures the initialization of Sentry on the browser.
// The config you add here will be used whenever a page is visited.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

import * as Sentry from '@sentry/nextjs'

const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN
const SENTRY_ENVIRONMENT = process.env.VERCEL_ENV

Sentry.init({
dsn:
SENTRY_DSN ||
'https://[email protected]/6380292',
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1.0,
environment: SENTRY_ENVIRONMENT,
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps
})
4 changes: 4 additions & 0 deletions sentry.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defaults.url=https://sentry.io/
defaults.org=solana
defaults.project=realms
cli.executable=../../../.npm/_npx/a8388072043b4cbc/node_modules/@sentry/cli/bin/sentry-cli
21 changes: 21 additions & 0 deletions sentry.server.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// This file configures the initialization of Sentry on the server.
// The config you add here will be used whenever the server handles a request.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

import * as Sentry from '@sentry/nextjs'

const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN
const SENTRY_ENVIRONMENT = process.env.VERCEL_ENV

Sentry.init({
dsn:
SENTRY_DSN ||
'https://[email protected]/6380292',
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1.0,
environment: SENTRY_ENVIRONMENT,
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps
})
Loading

0 comments on commit a949439

Please sign in to comment.