diff --git a/packages/gatsby-cli/src/reporter/redux/diagnostics.ts b/packages/gatsby-cli/src/reporter/redux/diagnostics.ts index 853306c005f60..97da4989efd28 100644 --- a/packages/gatsby-cli/src/reporter/redux/diagnostics.ts +++ b/packages/gatsby-cli/src/reporter/redux/diagnostics.ts @@ -38,6 +38,32 @@ const FIVE_SECONDS = 1000 * 5 const TEN_MINUTES = 1000 * 60 * 10 const TEN_SECONDS = 1000 * 10 +export type AdditionalDiagnosticsOutputHandler = () => string +const additionalDiagnosticOutputHandlers: Array = + [] + +export function registerAdditionalDiagnosticOutputHandler( + handler: AdditionalDiagnosticsOutputHandler +): void { + additionalDiagnosticOutputHandlers.push(handler) +} + +function generateAdditionalOutput(): string { + const extraMessages: Array = [] + + for (const handler of additionalDiagnosticOutputHandlers) { + const msg = handler() + + if (msg) { + extraMessages.push(msg) + } + } + + return extraMessages.length > 0 + ? `\n\nAdditional debugging logs:\n\n${extraMessages.join(`\n\n`)}` + : `` +} + export function createStructuredLoggingDiagnosticsMiddleware( getStore: () => GatsbyCLIStore ): DiagnosticsMiddleware { @@ -152,7 +178,7 @@ export function createStructuredLoggingDiagnosticsMiddleware( 1000 ).toFixed(3)} seconds if nothing will change.` : `` - }` + }${generateAdditionalOutput()}` ) displayingStuckStatusDiagnosticWarning = false displayedStuckStatusDiagnosticWarning = true @@ -179,6 +205,7 @@ export function createStructuredLoggingDiagnosticsMiddleware( stuckStatusDiagnosticMessage: generateStuckStatusDiagnosticMessage(), stuckStatusWatchdogTimeoutDelay, + additionalOutput: generateAdditionalOutput(), }, }) }, diff --git a/packages/gatsby-cli/src/reporter/reporter.ts b/packages/gatsby-cli/src/reporter/reporter.ts index 55e3ce2a8e01f..49059f45653c8 100644 --- a/packages/gatsby-cli/src/reporter/reporter.ts +++ b/packages/gatsby-cli/src/reporter/reporter.ts @@ -19,6 +19,10 @@ import { ILogIntent, IRenderPageArgs, } from "./types" +import { + registerAdditionalDiagnosticOutputHandler, + AdditionalDiagnosticsOutputHandler, +} from "./redux/diagnostics" const errorFormatter = getErrorFormatter() const tracer = globalTracer() @@ -351,6 +355,12 @@ class Reporter { _renderPageTree(args: IRenderPageArgs): void { reporterActions.renderPageTree(args) } + + _registerAdditionalDiagnosticOutputHandler( + handler: AdditionalDiagnosticsOutputHandler + ): void { + registerAdditionalDiagnosticOutputHandler(handler) + } } export type { Reporter } export const reporter = new Reporter() diff --git a/packages/gatsby-cli/src/structured-errors/error-map.ts b/packages/gatsby-cli/src/structured-errors/error-map.ts index 6aa1280ab9cd5..6617a68ee2430 100644 --- a/packages/gatsby-cli/src/structured-errors/error-map.ts +++ b/packages/gatsby-cli/src/structured-errors/error-map.ts @@ -620,7 +620,7 @@ const errors = { 3 )} seconds. Activities preventing Gatsby from transitioning to idle state:\n\n${ context.stuckStatusDiagnosticMessage - }`, + }${context.additionalOutput}`, level: Level.ERROR, docsUrl: `https://support.gatsbyjs.com/hc/en-us/articles/360056811354`, }, diff --git a/packages/gatsby/src/services/initialize.ts b/packages/gatsby/src/services/initialize.ts index 3e246ce566431..8972da6045269 100644 --- a/packages/gatsby/src/services/initialize.ts +++ b/packages/gatsby/src/services/initialize.ts @@ -20,6 +20,7 @@ import { IGatsbyState, IStateProgram } from "../redux/types" import { IBuildContext } from "./types" import { detectLmdbStore } from "../datastore" import { loadConfigAndPlugins } from "../bootstrap/load-config-and-plugins" +import type { InternalJob } from "../utils/jobs/types" interface IPluginResolution { resolve: string @@ -101,6 +102,29 @@ export async function initialize({ args.setStore(store) } + if (reporter._registerAdditionalDiagnosticOutputHandler) { + reporter._registerAdditionalDiagnosticOutputHandler( + function logPendingJobs(): string { + const outputs: Array = [] + + for (const [, { job }] of store.getState().jobsV2.incomplete) { + outputs.push(job) + if (outputs.length >= 5) { + // 5 not finished jobs should be enough to track down issues + // this is just limiting output "spam" + break + } + } + + return outputs.length + ? `Unfinished jobs (showing ${outputs.length} of ${ + store.getState().jobsV2.incomplete.size + } jobs total):\n\n` + JSON.stringify(outputs, null, 2) + : `` + } + ) + } + const directory = slash(args.directory) const program: IStateProgram = {