Skip to content

Commit

Permalink
Check if parentspan is provided in profiler (#22061)
Browse files Browse the repository at this point in the history
Co-authored-by: Dale Bustad <dale@divmain.com>
  • Loading branch information
timneutkens and divmain committed Feb 12, 2021
1 parent 5c24670 commit 83657b6
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 15 deletions.
11 changes: 11 additions & 0 deletions .vscode/launch.json
Expand Up @@ -25,6 +25,17 @@
"port": 9229,
"outFiles": ["${workspaceFolder}/packages/next/dist/**/*"]
},
{
"name": "Launch app build trace",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "yarn",
"runtimeArgs": ["run", "trace-debug", "build", "test/integration/basic"],
"skipFiles": ["<node_internals>/**"],
"port": 9229,
"outFiles": ["${workspaceFolder}/packages/next/dist/**/*"]
},
{
"name": "Launch app production",
"type": "node",
Expand Down
54 changes: 41 additions & 13 deletions packages/next/build/tracer.ts
Expand Up @@ -3,6 +3,7 @@ import api, { Span } from '@opentelemetry/api'
export const tracer = api.trace.getTracer('next', process.env.__NEXT_VERSION)

const compilerStacks = new WeakMap()
const compilerStoppedSpans = new WeakMap()

export function stackPush(compiler: any, spanName: string, attrs?: any): any {
let stack = compilerStacks.get(compiler)
Expand All @@ -13,34 +14,61 @@ export function stackPush(compiler: any, spanName: string, attrs?: any): any {
span = tracer.startSpan(spanName, attrs ? attrs() : undefined)
} else {
const parent = stack[stack.length - 1]
tracer.withSpan(parent, () => {
if (parent) {
tracer.withSpan(parent, () => {
span = tracer.startSpan(spanName, attrs ? attrs() : undefined)
})
} else {
span = tracer.startSpan(spanName, attrs ? attrs() : undefined)
})
}
}

stack.push(span)
return span
}

export function stackPop(compiler: any, span: any) {
span.end()

export function stackPop(compiler: any, span: any, associatedName?: string) {
let stack = compilerStacks.get(compiler)
if (!stack) {
console.warn(
'Attempted to pop from non-existent stack. Compiler reference must be bad.'
)
return
}
const poppedSpan = stack.pop()
if (poppedSpan !== span) {
stack.push(poppedSpan)
const spanIdx = stack.indexOf(span)
console.warn('Attempted to pop span that was not at top of stack.')
if (spanIdx !== -1) {
console.info(
`Span was found at index ${spanIdx} with stack size ${stack.length}`

let stoppedSpans: Set<Span> = compilerStoppedSpans.get(compiler)
if (!stoppedSpans) {
stoppedSpans = new Set()
compilerStoppedSpans.set(compiler, stoppedSpans)
}
if (stoppedSpans.has(span)) {
console.warn(
`Attempted to terminate tracing span that was already stopped for ${associatedName}`
)
return
}

while (true) {
let poppedSpan = stack.pop()

if (poppedSpan === span) {
stoppedSpans.add(poppedSpan)
span.end()
stoppedSpans.add(span)
break
} else if (poppedSpan === undefined || stack.indexOf(span) === -1) {
// We've either reached the top of the stack or the stack doesn't contain
// the span for another reason.
console.warn(`Tracing span was not found in stack for: ${associatedName}`)
stoppedSpans.add(span)
span.end()
break
} else if (stack.indexOf(span) !== -1) {
console.warn(
`Attempted to pop span that was not at top of stack for: ${associatedName}`
)
stoppedSpans.add(poppedSpan)
poppedSpan.end()
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions packages/next/build/webpack/plugins/profiling-plugin.ts
Expand Up @@ -54,7 +54,13 @@ export class ProfilingPlugin {
onSetSpan?.(span)
})
stopHook.tap(pluginName, () => {
stackPop(this.compiler, span)
// `stopHook` may be triggered when `startHook` has not in cases
// where `stopHook` is used as the terminating event for more
// than one pair of hooks.
if (!span) {
return
}
stackPop(this.compiler, span, spanName)
})
}

Expand All @@ -66,7 +72,7 @@ export class ProfilingPlugin {
}
})
stopHook.tap(pluginName, () => {
stackPop(this.compiler, span)
stackPop(this.compiler, span, spanName)
})
}

Expand Down

0 comments on commit 83657b6

Please sign in to comment.