Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update example with-sentry #24819

Merged
merged 7 commits into from
May 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions examples/with-sentry/.env.local.example

This file was deleted.

73 changes: 13 additions & 60 deletions examples/with-sentry/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
# Sentry

This is an example showing how to use [Sentry](https://sentry.io) to catch & report errors on both client + server side.
This is an example showing how to use [Sentry](https://sentry.io) to catch & report errors on both client + server side, using the [official Sentry SDK for Next.js](https://docs.sentry.io/platforms/javascript/guides/nextjs/).

- `_app.js` renders on both the server and client. It initializes Sentry to catch any unhandled exceptions
- `_app.js` renders on both the server and client
- `_error.js` is rendered by Next.js while handling certain types of exceptions for you. It is overridden so those exceptions can be passed along to Sentry
- Each API route also initializes Sentry, so it can work independently in the "serverless" build config
- `next.config.js` enables source maps in production, uploads them to a new Sentry release, and swaps out `@sentry/node` for `@sentry/browser` when building the client bundle
- Each API route is handled with `withSentry`
- `next.config.js` automatically configures the app to use Sentry through `withSentry`

## Deploy your own

Once you have access to your [Sentry DSN](#step-1-enable-error-tracking), deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
Once you have access to your [Sentry DSN](https://docs.sentry.io/product/sentry-basics/dsn-explainer/#where-to-find-your-dsn), deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-sentry&project-name=with-sentry&repository-name=with-sentry&env=NEXT_PUBLIC_SENTRY_DSN&envDescription=DSN%20Key%20required%20by%20Sentry&envLink=https://github.com/vercel/next.js/tree/canary/examples/with-sentry%23step-1-enable-error-tracking)

Check out [Sentry’s Vercel Integration](#sentry-integration).

## How To Use

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
Expand All @@ -25,61 +27,8 @@ yarn create next-app --example with-sentry with-sentry-app

## Configuration

### Step 1. Enable error tracking

Copy the `.env.local.example` file in this directory to `.env.local` (which will be ignored by Git):

```bash
cp .env.local.example .env.local
```

Next, Copy your Sentry DSN. You can get it from the settings of your project in **Client Keys (DSN)**. Then, copy the string labeled **DSN** and set it as the value for `NEXT_PUBLIC_SENTRY_DSN` inside `.env.local`

> **Note:** Error tracking is disabled in development mode using the `NODE_ENV` environment variable. To change this behavior, remove the `enabled` property from the `Sentry.init()` call inside your `utils/sentry.js` file.

### Step 2. Run Next.js in development mode

```bash
npm install
npm run dev

# or

yarn install
yarn dev
```

Your app should be up and running on [http://localhost:3000](http://localhost:3000)! If it doesn't work, post on [GitHub discussions](https://github.com/vercel/next.js/discussions).

### Step 3. Automatic sourcemap upload (optional)

#### Using Vercel

You will need to install and configure the [Sentry Vercel integration](https://docs.sentry.io/workflow/integrations/vercel). After you've completed the project linking step, all the needed environment variables will be set in your Vercel project, with the exception of `NEXT_PUBLIC_SENTRY_SERVER_ROOT_DIR`, which should be set to `/var/task/`.

> **Note:** A Vercel project connected to a [Git integration](https://vercel.com/docs/platform/deployments#git) is required before adding the Sentry integration.

#### Without Using Vercel

1. Set up the `NEXT_PUBLIC_SENTRY_DSN` environment variable as described above.
2. Save your Sentry organization slug as the `SENTRY_ORG` environment variable and your project slug as the `SENTRY_PROJECT` environment variable in `.env.local`.
3. Save your git provider's commit SHA as `VERCEL_GIT_COMMIT_SHA` environment variable in `.env.local`.
4. Create an auth token in Sentry. The recommended way to do this is by creating a new internal integration for your organization. To do so, go into **Settings > Developer Settings > New internal integration**. After the integration is created, copy the Token.
5. Save the token inside the `SENTRY_AUTH_TOKEN` environment variable in `.env.local`.
6. Set `NEXT_PUBLIC_SENTRY_SERVER_ROOT_DIR` to the absolute path of the folder the Next.js app is running from

> **Note:** Sourcemap upload is disabled in development mode using the `NODE_ENV` environment variable. To change this behavior, remove the `NODE_ENV === 'production'` check from your `next.config.js` file.

## Other configuration options

More configurations are available for the [Sentry webpack plugin](https://github.com/getsentry/sentry-webpack-plugin) using [Sentry Configuration variables](https://docs.sentry.io/cli/configuration/) for defining the releases/verbosity/etc.

## Notes

- By default, neither sourcemaps nor error tracking are enabled in development mode (see Configuration).
- When enabled in development mode, error handling [works differently than in production](https://nextjs.org/docs/advanced-features/custom-error-page#customizing-the-error-page) as `_error.js` is never actually called.
- The build output will contain warning about unhandled Promise rejections. This is caused by the test pages, and is expected. When deploying to Vercel, "Client Error 1" will actually be sent to Sentry during the build, while that test page is being statically rendered.
- By default, source maps are uploaded to [sentry.io](https://sentry.io). If you're self-hosting Sentry, add `SENTRY_URL` to `.env` or `.env.locale` and set it to the base domain of your installation, which by default is `https://sentry.io/`.
You can [configure your app automatically](https://docs.sentry.io/platforms/javascript/guides/nextjs/#configure) or do the [manual setup](https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/).
Both ways lead to having your custom config files (`next.config.js`, `sentry.client.config.js`, `sentry.server.config.js`, and `sentry.properties`); so you can delete them from the example, they are here to illustrate how an example app looks like.

## Deploy on Vercel

Expand All @@ -96,3 +45,7 @@ To deploy your local project to Vercel, push it to GitHub/GitLab/Bitbucket and [
Alternatively, you can deploy using our template by clicking on the Deploy button below.

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-sentry&project-name=with-sentry&repository-name=with-sentry&env=NEXT_PUBLIC_SENTRY_DSN&envDescription=DSN%20Key%20required%20by%20Sentry&envLink=https://github.com/vercel/next.js/tree/canary/examples/with-sentry%23step-1-enable-error-tracking)

## Sentry Integration

Sentry’s Vercel Integration connects your Sentry and Vercel projects to automatically upload source maps and notify Sentry of release deployment. Learn more about this integration in [Sentry’s full documentation](https://docs.sentry.io/product/integrations/vercel/).
94 changes: 20 additions & 74 deletions examples/with-sentry/next.config.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,24 @@
// Use the SentryWebpack plugin to upload the source maps during build step
const SentryWebpackPlugin = require('@sentry/webpack-plugin')
const {
NEXT_PUBLIC_SENTRY_DSN: SENTRY_DSN,
SENTRY_ORG,
SENTRY_PROJECT,
SENTRY_AUTH_TOKEN,
NODE_ENV,
VERCEL_GIT_COMMIT_SHA,
} = process.env
// This file sets a custom webpack configuration to use your Next.js app
// with Sentry.
// https://nextjs.org/docs/api-reference/next.config.js/introduction
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

process.env.SENTRY_DSN = SENTRY_DSN
const basePath = ''
const { withSentryConfig } = require('@sentry/nextjs')

module.exports = {
productionBrowserSourceMaps: true,
env: {
// Make the COMMIT_SHA available to the client so that Sentry events can be
// marked for the release they belong to. It may be undefined if running
// outside of Vercel
NEXT_PUBLIC_COMMIT_SHA: VERCEL_GIT_COMMIT_SHA,
},
webpack: (config, options) => {
// In `pages/_app.js`, Sentry is imported from @sentry/browser. While
// @sentry/node will run in a Node.js environment. @sentry/node will use
// Node.js-only APIs to catch even more unhandled exceptions.
//
// This works well when Next.js is SSRing your page on a server with
// Node.js, but it is not what we want when your client-side bundle is being
// executed by a browser.
//
// Luckily, Next.js will call this webpack function twice, once for the
// server and once for the client. Read more:
// https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config
//
// So ask Webpack to replace @sentry/node imports with @sentry/browser when
// building the browser's bundle
if (!options.isServer) {
config.resolve.alias['@sentry/node'] = '@sentry/browser'
}

// Define an environment variable so source code can check whether or not
// it's running on the server so we can correctly initialize Sentry
config.plugins.push(
new options.webpack.DefinePlugin({
'process.env.NEXT_IS_SERVER': JSON.stringify(
options.isServer.toString()
),
})
)
const moduleExports = {
// Your existing module.exports
}

// When all the Sentry configuration env variables are available/configured
// The Sentry webpack plugin gets pushed to the webpack plugins to build
// and upload the source maps to sentry.
// This is an alternative to manually uploading the source maps
// Note: This is disabled in development mode.
if (
SENTRY_DSN &&
SENTRY_ORG &&
SENTRY_PROJECT &&
SENTRY_AUTH_TOKEN &&
VERCEL_GIT_COMMIT_SHA &&
NODE_ENV === 'production'
) {
config.plugins.push(
new SentryWebpackPlugin({
include: '.next',
ignore: ['node_modules'],
stripPrefix: ['webpack://_N_E/'],
urlPrefix: `~${basePath}/_next`,
release: VERCEL_GIT_COMMIT_SHA,
})
)
}
return config
},
basePath,
const SentryWebpackPluginOptions = {
// 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
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options.
}

// Make sure adding Sentry options is the last code to run before exporting, to
// ensure that your source maps include changes from all other Webpack plugins
module.exports = withSentryConfig(moduleExports, SentryWebpackPluginOptions)
5 changes: 1 addition & 4 deletions examples/with-sentry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
"start": "next start"
},
"dependencies": {
"@sentry/browser": "^5.21.3",
"@sentry/integrations": "^5.21.3",
"@sentry/node": "^5.21.3",
"@sentry/webpack-plugin": "^1.12.1",
"@sentry/nextjs": "^6.3.5",
"next": "latest",
"react": "^16.8.6",
"react-dom": "^16.8.6"
Expand Down
4 changes: 0 additions & 4 deletions examples/with-sentry/pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import { init } from '../utils/sentry'

init()

export default function App({ Component, pageProps, err }) {
// Workaround for https://github.com/vercel/next.js/issues/8592
return <Component {...pageProps} err={err} />
Expand Down
3 changes: 2 additions & 1 deletion examples/with-sentry/pages/_error.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import NextErrorComponent from 'next/error'
import * as Sentry from '@sentry/node'

import * as Sentry from '@sentry/nextjs'

const MyError = ({ statusCode, hasGetInitialPropsRun, err }) => {
if (!hasGetInitialPropsRun && err) {
Expand Down
8 changes: 4 additions & 4 deletions examples/with-sentry/pages/api/test1.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { init } from '../../utils/sentry'

init()
import { withSentry } from '@sentry/nextjs'

const doAsyncWork = () => Promise.reject(new Error('API Test 1'))
doAsyncWork()

export default async function handler(req, res) {
async function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}

export default withSentry(handler)
8 changes: 4 additions & 4 deletions examples/with-sentry/pages/api/test2.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { init } from '../../utils/sentry'

init()
import { withSentry } from '@sentry/nextjs'

function work() {
throw new Error('API Test 2')
}

work()

export default async function handler(req, res) {
async function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}

export default withSentry(handler)
8 changes: 4 additions & 4 deletions examples/with-sentry/pages/api/test3.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { init } from '../../utils/sentry'

init()
import { withSentry } from '@sentry/nextjs'

function work() {
throw new Error('API Test 3')
}

export default async function handler(req, res) {
async function handler(req, res) {
work()

res.status(200).json({ name: 'John Doe' })
}

export default withSentry(handler)
10 changes: 4 additions & 6 deletions examples/with-sentry/pages/api/test4.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import * as Sentry from '@sentry/node'
import * as Sentry from '@sentry/nextjs'

import { init } from '../../utils/sentry'

init()

export default async function handler(req, res) {
async function handler(req, res) {
try {
throw new Error('API Test 4')
} catch (error) {
Expand All @@ -16,3 +12,5 @@ export default async function handler(req, res) {
await Sentry.flush(2000)
res.status(200).json({ name: 'John Doe' })
}

export default Sentry.withSentry(handler)
2 changes: 1 addition & 1 deletion examples/with-sentry/pages/ssr/test4.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as Sentry from '@sentry/node'
import * as Sentry from '@sentry/nextjs'

const Test4 = () => <h1>SSR Test 4</h1>

Expand Down
14 changes: 14 additions & 0 deletions examples/with-sentry/sentry.client.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This file configures the intialization 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

Sentry.init({
dsn: SENTRY_DSN,
// 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
})
5 changes: 5 additions & 0 deletions examples/with-sentry/sentry.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
defaults.url=# your base url
defaults.org=# your org
defaults.project=# your project
auth.token=# your auth token
cli.executable=# [optional] path to the cli executable
14 changes: 14 additions & 0 deletions examples/with-sentry/sentry.server.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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

Sentry.init({
dsn: SENTRY_DSN,
// 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
})
35 changes: 0 additions & 35 deletions examples/with-sentry/utils/sentry.js

This file was deleted.