Skip to content

Commit

Permalink
Add otel span for client component loading
Browse files Browse the repository at this point in the history
  • Loading branch information
ijjk committed Feb 20, 2024
1 parent 6d3ede1 commit 7469075
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 3 deletions.
60 changes: 57 additions & 3 deletions packages/next/src/server/app-render/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import {
getRedirectStatusCodeFromError,
} from '../../client/components/redirect'
import { addImplicitTags } from '../lib/patch-fetch'
import { AppRenderSpan } from '../lib/trace/constants'
import { AppRenderSpan, NextNodeServerSpan } from '../lib/trace/constants'
import { getTracer } from '../lib/trace/tracer'
import { FlightRenderResult } from './flight-render-result'
import {
Expand Down Expand Up @@ -615,15 +615,69 @@ async function renderToHTMLOrFlightImpl(
enableTainting,
} = renderOpts

// Combined load times for loading client components
let clientComponentLoadStart = 0
let clientComponentLoadTimes = 0
let clientComponentLoadCount = 0

// We need to expose the bundled `require` API globally for
// react-server-dom-webpack. This is a hack until we find a better way.
if (ComponentMod.__next_app__) {
// @ts-ignore
globalThis.__next_require__ = ComponentMod.__next_app__.require
globalThis.__next_require__ = (...args: any[]) => {
if (clientComponentLoadStart === 0) {
clientComponentLoadStart = Date.now()
}

const startTime = Date.now()
try {
clientComponentLoadCount += 1
return ComponentMod.__next_app__.require(...args)
} finally {
clientComponentLoadTimes += Date.now() - startTime
}
}

// @ts-ignore
globalThis.__next_chunk_load__ = ComponentMod.__next_app__.loadChunk
globalThis.__next_chunk_load__ = (...args: any[]) => {
const startTime = Date.now()
try {
clientComponentLoadCount += 1
return ComponentMod.__next_app__.loadChunk(...args)
} finally {
clientComponentLoadTimes += Date.now() - startTime
}
}
}
req.on('end', () => {
const type = NextNodeServerSpan.clientComponentLoading
const startTime = clientComponentLoadStart
const endTime = clientComponentLoadStart + clientComponentLoadTimes
getTracer()
.startSpan(type, {
startTime,
attributes: {
'next.clientComponentLoadCount': clientComponentLoadCount,
},
})
.end(endTime)

if (
typeof performance !== 'undefined' &&
process.env.NEXT_OTEL_PERFORMANCE_PREFIX
) {
const { timeOrigin } = performance
performance.measure(
`${process.env.NEXT_OTEL_PERFORMANCE_PREFIX}:next-${(
type.split('.').pop() || ''
).replace(/[A-Z]/g, (match: string) => '-' + match.toLowerCase())}`,
{
start: startTime - timeOrigin,
end: endTime - timeOrigin,
}
)
}
})

const metadata: AppPageRenderResultMetadata = {}

Expand Down
3 changes: 3 additions & 0 deletions packages/next/src/server/lib/trace/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enum NextNodeServerSpan {
compression = 'NextNodeServer.compression',
getBuildId = 'NextNodeServer.getBuildId',
createComponentTree = 'NextNodeServer.createComponentTree',
clientComponentLoading = 'NextNodeServer.clientComponentLoading',
getLayoutOrPageModule = 'NextNodeServer.getLayoutOrPageModule',
generateStaticRoutes = 'NextNodeServer.generateStaticRoutes',
generateFsStaticRoutes = 'NextNodeServer.generateFsStaticRoutes',
Expand Down Expand Up @@ -134,13 +135,15 @@ export const NextVanillaSpanAllowlist = [
NextNodeServerSpan.findPageComponents,
NextNodeServerSpan.getLayoutOrPageModule,
NextNodeServerSpan.startResponse,
NextNodeServerSpan.clientComponentLoading,
]

// These Spans are allowed to be always logged
// when the otel log prefix env is set
export const LogSpanAllowList = [
NextNodeServerSpan.findPageComponents,
NextNodeServerSpan.createComponentTree,
NextNodeServerSpan.clientComponentLoading,
]

export {
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/lib/trace/tracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ type NextAttributeNames =
| 'next.segment'
| 'next.span_name'
| 'next.span_type'
| 'next.clientComponentLoadCount'
type OTELAttributeNames = `http.${string}` | `net.${string}`
type AttributeNames = NextAttributeNames | OTELAttributeNames

Expand Down

0 comments on commit 7469075

Please sign in to comment.