Fix remaining OTEL issues in adapter (#94817)

**View diff without whitespace**

1. RSC requests weren't properly handled
2. The mismatch on getServerSideProps is actually fine (depends on
whatever invokes the handler)
This commit is contained in:
Niklas Mischkulnig
2026-06-16 18:37:55 +02:00
committed by GitHub
parent b08fb8d922
commit 40296fe53f
2 changed files with 140 additions and 128 deletions
+11 -3
View File
@@ -222,6 +222,12 @@ export async function handler(
}
const isMinimalMode = Boolean(getRequestMeta(req, 'minimalMode'))
// Capture the request target before `prepare()` runs, since route
// normalization (e.g. `normalizeCdnUrl`) rewrites `req.url` and would
// otherwise change the `http.target` span attribute. This mirrors
// `BaseServer.handleRequest`, which records the target before normalization.
const httpTarget = req.url
const multiZoneDraftMode = process.env
.__NEXT_MULTI_ZONE_DRAFT_MODE as any as boolean
@@ -722,7 +728,7 @@ export async function handler(
span.setAttributes({
'http.status_code': res.statusCode,
'next.rsc': false,
'next.rsc': isRSCRequest,
})
if (res.statusCode && res.statusCode >= 500) {
@@ -754,7 +760,9 @@ export async function handler(
}
const route = rootSpanAttributes.get('next.route') || normalizedSrcPage
const name = `${method} ${route}`
const name = isRSCRequest
? `RSC ${method} ${route}`
: `${method} ${route}`
span.setAttributes({
'next.route': route,
@@ -2009,7 +2017,7 @@ export async function handler(
kind: SpanKind.SERVER,
attributes: {
'http.method': method,
'http.target': req.url,
'http.target': httpTarget,
},
},
handleResponse
@@ -69,7 +69,6 @@ describe.each(
// Edge runtime is currently not implemented in custom-entrypoint-server.ts
const itEdge = useDirectEntrypointHandler ? it.skip : it
const itNoDirect = useDirectEntrypointHandler ? it.skip : it
for (const env of [
{
@@ -371,8 +370,7 @@ describe.each(
)
})
// TODO why is this failing
itNoDirect('should handle RSC with fetch in RSC mode', async () => {
it('should handle RSC with fetch in RSC mode', async () => {
await next.fetch(`/app/param/rsc-fetch?${NEXT_RSC_UNION_QUERY}`, {
...env.fetchInit,
headers: {
@@ -1033,131 +1031,137 @@ describe.each(
)
})
// TODO why is this failing
itNoDirect(
'should handle getServerSideProps exceptions',
async () => {
await next.fetch(
'/pages/param/getServerSidePropsError',
env.fetchInit
)
it('should handle getServerSideProps exceptions', async () => {
await next.fetch(
'/pages/param/getServerSidePropsError',
env.fetchInit
)
await expectTrace(getCollector(), [
{
name: 'GET /pages/[param]/getServerSidePropsError',
attributes: {
'http.method': 'GET',
'http.route': '/pages/[param]/getServerSidePropsError',
'http.status_code': 500,
'http.target': '/pages/param/getServerSidePropsError',
'next.route': '/pages/[param]/getServerSidePropsError',
'next.span_name':
'GET /pages/[param]/getServerSidePropsError',
'next.span_type': 'BaseServer.handleRequest',
'error.type': '500',
},
kind: 1,
status: { code: 2 },
traceId: env.span.traceId,
parentId: env.span.rootParentId,
spans: [
{
name: 'getServerSideProps /pages/[param]/getServerSidePropsError',
attributes: {
'next.route': '/pages/[param]/getServerSidePropsError',
'next.span_name':
'getServerSideProps /pages/[param]/getServerSidePropsError',
'next.span_type': 'Render.getServerSideProps',
await expectTrace(getCollector(), [
{
name: 'GET /pages/[param]/getServerSidePropsError',
attributes: {
'http.method': 'GET',
'http.route': '/pages/[param]/getServerSidePropsError',
'http.target': '/pages/param/getServerSidePropsError',
'next.route': '/pages/[param]/getServerSidePropsError',
'next.span_name':
'GET /pages/[param]/getServerSidePropsError',
'next.span_type': 'BaseServer.handleRequest',
...(useDirectEntrypointHandler
? {
// With direct entrypoints, this 500 error has to be handled by whatever is
// invoking the handler. And that same invoker is then also responsible for
// setting OTEL correctly.
'error.type': 'Error',
},
kind: 0,
status: {
code: 2,
message: 'ServerSideProps error',
},
events: [
{
name: 'exception',
attributes: {
'exception.type': 'Error',
'exception.message': 'ServerSideProps error',
},
},
],
},
...(useDirectEntrypointHandler
? []
: [
{
name: 'render route (pages) /_error',
attributes: {
'next.route': '/_error',
'next.span_name': 'render route (pages) /_error',
'next.span_type': 'Render.renderDocument',
},
kind: 0,
status: { code: 0 },
},
{
name: 'resolve page components',
attributes: {
'next.route': '/_error',
'next.span_name': 'resolve page components',
'next.span_type':
'NextNodeServer.findPageComponents',
},
kind: 0,
status: { code: 0 },
},
]),
...(isNextDev || useDirectEntrypointHandler
? []
: [
{
name: 'resolve page components',
attributes: {
'next.route': '/500',
'next.span_name': 'resolve page components',
'next.span_type':
'NextNodeServer.findPageComponents',
},
kind: 0,
status: { code: 0 },
},
{
name: 'resolve page components',
attributes: {
'next.route': '/500',
'next.span_name': 'resolve page components',
'next.span_type':
'NextNodeServer.findPageComponents',
},
kind: 0,
status: { code: 0 },
},
]),
...(useDirectEntrypointHandler
? []
: [
{
name: 'resolve page components',
attributes: {
'next.route':
'/pages/[param]/getServerSidePropsError',
'next.span_name': 'resolve page components',
'next.span_type':
'NextNodeServer.findPageComponents',
},
kind: 0,
status: { code: 0 },
},
]),
],
'http.status_code': 200,
}
: {
'error.type': '500',
'http.status_code': 500,
}),
},
])
}
)
kind: 1,
status: { code: 2 },
traceId: env.span.traceId,
parentId: env.span.rootParentId,
spans: [
{
name: 'getServerSideProps /pages/[param]/getServerSidePropsError',
attributes: {
'next.route': '/pages/[param]/getServerSidePropsError',
'next.span_name':
'getServerSideProps /pages/[param]/getServerSidePropsError',
'next.span_type': 'Render.getServerSideProps',
'error.type': 'Error',
},
kind: 0,
status: {
code: 2,
message: 'ServerSideProps error',
},
events: [
{
name: 'exception',
attributes: {
'exception.type': 'Error',
'exception.message': 'ServerSideProps error',
},
},
],
},
...(useDirectEntrypointHandler
? []
: [
{
name: 'render route (pages) /_error',
attributes: {
'next.route': '/_error',
'next.span_name': 'render route (pages) /_error',
'next.span_type': 'Render.renderDocument',
},
kind: 0,
status: { code: 0 },
},
{
name: 'resolve page components',
attributes: {
'next.route': '/_error',
'next.span_name': 'resolve page components',
'next.span_type':
'NextNodeServer.findPageComponents',
},
kind: 0,
status: { code: 0 },
},
]),
...(isNextDev || useDirectEntrypointHandler
? []
: [
{
name: 'resolve page components',
attributes: {
'next.route': '/500',
'next.span_name': 'resolve page components',
'next.span_type':
'NextNodeServer.findPageComponents',
},
kind: 0,
status: { code: 0 },
},
{
name: 'resolve page components',
attributes: {
'next.route': '/500',
'next.span_name': 'resolve page components',
'next.span_type':
'NextNodeServer.findPageComponents',
},
kind: 0,
status: { code: 0 },
},
]),
...(useDirectEntrypointHandler
? []
: [
{
name: 'resolve page components',
attributes: {
'next.route':
'/pages/[param]/getServerSidePropsError',
'next.span_name': 'resolve page components',
'next.span_type':
'NextNodeServer.findPageComponents',
},
kind: 0,
status: { code: 0 },
},
]),
],
},
])
})
it('should handle getServerSideProps returning notFound', async () => {
await next.fetch(