diff --git a/packages/amplify-cli/src/__tests__/context-manager.test.ts b/packages/amplify-cli/src/__tests__/context-manager.test.ts index 82785cd268d..c0f19504c88 100644 --- a/packages/amplify-cli/src/__tests__/context-manager.test.ts +++ b/packages/amplify-cli/src/__tests__/context-manager.test.ts @@ -55,6 +55,7 @@ describe('test attachUsageData', () => { assignProjectIdentifier: jest.fn(), getUsageDataPayload: jest.fn(), calculatePushNormalizationFactor: jest.fn(), + getSessionUuid: jest.fn(), }; const stateManagerMocked = stateManager as jest.Mocked; diff --git a/packages/amplify-cli/src/__tests__/execution-manager.test.ts b/packages/amplify-cli/src/__tests__/execution-manager.test.ts index d5f1beb70b6..6842b10a29c 100644 --- a/packages/amplify-cli/src/__tests__/execution-manager.test.ts +++ b/packages/amplify-cli/src/__tests__/execution-manager.test.ts @@ -77,6 +77,7 @@ describe('execution manager', () => { assignProjectIdentifier: jest.fn(), getUsageDataPayload: jest.fn(), calculatePushNormalizationFactor: jest.fn(), + getSessionUuid: jest.fn(), }; beforeEach(() => { diff --git a/packages/amplify-cli/src/__tests__/test-aborting.test.ts b/packages/amplify-cli/src/__tests__/test-aborting.test.ts index 9ecb7712de8..843da006551 100644 --- a/packages/amplify-cli/src/__tests__/test-aborting.test.ts +++ b/packages/amplify-cli/src/__tests__/test-aborting.test.ts @@ -88,6 +88,7 @@ describe('test SIGINT with execute', () => { assignProjectIdentifier: jest.fn(), getUsageDataPayload: jest.fn(), calculatePushNormalizationFactor: jest.fn(), + getSessionUuid: jest.fn(), }; mockContext.projectHasMobileHubResources = false; diff --git a/packages/amplify-cli/src/amplify-exception-handler.ts b/packages/amplify-cli/src/amplify-exception-handler.ts index 4be1d157865..f1d5484abd5 100644 --- a/packages/amplify-cli/src/amplify-exception-handler.ts +++ b/packages/amplify-cli/src/amplify-exception-handler.ts @@ -7,7 +7,7 @@ import { HooksMeta, } from 'amplify-cli-core'; import { logger } from 'amplify-cli-logger'; -import { AmplifyPrinter, printer, isDebug } from 'amplify-prompts'; +import { AmplifyPrinter, printer } from 'amplify-prompts'; import { reportError } from './commands/diagnose'; import { isHeadlessCommand } from './context-manager'; import { Context } from './domain/context'; @@ -37,48 +37,40 @@ export const handleException = async (exception: unknown): Promise => { amplifyException = genericErrorToAmplifyException(exception); } + const deepestException = getDeepestAmplifyException(amplifyException); + if (context && isHeadlessCommand(context)) { + printHeadlessAmplifyException(deepestException); + } else { + printAmplifyException(deepestException); + } + if (context?.usageData) { await executeSafely( - () => context?.usageData.emitError(amplifyException), 'Failed to emit error to usage data', + () => { + context?.usageData.emitError(deepestException); + printer.blankLine(); + printer.info(`Session Identifier: ${context?.usageData.getSessionUuid()}`); + }, 'Failed to emit error to usage data', ); } - if (context && isHeadlessCommand(context)) { - printHeadlessAmplifyException(amplifyException); - } else { - printAmplifyException(amplifyException); - - let { downstreamException } = amplifyException; - while (isDebug && downstreamException) { - printer.blankLine(); - - if (downstreamException instanceof AmplifyException) { - printAmplifyException(downstreamException); - downstreamException = downstreamException.downstreamException; - } else { - printError(downstreamException); - downstreamException = undefined; - } - } - } - // Swallow and continue if any operations fail if (context) { - await executeSafely(() => reportError(context, amplifyException), 'Failed to report error'); + await executeSafely(() => reportError(context, deepestException), 'Failed to report error'); } await executeSafely( () => executeHooks(HooksMeta.getInstance(undefined, 'post', { - message: amplifyException.message ?? 'undefined error in Amplify process', - stack: amplifyException.stack ?? 'undefined error stack', + message: deepestException.message ?? 'undefined error in Amplify process', + stack: deepestException.stack ?? 'undefined error stack', })), 'Failed to execute hooks', ); await executeSafely( () => logger.logError({ - message: amplifyException.message, - error: amplifyException, + message: deepestException.message, + error: deepestException, }), 'Failed to log error', ); @@ -86,6 +78,14 @@ export const handleException = async (exception: unknown): Promise => { process.exitCode = 1; }; +const getDeepestAmplifyException = (amplifyException: AmplifyException): AmplifyException => { + let deepestAmplifyException = amplifyException; + while (deepestAmplifyException.downstreamException && deepestAmplifyException.downstreamException instanceof AmplifyException) { + deepestAmplifyException = deepestAmplifyException.downstreamException; + } + return deepestAmplifyException; +}; + /** * Utility function to ensure a passed in function does not invoke the exception handler to avoid an infinite loop * @@ -117,15 +117,20 @@ const printAmplifyException = (amplifyException: AmplifyException): void => { if (link) { printer.info(`Learn more at: ${link}`); } - printer.blankLine(); + if (stack) { + printer.debug(''); printer.debug(stack); } + + if (amplifyException.downstreamException) { + printError(amplifyException.downstreamException); + } }; const printError = (err: Error): void => { - printer.error(err.message); - printer.blankLine(); + printer.debug(''); + printer.debug(err.message); if (err.stack) { printer.debug(err.stack); } diff --git a/packages/amplify-cli/src/domain/amplify-usageData/NoUsageData.ts b/packages/amplify-cli/src/domain/amplify-usageData/NoUsageData.ts index 5df1b1f01a7..d0f00e4a928 100644 --- a/packages/amplify-cli/src/domain/amplify-usageData/NoUsageData.ts +++ b/packages/amplify-cli/src/domain/amplify-usageData/NoUsageData.ts @@ -53,6 +53,13 @@ export class NoUsageData implements IUsageData, IFlowData { /* noop */ } + /** + * Noop implementation of getSessionUuid + */ + getSessionUuid(): string { + return ''; + } + /** * Noop implementation of emitError */ diff --git a/packages/amplify-cli/src/domain/amplify-usageData/UsageData.ts b/packages/amplify-cli/src/domain/amplify-usageData/UsageData.ts index 8c68992a147..a689fb53ec2 100644 --- a/packages/amplify-cli/src/domain/amplify-usageData/UsageData.ts +++ b/packages/amplify-cli/src/domain/amplify-usageData/UsageData.ts @@ -83,6 +83,13 @@ export class UsageData implements IUsageData { return UsageData.instance; } + /** + * returns current sessionUuid + */ + getSessionUuid(): string { + return this.sessionUuid; + } + /** * Emit usage data on error */ diff --git a/packages/amplify-cli/src/domain/amplify-usageData/UsageDataTypes.ts b/packages/amplify-cli/src/domain/amplify-usageData/UsageDataTypes.ts index 1f5af4ffed0..d1f0abd3c1b 100644 --- a/packages/amplify-cli/src/domain/amplify-usageData/UsageDataTypes.ts +++ b/packages/amplify-cli/src/domain/amplify-usageData/UsageDataTypes.ts @@ -21,6 +21,7 @@ interface IUsageMetricsData { startCodePathTimer: (codePath: StartableTimedCodePath) => void; stopCodePathTimer: (codePath: StoppableTimedCodePath) => void; calculatePushNormalizationFactor: (events: { StackId: string, PhysicalResourceId: string } [], StackId: string) => void; + getSessionUuid: () => string; } /**