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

Add default trace format that is exported automatically #28461

Merged
merged 9 commits into from Aug 25, 2021
2 changes: 1 addition & 1 deletion packages/next/build/babel/loader/index.ts
Expand Up @@ -40,7 +40,7 @@ const nextBabelLoaderOuter = function nextBabelLoaderOuter(
) {
const callback = this.async()

const loaderSpan = trace('next-babel-turbo-loader', this.currentTraceSpan?.id)
const loaderSpan = this.currentTraceSpan.traceChild('next-babel-turbo-loader')
loaderSpan
.traceAsyncFn(() =>
nextBabelLoader.call(this, loaderSpan, inputSource, inputSourceMap)
Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/babel/loader/types.d.ts
Expand Up @@ -2,7 +2,7 @@ import { loader } from 'next/dist/compiled/webpack/webpack'
import { Span } from '../../../telemetry/trace'

export interface NextJsLoaderContext extends loader.LoaderContext {
currentTraceSpan?: Span
currentTraceSpan: Span
}

export interface NextBabelLoaderOptions {
Expand Down
4 changes: 3 additions & 1 deletion packages/next/build/index.ts
Expand Up @@ -130,11 +130,13 @@ export default async function build(
const config: NextConfigComplete = await nextBuildSpan
.traceChild('load-next-config')
.traceAsyncFn(() => loadConfig(PHASE_PRODUCTION_BUILD, dir, conf))
const distDir = path.join(dir, config.distDir)
setGlobal('distDir', distDir)

const { target } = config
const buildId: string = await nextBuildSpan
.traceChild('generate-buildid')
.traceAsyncFn(() => generateBuildId(config.generateBuildId, nanoid))
const distDir = path.join(dir, config.distDir)

const customRoutes: CustomRoutes = await nextBuildSpan
.traceChild('load-custom-routes')
Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/webpack-config.ts
Expand Up @@ -240,7 +240,7 @@ export default async function getBaseWebpackConfig(
entrypoints: WebpackEntrypoints
rewrites: CustomRoutes['rewrites']
isDevFallback?: boolean
runWebpackSpan?: Span
runWebpackSpan: Span
}
): Promise<webpack.Configuration> {
const hasRewrites =
Expand Down
Expand Up @@ -11,7 +11,6 @@ import {
ROUTES_MANIFEST,
REACT_LOADABLE_MANIFEST,
} from '../../../../shared/lib/constants'
import { trace } from '../../../../telemetry/trace'

export type ServerlessLoaderQuery = {
page: string
Expand All @@ -34,63 +33,61 @@ export type ServerlessLoaderQuery = {
}

const nextServerlessLoader: webpack.loader.Loader = function () {
const loaderSpan = trace('next-serverless-loader')
return loaderSpan.traceFn(() => {
const {
distDir,
absolutePagePath,
page,
buildId,
canonicalBase,
assetPrefix,
absoluteAppPath,
absoluteDocumentPath,
absoluteErrorPath,
absolute404Path,
generateEtags,
poweredByHeader,
basePath,
runtimeConfig,
previewProps,
loadedEnvFiles,
i18n,
}: ServerlessLoaderQuery =
typeof this.query === 'string' ? parse(this.query.substr(1)) : this.query

const buildManifest = join(distDir, BUILD_MANIFEST).replace(/\\/g, '/')
const reactLoadableManifest = join(
distDir,
REACT_LOADABLE_MANIFEST
).replace(/\\/g, '/')
const routesManifest = join(distDir, ROUTES_MANIFEST).replace(/\\/g, '/')

const escapedBuildId = escapeRegexp(buildId)
const pageIsDynamicRoute = isDynamicRoute(page)

const encodedPreviewProps = devalue(
JSON.parse(previewProps) as __ApiPreviewProps
)

const envLoading = `
const {
distDir,
absolutePagePath,
page,
buildId,
canonicalBase,
assetPrefix,
absoluteAppPath,
absoluteDocumentPath,
absoluteErrorPath,
absolute404Path,
generateEtags,
poweredByHeader,
basePath,
runtimeConfig,
previewProps,
loadedEnvFiles,
i18n,
}: ServerlessLoaderQuery =
typeof this.query === 'string' ? parse(this.query.substr(1)) : this.query

const buildManifest = join(distDir, BUILD_MANIFEST).replace(/\\/g, '/')
const reactLoadableManifest = join(distDir, REACT_LOADABLE_MANIFEST).replace(
/\\/g,
'/'
)
const routesManifest = join(distDir, ROUTES_MANIFEST).replace(/\\/g, '/')

const escapedBuildId = escapeRegexp(buildId)
const pageIsDynamicRoute = isDynamicRoute(page)

const encodedPreviewProps = devalue(
JSON.parse(previewProps) as __ApiPreviewProps
)

const envLoading = `
const { processEnv } = require('@next/env')
processEnv(${Buffer.from(loadedEnvFiles, 'base64').toString()})
`

const runtimeConfigImports = runtimeConfig
? `
const runtimeConfigImports = runtimeConfig
? `
const { setConfig } = require('next/config')
`
: ''
: ''

const runtimeConfigSetter = runtimeConfig
? `
const runtimeConfigSetter = runtimeConfig
? `
const runtimeConfig = ${runtimeConfig}
setConfig(runtimeConfig)
`
: 'const runtimeConfig = {}'
: 'const runtimeConfig = {}'

if (page.match(API_ROUTE)) {
return `
if (page.match(API_ROUTE)) {
return `
${envLoading}
${runtimeConfigImports}
${
Expand Down Expand Up @@ -125,8 +122,8 @@ const nextServerlessLoader: webpack.loader.Loader = function () {
})
export default apiHandler
`
} else {
return `
} else {
return `
import 'next/dist/server/node-polyfill-fetch'
import routesManifest from '${routesManifest}'
import buildManifest from '${buildManifest}'
Expand Down Expand Up @@ -206,8 +203,7 @@ const nextServerlessLoader: webpack.loader.Loader = function () {
})
export { renderReqToHTML, render }
`
}
})
}
}

export default nextServerlessLoader
2 changes: 1 addition & 1 deletion packages/next/build/webpack/loaders/next-swc-loader.js
Expand Up @@ -123,7 +123,7 @@ async function loaderTransform(parentTrace, source, inputSourceMap) {
}

export default function swcLoader(inputSource, inputSourceMap) {
const loaderSpan = trace('next-swc-loader', this.currentTraceSpan?.id)
const loaderSpan = this.currentTraceSpan.traceChild('next-swc-loader')
const callback = this.async()
loaderSpan
.traceAsyncFn(() =>
Expand Down
Expand Up @@ -118,7 +118,7 @@ export default class BuildStatsPlugin {
async (stats, callback) => {
const compilerSpan = spans.get(compiler)
try {
const writeStatsSpan = trace('NextJsBuildStats', compilerSpan?.id)
const writeStatsSpan = compilerSpan!.traceChild('NextJsBuildStats')
await writeStatsSpan.traceAsyncFn(() => {
return new Promise((resolve, reject) => {
const statsJson = reduceSize(
Expand Down
7 changes: 3 additions & 4 deletions packages/next/build/webpack/plugins/css-minimizer-plugin.ts
Expand Up @@ -71,9 +71,8 @@ export class CssMinimizerPlugin {
},
async (assets: any) => {
const compilerSpan = spans.get(compiler)
const cssMinimizerSpan = trace(
'css-minimizer-plugin',
compilerSpan?.id
const cssMinimizerSpan = compilerSpan!.traceChild(
'css-minimizer-plugin'
)
cssMinimizerSpan.setAttribute('webpackVersion', 5)

Expand All @@ -83,7 +82,7 @@ export class CssMinimizerPlugin {
files
.filter((file) => CSS_REGEX.test(file))
.map(async (file) => {
const assetSpan = trace('minify-css', cssMinimizerSpan.id)
const assetSpan = cssMinimizerSpan.traceChild('minify-css')
assetSpan.setAttribute('file', file)

return assetSpan.traceAsyncFn(async () => {
Expand Down
23 changes: 15 additions & 8 deletions packages/next/build/webpack/plugins/profiling-plugin.ts
Expand Up @@ -15,9 +15,9 @@ function getNormalModuleLoaderHook(compilation: any) {

export class ProfilingPlugin {
compiler: any
runWebpackSpan: Span | undefined
runWebpackSpan: Span

constructor({ runWebpackSpan }: { runWebpackSpan: Span | undefined }) {
constructor({ runWebpackSpan }: { runWebpackSpan: Span }) {
this.runWebpackSpan = runWebpackSpan
}
apply(compiler: any) {
Expand All @@ -35,14 +35,17 @@ export class ProfilingPlugin {
attrs,
onSetSpan,
}: {
parentSpan?: () => Span | undefined
parentSpan?: () => Span
attrs?: any
onSetSpan?: (span: Span) => void
} = {}
) {
let span: Span | undefined
startHook.tap(pluginName, () => {
span = trace(spanName, parentSpan?.()?.id, attrs ? attrs() : attrs)
span = parentSpan
? parentSpan().traceChild(spanName, attrs ? attrs() : attrs)
: trace(spanName, undefined, attrs ? attrs() : attrs)

onSetSpan?.(span)
})
stopHook.tap(pluginName, () => {
Expand Down Expand Up @@ -103,10 +106,14 @@ export class ProfilingPlugin {

const issuerModule = compilation?.moduleGraph?.getIssuer(module)

const span = trace(
`build-module${moduleType ? `-${moduleType}` : ''}`,
issuerModule ? spans.get(issuerModule)?.id : compilerSpan.id
)
let span: Span

const spanName = `build-module${moduleType ? `-${moduleType}` : ''}`
if (issuerModule) {
span = spans.get(issuerModule)!.traceChild(spanName)
timneutkens marked this conversation as resolved.
Show resolved Hide resolved
} else {
span = compilerSpan.traceChild(spanName)
}
span.setAttribute('name', module.userRequest)
spans.set(module, span)
})
Expand Down
6 changes: 6 additions & 0 deletions packages/next/server/dev/hot-reloader.ts
Expand Up @@ -27,6 +27,7 @@ import { difference } from '../../build/utils'
import { NextConfigComplete } from '../config-shared'
import { CustomRoutes } from '../../lib/load-custom-routes'
import { DecodeError } from '../../shared/lib/utils'
import { Span, trace } from '../../telemetry/trace'

export async function renderScriptError(
res: ServerResponse,
Expand Down Expand Up @@ -143,6 +144,7 @@ export default class HotReloader {
private watcher: any
private rewrites: CustomRoutes['rewrites']
private fallbackWatcher: any
private hotReloaderSpan: Span
public isWebpack5: any

constructor(
Expand Down Expand Up @@ -174,6 +176,7 @@ export default class HotReloader {
this.previewProps = previewProps
this.rewrites = rewrites
this.isWebpack5 = isWebpack5
this.hotReloaderSpan = trace('hot-reloader')
}

public async run(
Expand Down Expand Up @@ -283,6 +286,7 @@ export default class HotReloader {
pagesDir: this.pagesDir,
rewrites: this.rewrites,
entrypoints: entrypoints.client,
runWebpackSpan: this.hotReloaderSpan,
}),
getBaseWebpackConfig(this.dir, {
dev: true,
Expand All @@ -292,6 +296,7 @@ export default class HotReloader {
pagesDir: this.pagesDir,
rewrites: this.rewrites,
entrypoints: entrypoints.server,
runWebpackSpan: this.hotReloaderSpan,
}),
])
}
Expand All @@ -300,6 +305,7 @@ export default class HotReloader {
if (this.fallbackWatcher) return

const fallbackConfig = await getBaseWebpackConfig(this.dir, {
runWebpackSpan: this.hotReloaderSpan,
dev: true,
isServer: false,
config: this.config,
Expand Down
39 changes: 34 additions & 5 deletions packages/next/telemetry/trace/report/index.ts
Expand Up @@ -3,6 +3,7 @@ import reportToConsole from './to-console'
import reportToZipkin from './to-zipkin'
import reportToJaeger from './to-jaeger'
import reportToTelemetry from './to-telemetry'
import reportToJson from './to-json'

type Reporter = {
flushAll: () => Promise<void> | void
Expand All @@ -16,6 +17,31 @@ type Reporter = {
) => void
}

class MultiReporter implements Reporter {
private reporters: Reporter[] = []

constructor(reporters: Reporter[]) {
this.reporters = reporters
}

async flushAll() {
await Promise.all(this.reporters.map((reporter) => reporter.flushAll()))
}

report(
spanName: string,
duration: number,
timestamp: number,
id: SpanId,
parentId?: SpanId,
attrs?: Object
) {
this.reporters.forEach((reporter) =>
reporter.report(spanName, duration, timestamp, id, parentId, attrs)
)
}
}

const target =
process.env.TRACE_TARGET && process.env.TRACE_TARGET in TARGET
? TARGET[process.env.TRACE_TARGET as TARGET]
Expand All @@ -27,14 +53,17 @@ if (process.env.TRACE_TARGET && !target) {
)
}

export let reporter: Reporter
let traceTargetReporter: Reporter

if (target === TARGET.CONSOLE) {
reporter = reportToConsole
traceTargetReporter = reportToConsole
} else if (target === TARGET.ZIPKIN) {
reporter = reportToZipkin
traceTargetReporter = reportToZipkin
} else if (target === TARGET.JAEGER) {
reporter = reportToJaeger
traceTargetReporter = reportToJaeger
} else {
reporter = reportToTelemetry
traceTargetReporter = reportToTelemetry
}

// JSON is always reported to allow for diagnostics
export const reporter = new MultiReporter([reportToJson, traceTargetReporter])
timneutkens marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 2 additions & 2 deletions packages/next/telemetry/trace/report/to-jaeger.ts
Expand Up @@ -5,7 +5,7 @@ import * as Log from '../../../build/output/log'
// Jaeger uses Zipkin's reporting
import { batcher } from './to-zipkin'

let traceId = process.env.TRACE_ID
let traceId: string
let batch: ReturnType<typeof batcher> | undefined

const localEndpoint = {
Expand Down Expand Up @@ -33,7 +33,7 @@ const reportToLocalHost = (
attrs?: Object
) => {
if (!traceId) {
traceId = process.env.TRACE_ID = randomBytes(8).toString('hex')
traceId = process.env.TRACE_ID || randomBytes(8).toString('hex')
logWebUrl()
}

Expand Down