diff --git a/scripts/serverless.js b/scripts/serverless.js index 361cfa65e..210a3b1b5 100755 --- a/scripts/serverless.js +++ b/scripts/serverless.js @@ -12,6 +12,8 @@ require('graceful-fs').gracefulify(require('fs')); require('@serverless/utils/log-reporters/node'); const { log, progress, isInteractive: isInteractiveTerminal } = require('@serverless/utils/log'); +const processLog = log.get('process'); + const handleError = require('../lib/cli/handle-error'); const { storeLocally: storeTelemetryLocally, @@ -39,6 +41,7 @@ const keepAliveTimer = setTimeout(() => {}, 60 * 60 * 1000); let processSpanPromise; let hasBeenFinalized = false; const finalize = async ({ error, shouldBeSync, telemetryData, shouldSendTelemetry } = {}) => { + processLog.debug('finalize %o', { error, shouldBeSync, telemetryData, shouldSendTelemetry }); if (hasBeenFinalized) { if (error) { // Programmer error in finalize handling, ensure to expose @@ -84,6 +87,7 @@ processSpanPromise = (async () => { require('signal-exit/signals').forEach((signal) => { process.once(signal, () => { + processLog.debug('exit signal %s', signal); // If there's another listener (e.g. we're in deamon context or reading stdin input) // then let the other listener decide how process will exit const isOtherSigintListener = Boolean(process.listenerCount(signal)); @@ -121,6 +125,7 @@ processSpanPromise = (async () => { const resolveInput = require('../lib/cli/resolve-input'); let commands; + processLog.debug('resolve CLI input (no service schema)'); // Parse args against schemas of commands which do not require to be run in service context ({ command, commands, options, isHelpRequest, commandSchema } = resolveInput( require('../lib/cli/commands-schema/no-service') @@ -128,6 +133,7 @@ processSpanPromise = (async () => { // If version number request, show it and abort if (options.version) { + processLog.debug('render version'); await require('../lib/cli/render-version')(); await finalize(); return; @@ -179,6 +185,7 @@ processSpanPromise = (async () => { // Parse args again, taking acounnt schema of service-specific flags // as they may influence configuration resolution + processLog.debug('resolve CLI input (service schema)'); resolveInput.clear(); ({ command, commands, options, isHelpRequest, commandSchema } = resolveInput( require('../lib/cli/commands-schema/service') @@ -186,12 +193,16 @@ processSpanPromise = (async () => { isInteractiveSetup = !isHelpRequest && command === ''; + processLog.debug('resolve eventual service configuration'); const resolveConfigurationPath = require('../lib/cli/resolve-configuration-path'); const readConfiguration = require('../lib/configuration/read'); const resolveProviderName = require('../lib/configuration/resolve-provider-name'); // Resolve eventual service configuration path configurationPath = await resolveConfigurationPath(); + if (configurationPath) { + processLog.debug('service configuration found at %s', configurationPath); + } else processLog.debug('no service configuration found'); // If service configuration file is found, load its content configuration = configurationPath @@ -209,10 +220,12 @@ processSpanPromise = (async () => { : null; if (configuration) { + processLog.debug('service configuration file successfully parsed'); serviceDir = process.cwd(); // IIFE for maintenance convenience await (async () => { + processLog.debug('resolve variables meta'); const resolveVariablesMeta = require('../lib/configuration/variables/resolve-meta'); variablesMeta = resolveVariablesMeta(configuration); @@ -242,8 +255,8 @@ processSpanPromise = (async () => { if (!commandSchema && providerName === 'aws') { // If command was not recognized in previous resolution phases // parse args again also against schemas commands which require AWS service context + processLog.debug('resolve CLI input (AWS service schema)'); resolveInput.clear(); - ({ command, commands, options, isHelpRequest, commandSchema } = resolveInput( require('../lib/cli/commands-schema/aws-service') )); @@ -251,6 +264,7 @@ processSpanPromise = (async () => { let envVarNamesNeededForDotenvResolution; if (variablesMeta.size) { + processLog.debug('resolve variables in core properties'); // Some properties are configured with variables // Resolve eventual variables in `provider.stage` and `useDotEnv` @@ -297,12 +311,14 @@ processSpanPromise = (async () => { // If command was not recognized in previous resolution phases // Parse args again also against schemas of commands which work in context of an AWS // service + processLog.debug('resolve CLI input (AWS service schema)'); resolveInput.clear(); ({ command, commands, options, isHelpRequest, commandSchema } = resolveInput( require('../lib/cli/commands-schema/aws-service') )); if (commandSchema) { + processLog.debug('resolve variables in core properties #2'); resolverConfiguration.options = filterSupportedOptions(options, { commandSchema, providerName, @@ -330,6 +346,7 @@ processSpanPromise = (async () => { // Assume "env" source fulfilled for `provider.stage` and `useDotenv` resolution. // To pick eventual resolution conflict, track what env variables were reported // misssing when applying this resolution + processLog.debug('resolve variables in stage related properties'); const envSource = require('../lib/configuration/variables/sources/env'); envSource.missingEnvVariables.clear(); await resolveVariables({ @@ -377,6 +394,7 @@ processSpanPromise = (async () => { } } if (!isPropertyResolved(variablesMeta, 'provider\0name')) { + processLog.debug('resolve variables in "provider.name"'); await resolveVariables(resolverConfiguration); if ( eventuallyReportVariableResolutionErrors( @@ -401,6 +419,7 @@ processSpanPromise = (async () => { return; } if (!commandSchema && providerName === 'aws') { + processLog.debug('resolve CLI input (AWS service schema)'); resolveInput.clear(); ({ command, commands, options, isHelpRequest, commandSchema } = resolveInput( require('../lib/cli/commands-schema/aws-service') @@ -415,11 +434,13 @@ processSpanPromise = (async () => { } if (isHelpRequest || commands[0] === 'plugin') { + processLog.debug('resolve variables in "plugins"'); // We do not need full config resolved, we just need to know what // provider is service setup with, and with what eventual plugins Framework is extended // as that influences what CLI commands and options could be used, resolverConfiguration.propertyPathsToResolve.add('plugins'); } else { + processLog.debug('resolve variables in all properties'); delete resolverConfiguration.propertyPathsToResolve; } @@ -453,6 +474,7 @@ processSpanPromise = (async () => { // Ensure to have full AWS commands schema loaded if we're in context of AWS provider // It's not the case if not AWS service specific command was resolved if (configuration && resolveProviderName(configuration) === 'aws') { + processLog.debug('resolve CLI input (AWS service schema)'); resolveInput.clear(); ({ command, commands, options, isHelpRequest, commandSchema } = resolveInput( require('../lib/cli/commands-schema/aws-service') @@ -460,6 +482,8 @@ processSpanPromise = (async () => { } } else { // In non-service context we recognize all AWS service commands + processLog.debug('parsing of configuration file failed'); + processLog.debug('resolve CLI input (AWS service schema)'); resolveInput.clear(); ({ command, commands, options, isHelpRequest, commandSchema } = resolveInput( require('../lib/cli/commands-schema/aws-service') @@ -481,6 +505,7 @@ processSpanPromise = (async () => { if (!isHelpRequest) { if (isStandaloneCommand) { + processLog.debug('run standalone commmand'); if (configuration) require('../lib/cli/ensure-supported-command')(configuration); await require(`../commands/${commands.join('-')}`)({ configuration, @@ -499,6 +524,7 @@ processSpanPromise = (async () => { ); } if (!configuration) { + processLog.debug('run interative onboarding'); const interactiveContext = await require('../lib/cli/interactive-setup')({ configuration, serviceDir, @@ -518,6 +544,7 @@ processSpanPromise = (async () => { } } + processLog.debug('construct Serverless instance'); serverless = new Serverless({ configuration, serviceDir, @@ -531,6 +558,7 @@ processSpanPromise = (async () => { try { serverless.onExitPromise = processSpanPromise; serverless.invocationId = uuid.v4(); + processLog.debug('initialize Serverless instance'); await serverless.init(); // IIFE for maintanance convenience @@ -542,6 +570,7 @@ processSpanPromise = (async () => { // might have defined extra commands and options if (serverless.pluginManager.externalPlugins.size) { + processLog.debug('resolve CLI input (+ plugins schema)'); const commandsSchema = require('../lib/cli/commands-schema/resolve-final')( serverless.pluginManager.externalPlugins, { providerName: providerName || 'aws', configuration } @@ -557,6 +586,7 @@ processSpanPromise = (async () => { } if (!providerName && !hasFinalCommandSchema) { // Invalid configuration, ensure to recognize all AWS commands + processLog.debug('resolve CLI input (AWS service schema)'); resolveInput.clear(); ({ command, commands, options, isHelpRequest, commandSchema } = resolveInput( require('../lib/cli/commands-schema/aws-service') @@ -600,6 +630,7 @@ processSpanPromise = (async () => { // Register AWS provider specific variable sources if (providerName === 'aws') { // Pre-resolve to eventually pick not yet resolved AWS auth related properties + processLog.debug('resolve variables'); await resolveVariables(resolverConfiguration); if (!variablesMeta.size) return; if ( @@ -648,6 +679,7 @@ processSpanPromise = (async () => { ); // Having all source resolvers configured, resolve variables + processLog.debug('resolve all variables'); await resolveVariables(resolverConfiguration); if (!variablesMeta.size) return; if ( @@ -684,8 +716,10 @@ processSpanPromise = (async () => { if (isHelpRequest && serverless.pluginManager.externalPlugins) { // Show help + processLog.debug('render help'); require('../lib/cli/render-help')(serverless.pluginManager.externalPlugins); } else if (isInteractiveSetup) { + processLog.debug('run interactive onboarding'); const interactiveContext = await require('../lib/cli/interactive-setup')({ configuration, serverless, @@ -701,6 +735,7 @@ processSpanPromise = (async () => { serverless = interactiveContext.serverless; } } else { + processLog.debug('run Serverless instance'); // Run command await serverless.run(); } @@ -713,6 +748,7 @@ processSpanPromise = (async () => { await processBackendNotificationRequest(backendNotificationRequest); } } catch (error) { + processLog.debug('handle error'); // If Dashboard Plugin, capture error const dashboardPlugin = serverless.pluginManager.dashboardPlugin; const dashboardErrorHandler = _.get(dashboardPlugin, 'enterprise.errorHandler');