-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(nextjs): Use OpenTelemetry for performance monitoring and tracing #11016
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
Changes from all commits
3b5d9ce
c5146f3
5d1e52a
93bf4f9
e3ead78
6a5e564
cf5fe92
15ffe0f
d4b0e65
0973ee0
e4aecd0
201d459
c4c37fd
55c3bc7
c16a2d9
d11620e
7e7824c
728c086
b61b646
684dd65
dc0fe4f
d39e169
57c7026
8ae8d8d
ac79853
f297b78
3aaeb06
785f36d
caa9fb0
ba3f500
4e6097c
47f3b1b
65f3e73
348a656
0eb8af0
c6977a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,8 @@ | ||
// 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/ | ||
|
||
const { withSentryConfig } = require('@sentry/nextjs'); | ||
|
||
/** @type {import('next').NextConfig} */ | ||
const moduleExports = {}; | ||
|
||
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 | ||
|
||
silent: true, // Suppresses all logs | ||
// For all available options, see: | ||
// https://github.com/getsentry/sentry-webpack-plugin#options. | ||
|
||
// We're not testing source map uploads at the moment. | ||
dryRun: true, | ||
}; | ||
const nextConfig = {}; | ||
|
||
// 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, { | ||
hideSourceMaps: true, | ||
module.exports = withSentryConfig(nextConfig, { | ||
silent: true, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,7 @@ test('Should send a transaction with a fetch span', async ({ page }) => { | |
data: expect.objectContaining({ | ||
'http.method': 'GET', | ||
'sentry.op': 'http.client', | ||
'sentry.origin': 'auto.http.node.undici', | ||
'next.span_type': 'AppRender.fetch', // This span is created by Next.js own fetch instrumentation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. l: We could think about adding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have started a broader discussion around this topic last week because we need a generic decision in all SDKs for this. The important question being: "What sentry.origin do we give spans that are not generated through Sentry SDK API?" Right now it is manual - which is obv wrong. I'd argue we don't set anything, because sentry.origin doesn't make sense anymore. |
||
}), | ||
description: 'GET http://example.com/', | ||
}), | ||
|
@@ -24,7 +24,7 @@ test('Should send a transaction with a fetch span', async ({ page }) => { | |
data: expect.objectContaining({ | ||
'http.method': 'GET', | ||
'sentry.op': 'http.client', | ||
'sentry.origin': 'auto.http.node.http', | ||
'sentry.origin': 'auto.http.otel.http', | ||
}), | ||
description: 'GET http://example.com/', | ||
}), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,13 @@ | ||
// 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/ | ||
|
||
const { withSentryConfig } = require('@sentry/nextjs'); | ||
|
||
const moduleExports = { | ||
/** @type {import('next').NextConfig} */ | ||
const nextConfig = { | ||
experimental: { | ||
appDir: true, | ||
serverActions: true, | ||
}, | ||
}; | ||
|
||
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 | ||
|
||
silent: true, // Suppresses all logs | ||
// For all available options, see: | ||
// https://github.com/getsentry/sentry-webpack-plugin#options. | ||
|
||
// We're not testing source map uploads at the moment. | ||
dryRun: true, | ||
}; | ||
|
||
// 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, { | ||
hideSourceMaps: true, | ||
module.exports = withSentryConfig(nextConfig, { | ||
silent: true, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
"version": "0.1.0", | ||
"private": true, | ||
"scripts": { | ||
"build": "next build > .tmp_build_stdout 2> .tmp_build_stderr", | ||
"build": "next build > .tmp_build_stdout 2> .tmp_build_stderr || (cat .tmp_build_stdout && cat .tmp_build_stderr && exit 1)", | ||
"clean": "npx rimraf node_modules,pnpm-lock.yaml", | ||
"test:prod": "TEST_ENV=production playwright test", | ||
"test:dev": "TEST_ENV=development playwright test", | ||
|
@@ -29,8 +29,19 @@ | |
"@playwright/test": "^1.27.1" | ||
}, | ||
"devDependencies": { | ||
"@sentry-internal/feedback": "latest || *", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need all of these? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as #11016 (comment) |
||
"@sentry-internal/replay-canvas": "latest || *", | ||
"@sentry-internal/tracing": "latest || *", | ||
"@sentry/browser": "latest || *", | ||
"@sentry/core": "latest || *", | ||
"@sentry/nextjs": "latest || *", | ||
"@sentry/node": "latest || *", | ||
"@sentry/opentelemetry": "latest || *", | ||
"@sentry/react": "latest || *", | ||
"@sentry-internal/replay": "latest || *", | ||
"@sentry/types": "latest || *", | ||
"@sentry/utils": "latest || *" | ||
"@sentry/utils": "latest || *", | ||
"@sentry/vercel-edge": "latest || *" | ||
}, | ||
"volta": { | ||
"extends": "../../package.json" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { get } from 'http'; | ||
import { NextApiRequest, NextApiResponse } from 'next'; | ||
|
||
export default (_req: NextApiRequest, res: NextApiResponse) => { | ||
// make an outgoing request in order to test that the `Http` integration creates a span | ||
get('http://example.com/', message => { | ||
message.on('data', () => { | ||
// Noop consuming some data so that request can close :) | ||
}); | ||
|
||
message.on('end', () => { | ||
setTimeout(() => { | ||
res.status(200).json({ message: 'Hello from Next.js!' }); | ||
}, 500); | ||
}); | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { expect, test } from '@playwright/test'; | ||
import { waitForTransaction } from '../event-proxy-server'; | ||
|
||
// Note(lforst): I officially declare bancruptcy on this test. I tried a million ways to make it work but it kept flaking. | ||
// Sometimes the request span was included in the handler span, more often it wasn't. I have no idea why. Maybe one day we will | ||
// figure it out. Today is not that day. | ||
test.skip('Should send a transaction with a http span', async ({ request }) => { | ||
const transactionPromise = waitForTransaction('nextjs-13-app-dir', async transactionEvent => { | ||
return transactionEvent?.transaction === 'GET /api/request-instrumentation'; | ||
}); | ||
|
||
await request.get('/api/request-instrumentation'); | ||
|
||
expect((await transactionPromise).spans).toContainEqual( | ||
expect.objectContaining({ | ||
data: expect.objectContaining({ | ||
'http.method': 'GET', | ||
'sentry.op': 'http.client', | ||
'sentry.origin': 'auto.http.otel.http', | ||
}), | ||
description: 'GET http://example.com/', | ||
}), | ||
); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need all of these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, at least I couldn't be bothered to filter them out. These are all deps that nextjs depends on or could ever depend on.