Hide internal fetches OTel traces in dev mode and assert duplicate OTel spans are present only in dev mode (#47822)
This commit is contained in:
parent
da37c018f3
commit
aeec6b5d0f
11 changed files with 230 additions and 253 deletions
|
@ -529,6 +529,7 @@ export async function apiResolver(
|
|||
res.once('pipe', () => (wasPiped = true))
|
||||
}
|
||||
|
||||
getTracer().getRootSpanAttributes()?.set('next.route', page)
|
||||
// Call API route method
|
||||
const apiRouteResult = await getTracer().trace(
|
||||
NodeSpan.runHandler,
|
||||
|
|
|
@ -1226,6 +1226,7 @@ export async function renderToHTMLOrFlight(
|
|||
)
|
||||
}
|
||||
|
||||
getTracer().getRootSpanAttributes()?.set('next.route', pathname)
|
||||
const bodyResult = getTracer().wrap(
|
||||
AppRenderSpan.getBodyResult,
|
||||
{
|
||||
|
|
|
@ -543,6 +543,8 @@ export default abstract class Server<ServerOptions extends Options = Options> {
|
|||
'http.method': method,
|
||||
'http.target': req.url,
|
||||
},
|
||||
// We will fire this from the renderer worker
|
||||
hideSpan: this.serverOptions.dev && this.isRouterWorker,
|
||||
},
|
||||
async (span) =>
|
||||
this.handleRequestImpl(req, res, parsedUrl).finally(() => {
|
||||
|
@ -568,11 +570,13 @@ export default abstract class Server<ServerOptions extends Options = Options> {
|
|||
|
||||
const route = rootSpanAttributes.get('next.route')
|
||||
if (route) {
|
||||
const newName = `${method} ${route}`
|
||||
span.setAttributes({
|
||||
'next.route': route,
|
||||
'http.route': route,
|
||||
'next.span_name': newName,
|
||||
})
|
||||
span.updateName(`${method} ${route}`)
|
||||
span.updateName(newName)
|
||||
}
|
||||
})
|
||||
)
|
||||
|
|
|
@ -136,7 +136,7 @@ export default class DevServer extends Server {
|
|||
private edgeFunctions?: RoutingItem[]
|
||||
private verifyingTypeScript?: boolean
|
||||
private usingTypeScript?: boolean
|
||||
private originalFetch?: typeof fetch
|
||||
private originalFetch: typeof fetch
|
||||
private staticPathsCache: LRUCache<
|
||||
string,
|
||||
UnwrapPromise<ReturnType<DevServer['getStaticPaths']>>
|
||||
|
@ -187,7 +187,7 @@ export default class DevServer extends Server {
|
|||
Error.stackTraceLimit = 50
|
||||
} catch {}
|
||||
super({ ...options, dev: true })
|
||||
this.persistPatchedGlobals()
|
||||
this.originalFetch = global.fetch
|
||||
this.renderOpts.dev = true
|
||||
this.renderOpts.appDirDevErrorLogger = (err: any) =>
|
||||
this.logErrorWithOriginalStack(err, 'app-dir')
|
||||
|
@ -1257,7 +1257,7 @@ export default class DevServer extends Server {
|
|||
private async invokeIpcMethod(method: string, args: any[]): Promise<any> {
|
||||
const ipcPort = process.env.__NEXT_PRIVATE_ROUTER_IPC_PORT
|
||||
if (ipcPort) {
|
||||
const res = await fetch(
|
||||
const res = await this.originalFetch(
|
||||
`http://${this.hostname}:${ipcPort}?method=${
|
||||
method as string
|
||||
}&args=${encodeURIComponent(JSON.stringify(args))}`
|
||||
|
@ -1703,12 +1703,8 @@ export default class DevServer extends Server {
|
|||
return nextInvoke as NonNullable<typeof result>
|
||||
}
|
||||
|
||||
private persistPatchedGlobals(): void {
|
||||
this.originalFetch = global.fetch
|
||||
}
|
||||
|
||||
private restorePatchedGlobals(): void {
|
||||
global.fetch = this.originalFetch!
|
||||
global.fetch = this.originalFetch
|
||||
}
|
||||
|
||||
protected async ensurePage(opts: {
|
||||
|
|
|
@ -320,13 +320,13 @@ export class AppRouteRouteModule extends RouteModule<
|
|||
}
|
||||
)
|
||||
|
||||
const route = getPathnameFromAbsolutePath(this.resolvedPagePath)
|
||||
getTracer().getRootSpanAttributes()?.set('next.route', route)
|
||||
return getTracer().trace(
|
||||
AppRouteRouteHandlersSpan.runHandler,
|
||||
{
|
||||
// TODO: propagate this pathname from route matcher
|
||||
spanName: `executing api route (app) ${getPathnameFromAbsolutePath(
|
||||
this.resolvedPagePath
|
||||
)}`,
|
||||
spanName: `executing api route (app) ${route}`,
|
||||
},
|
||||
() =>
|
||||
handler(wrappedRequest, {
|
||||
|
|
|
@ -41,6 +41,7 @@ type TracerSpanOptions = Omit<SpanOptions, 'attributes'> & {
|
|||
parentSpan?: Span
|
||||
spanName?: string
|
||||
attributes?: Partial<Record<AttributeNames, AttributeValue | undefined>>
|
||||
hideSpan?: boolean
|
||||
}
|
||||
|
||||
interface NextTracer {
|
||||
|
@ -201,8 +202,9 @@ class NextTracerImpl implements NextTracer {
|
|||
}
|
||||
|
||||
if (
|
||||
!NextVanillaSpanAllowlist.includes(type) &&
|
||||
process.env.NEXT_OTEL_VERBOSE !== '1'
|
||||
(!NextVanillaSpanAllowlist.includes(type) &&
|
||||
process.env.NEXT_OTEL_VERBOSE !== '1') ||
|
||||
options.hideSpan
|
||||
) {
|
||||
return fn()
|
||||
}
|
||||
|
|
|
@ -1054,13 +1054,18 @@ export default class NextNodeServer extends BaseServer {
|
|||
params: Params | null
|
||||
isAppPath: boolean
|
||||
}): Promise<FindComponentsResult | null> {
|
||||
getTracer().getRootSpanAttributes()?.set('next.route', pathname)
|
||||
let route = pathname
|
||||
if (isAppPath) {
|
||||
// When in App we get page instead of route
|
||||
route = pathname.replace(/\/[^/]*$/, '')
|
||||
}
|
||||
|
||||
return getTracer().trace(
|
||||
NextNodeServerSpan.findPageComponents,
|
||||
{
|
||||
spanName: `resolving page into components`,
|
||||
attributes: {
|
||||
'next.route': pathname,
|
||||
'next.route': route,
|
||||
},
|
||||
},
|
||||
() => this.findPageComponentsImpl({ pathname, query, params, isAppPath })
|
||||
|
|
|
@ -1361,6 +1361,7 @@ export async function renderToHTML(
|
|||
}
|
||||
}
|
||||
|
||||
getTracer().getRootSpanAttributes()?.set('next.route', renderOpts.pathname)
|
||||
const documentResult = await getTracer().trace(
|
||||
RenderSpan.renderDocument,
|
||||
{
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Resource } from '@opentelemetry/resources'
|
||||
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
|
||||
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
|
||||
import {
|
||||
NodeTracerProvider,
|
||||
SimpleSpanProcessor,
|
||||
SpanExporter,
|
||||
ReadableSpan,
|
||||
} from '@opentelemetry/sdk-trace-node'
|
||||
} from '@opentelemetry/sdk-trace-base'
|
||||
import {
|
||||
ExportResult,
|
||||
ExportResultCode,
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { Resource } from '@opentelemetry/resources'
|
||||
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
|
||||
import {
|
||||
NodeTracerProvider,
|
||||
SimpleSpanProcessor,
|
||||
} from '@opentelemetry/sdk-trace-node'
|
||||
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
||||
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
|
||||
|
||||
// You can use gRPC exporter instead
|
||||
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
|
||||
|
|
|
@ -10,12 +10,7 @@ createNextDescribe(
|
|||
skipDeployment: true,
|
||||
dependencies: require('./package.json').dependencies,
|
||||
},
|
||||
({ next }) => {
|
||||
// TODO: remove after resolving dev expected behavior
|
||||
// x-ref: https://github.com/vercel/next.js/pull/47822
|
||||
if ((global as any).isNextDev) {
|
||||
return it('should skip for dev for now', () => {})
|
||||
}
|
||||
({ next, isNextDev }) => {
|
||||
const getTraces = async (): Promise<SavedSpan[]> => {
|
||||
const traces = await next.readFile(traceFile)
|
||||
return traces
|
||||
|
@ -24,16 +19,6 @@ createNextDescribe(
|
|||
.map((line) => JSON.parse(line))
|
||||
}
|
||||
|
||||
const waitForRootSpan = async (numberOfRootTraces: number) => {
|
||||
await check(async () => {
|
||||
const spans = await getTraces()
|
||||
const rootSpans = spans.filter((span) => !span.parentId)
|
||||
return rootSpans.length >= numberOfRootTraces
|
||||
? String(numberOfRootTraces)
|
||||
: rootSpans.length
|
||||
}, String(numberOfRootTraces))
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize (modifies) span to make it ready for snapshot testing.
|
||||
*/
|
||||
|
@ -48,31 +33,29 @@ createNextDescribe(
|
|||
return span
|
||||
}
|
||||
const sanitizeSpans = (spans: SavedSpan[]) => {
|
||||
const seenSpans = new Set()
|
||||
return spans
|
||||
.sort((a, b) =>
|
||||
(a.attributes?.['next.span_name'] ?? '').localeCompare(
|
||||
b.attributes?.['next.span_name'] ?? ''
|
||||
)
|
||||
)
|
||||
.sort((a, b) =>
|
||||
(a.attributes?.['next.span_type'] ?? '').localeCompare(
|
||||
b.attributes?.['next.span_type'] ?? ''
|
||||
)
|
||||
)
|
||||
.map(sanitizeSpan)
|
||||
.filter((span) => {
|
||||
const target = span.attributes?.['http.target']
|
||||
const result =
|
||||
!span.attributes?.['http.url']?.startsWith('http://localhost') &&
|
||||
!seenSpans.has(target)
|
||||
|
||||
if (target) {
|
||||
seenSpans.add(target)
|
||||
}
|
||||
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
const getSanitizedTraces = async (numberOfRootTraces: number) => {
|
||||
await waitForRootSpan(numberOfRootTraces)
|
||||
return sanitizeSpans(await getTraces())
|
||||
let traces
|
||||
await check(async () => {
|
||||
traces = sanitizeSpans(await getTraces())
|
||||
|
||||
const rootSpans = traces.filter((span) => !span.parentId)
|
||||
return String(rootSpans.length)
|
||||
}, String(numberOfRootTraces))
|
||||
return traces
|
||||
}
|
||||
|
||||
const cleanTraces = async () => {
|
||||
|
@ -87,130 +70,116 @@ createNextDescribe(
|
|||
it('should handle RSC with fetch', async () => {
|
||||
await next.fetch('/app/param/rsc-fetch')
|
||||
|
||||
await check(async () => {
|
||||
const traces = await getSanitizedTraces(1)
|
||||
|
||||
for (const entry of [
|
||||
{
|
||||
attributes: {
|
||||
'http.method': 'GET',
|
||||
'http.url': 'https://vercel.com/',
|
||||
'net.peer.name': 'vercel.com',
|
||||
'next.span_name': 'fetch GET https://vercel.com/',
|
||||
'next.span_type': 'AppRender.fetch',
|
||||
expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"http.method": "GET",
|
||||
"http.url": "https://vercel.com/",
|
||||
"net.peer.name": "vercel.com",
|
||||
"next.span_name": "fetch GET https://vercel.com/",
|
||||
"next.span_type": "AppRender.fetch",
|
||||
},
|
||||
kind: 2,
|
||||
name: 'fetch GET https://vercel.com/',
|
||||
parentId: '[parent-id]',
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 2,
|
||||
"name": "fetch GET https://vercel.com/",
|
||||
"parentId": "[parent-id]",
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
'next.span_name': 'render route (app) /app/[param]/rsc-fetch',
|
||||
'next.span_type': 'AppRender.getBodyResult',
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"next.span_name": "render route (app) /app/[param]/rsc-fetch",
|
||||
"next.span_type": "AppRender.getBodyResult",
|
||||
},
|
||||
kind: 0,
|
||||
name: 'render route (app) /app/[param]/rsc-fetch',
|
||||
parentId: '[parent-id]',
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 0,
|
||||
"name": "render route (app) /app/[param]/rsc-fetch",
|
||||
"parentId": "[parent-id]",
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
'http.method': 'GET',
|
||||
'http.route': '/app/[param]/rsc-fetch/page',
|
||||
'http.status_code': 200,
|
||||
'http.target': '/app/param/rsc-fetch',
|
||||
'next.route': '/app/[param]/rsc-fetch/page',
|
||||
'next.span_name': 'GET /app/param/rsc-fetch',
|
||||
'next.span_type': 'BaseServer.handleRequest',
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"http.method": "GET",
|
||||
"http.route": "/app/[param]/rsc-fetch",
|
||||
"http.status_code": 200,
|
||||
"http.target": "/app/param/rsc-fetch",
|
||||
"next.route": "/app/[param]/rsc-fetch",
|
||||
"next.span_name": "GET /app/[param]/rsc-fetch",
|
||||
"next.span_type": "BaseServer.handleRequest",
|
||||
},
|
||||
kind: 1,
|
||||
name: 'GET /app/[param]/rsc-fetch/page',
|
||||
parentId: undefined,
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 1,
|
||||
"name": "GET /app/[param]/rsc-fetch",
|
||||
"parentId": undefined,
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
'next.route': '/app/[param]/layout',
|
||||
'next.span_name': 'generateMetadata /app/[param]/layout',
|
||||
'next.span_type': 'ResolveMetadata.generateMetadata',
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"next.route": "/app/[param]/layout",
|
||||
"next.span_name": "generateMetadata /app/[param]/layout",
|
||||
"next.span_type": "ResolveMetadata.generateMetadata",
|
||||
},
|
||||
kind: 0,
|
||||
name: 'generateMetadata /app/[param]/layout',
|
||||
parentId: '[parent-id]',
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 0,
|
||||
"name": "generateMetadata /app/[param]/layout",
|
||||
"parentId": "[parent-id]",
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
'next.route': '/app/[param]/rsc-fetch/page',
|
||||
'next.span_name':
|
||||
'generateMetadata /app/[param]/rsc-fetch/page',
|
||||
'next.span_type': 'ResolveMetadata.generateMetadata',
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"next.route": "/app/[param]/rsc-fetch/page",
|
||||
"next.span_name": "generateMetadata /app/[param]/rsc-fetch/page",
|
||||
"next.span_type": "ResolveMetadata.generateMetadata",
|
||||
},
|
||||
kind: 0,
|
||||
name: 'generateMetadata /app/[param]/rsc-fetch/page',
|
||||
parentId: '[parent-id]',
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 0,
|
||||
"name": "generateMetadata /app/[param]/rsc-fetch/page",
|
||||
"parentId": "[parent-id]",
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
]) {
|
||||
expect(traces).toContainEqual(entry)
|
||||
}
|
||||
return 'success'
|
||||
}, 'success')
|
||||
]
|
||||
`)
|
||||
})
|
||||
|
||||
it('should handle route handlers in app router', async () => {
|
||||
await next.fetch('/api/app/param/data')
|
||||
|
||||
await check(async () => {
|
||||
const traces = await getSanitizedTraces(1)
|
||||
|
||||
for (const entry of [
|
||||
{
|
||||
attributes: {
|
||||
'next.span_name':
|
||||
'executing api route (app) /api/app/[param]/data/route',
|
||||
'next.span_type': 'AppRouteRouteHandlers.runHandler',
|
||||
expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"next.span_name": "executing api route (app) /api/app/[param]/data/route",
|
||||
"next.span_type": "AppRouteRouteHandlers.runHandler",
|
||||
},
|
||||
kind: 0,
|
||||
name: 'executing api route (app) /api/app/[param]/data/route',
|
||||
parentId: '[parent-id]',
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 0,
|
||||
"name": "executing api route (app) /api/app/[param]/data/route",
|
||||
"parentId": "[parent-id]",
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
'http.method': 'GET',
|
||||
'http.route': '/api/app/[param]/data/route',
|
||||
'http.status_code': 200,
|
||||
'http.target': '/api/app/param/data',
|
||||
'next.route': '/api/app/[param]/data/route',
|
||||
'next.span_name': 'GET /api/app/param/data',
|
||||
'next.span_type': 'BaseServer.handleRequest',
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"http.method": "GET",
|
||||
"http.status_code": 200,
|
||||
"http.target": "/api/app/param/data",
|
||||
"next.span_name": "GET /api/app/param/data",
|
||||
"next.span_type": "BaseServer.handleRequest",
|
||||
},
|
||||
kind: 1,
|
||||
name: 'GET /api/app/[param]/data/route',
|
||||
parentId: undefined,
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 1,
|
||||
"name": "GET /api/app/param/data",
|
||||
"parentId": undefined,
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
]) {
|
||||
expect(traces).toContainEqual(entry)
|
||||
}
|
||||
return 'success'
|
||||
}, 'success')
|
||||
]
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -218,139 +187,139 @@ createNextDescribe(
|
|||
it('should handle getServerSideProps', async () => {
|
||||
await next.fetch('/pages/param/getServerSideProps')
|
||||
|
||||
await check(async () => {
|
||||
const traces = await getSanitizedTraces(1)
|
||||
for (const entry of [
|
||||
{
|
||||
attributes: {
|
||||
'next.span_name':
|
||||
'getServerSideProps /pages/[param]/getServerSideProps',
|
||||
'next.span_type': 'Render.getServerSideProps',
|
||||
expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"http.method": "GET",
|
||||
"http.route": "/pages/[param]/getServerSideProps",
|
||||
"http.status_code": 200,
|
||||
"http.target": "/pages/param/getServerSideProps",
|
||||
"next.route": "/pages/[param]/getServerSideProps",
|
||||
"next.span_name": "GET /pages/[param]/getServerSideProps",
|
||||
"next.span_type": "BaseServer.handleRequest",
|
||||
},
|
||||
kind: 0,
|
||||
name: 'getServerSideProps /pages/[param]/getServerSideProps',
|
||||
parentId: '[parent-id]',
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 1,
|
||||
"name": "GET /pages/[param]/getServerSideProps",
|
||||
"parentId": undefined,
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
'next.span_name':
|
||||
'render route (pages) /pages/[param]/getServerSideProps',
|
||||
'next.span_type': 'Render.renderDocument',
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"next.span_name": "getServerSideProps /pages/[param]/getServerSideProps",
|
||||
"next.span_type": "Render.getServerSideProps",
|
||||
},
|
||||
kind: 0,
|
||||
name: 'render route (pages) /pages/[param]/getServerSideProps',
|
||||
parentId: '[parent-id]',
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 0,
|
||||
"name": "getServerSideProps /pages/[param]/getServerSideProps",
|
||||
"parentId": "[parent-id]",
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
]) {
|
||||
expect(traces).toContainEqual(entry)
|
||||
}
|
||||
return 'success'
|
||||
}, 'success')
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"next.span_name": "render route (pages) /pages/[param]/getServerSideProps",
|
||||
"next.span_type": "Render.renderDocument",
|
||||
},
|
||||
"kind": 0,
|
||||
"name": "render route (pages) /pages/[param]/getServerSideProps",
|
||||
"parentId": "[parent-id]",
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
]
|
||||
`)
|
||||
})
|
||||
|
||||
it("should handle getStaticProps when fallback: 'blocking'", async () => {
|
||||
await next.fetch('/pages/param/getStaticProps')
|
||||
|
||||
await check(async () => {
|
||||
const traces = await getSanitizedTraces(1)
|
||||
|
||||
for (const entry of [
|
||||
{
|
||||
attributes: {
|
||||
'http.method': 'GET',
|
||||
'http.route': '/pages/[param]/getStaticProps',
|
||||
'http.status_code': 200,
|
||||
'http.target': '/pages/param/getStaticProps',
|
||||
'next.route': '/pages/[param]/getStaticProps',
|
||||
'next.span_name': 'GET /pages/param/getStaticProps',
|
||||
'next.span_type': 'BaseServer.handleRequest',
|
||||
expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"http.method": "GET",
|
||||
"http.route": "/pages/[param]/getStaticProps",
|
||||
"http.status_code": 200,
|
||||
"http.target": "/pages/param/getStaticProps",
|
||||
"next.route": "/pages/[param]/getStaticProps",
|
||||
"next.span_name": "GET /pages/[param]/getStaticProps",
|
||||
"next.span_type": "BaseServer.handleRequest",
|
||||
},
|
||||
kind: 1,
|
||||
name: 'GET /pages/[param]/getStaticProps',
|
||||
parentId: undefined,
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 1,
|
||||
"name": "GET /pages/[param]/getStaticProps",
|
||||
"parentId": undefined,
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
'next.span_name':
|
||||
'getStaticProps /pages/[param]/getStaticProps',
|
||||
'next.span_type': 'Render.getStaticProps',
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"next.span_name": "getStaticProps /pages/[param]/getStaticProps",
|
||||
"next.span_type": "Render.getStaticProps",
|
||||
},
|
||||
kind: 0,
|
||||
name: 'getStaticProps /pages/[param]/getStaticProps',
|
||||
parentId: '[parent-id]',
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 0,
|
||||
"name": "getStaticProps /pages/[param]/getStaticProps",
|
||||
"parentId": "[parent-id]",
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
'next.span_name':
|
||||
'render route (pages) /pages/[param]/getStaticProps',
|
||||
'next.span_type': 'Render.renderDocument',
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"next.span_name": "render route (pages) /pages/[param]/getStaticProps",
|
||||
"next.span_type": "Render.renderDocument",
|
||||
},
|
||||
kind: 0,
|
||||
name: 'render route (pages) /pages/[param]/getStaticProps',
|
||||
parentId: '[parent-id]',
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 0,
|
||||
"name": "render route (pages) /pages/[param]/getStaticProps",
|
||||
"parentId": "[parent-id]",
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
]) {
|
||||
expect(traces).toContainEqual(entry)
|
||||
}
|
||||
return 'success'
|
||||
}, 'success')
|
||||
]
|
||||
`)
|
||||
})
|
||||
|
||||
it('should handle api routes in pages', async () => {
|
||||
await next.fetch('/api/pages/param/basic')
|
||||
|
||||
await check(async () => {
|
||||
const traces = await getSanitizedTraces(1)
|
||||
|
||||
for (const entry of [
|
||||
{
|
||||
attributes: {
|
||||
'http.method': 'GET',
|
||||
'http.status_code': 200,
|
||||
'http.target': '/api/pages/param/basic',
|
||||
'next.span_name': 'GET /api/pages/param/basic',
|
||||
'next.span_type': 'BaseServer.handleRequest',
|
||||
expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"http.method": "GET",
|
||||
"http.route": "/api/pages/[param]/basic",
|
||||
"http.status_code": 200,
|
||||
"http.target": "/api/pages/param/basic",
|
||||
"next.route": "/api/pages/[param]/basic",
|
||||
"next.span_name": "GET /api/pages/[param]/basic",
|
||||
"next.span_type": "BaseServer.handleRequest",
|
||||
},
|
||||
kind: 1,
|
||||
name: 'GET /api/pages/param/basic',
|
||||
parentId: undefined,
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 1,
|
||||
"name": "GET /api/pages/[param]/basic",
|
||||
"parentId": undefined,
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
'next.span_name':
|
||||
'executing api route (pages) /api/pages/[param]/basic',
|
||||
'next.span_type': 'Node.runHandler',
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"next.span_name": "executing api route (pages) /api/pages/[param]/basic",
|
||||
"next.span_type": "Node.runHandler",
|
||||
},
|
||||
kind: 0,
|
||||
name: 'executing api route (pages) /api/pages/[param]/basic',
|
||||
parentId: '[parent-id]',
|
||||
status: {
|
||||
code: 0,
|
||||
"kind": 0,
|
||||
"name": "executing api route (pages) /api/pages/[param]/basic",
|
||||
"parentId": "[parent-id]",
|
||||
"status": Object {
|
||||
"code": 0,
|
||||
},
|
||||
},
|
||||
]) {
|
||||
expect(traces).toContainEqual(entry)
|
||||
}
|
||||
return 'success'
|
||||
}, 'success')
|
||||
]
|
||||
`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue