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

fix: updates to error handler print format #11311

Merged
merged 4 commits into from
Nov 3, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<typeof stateManager>;
Original file line number Diff line number Diff line change
@@ -77,6 +77,7 @@ describe('execution manager', () => {
assignProjectIdentifier: jest.fn(),
getUsageDataPayload: jest.fn(),
calculatePushNormalizationFactor: jest.fn(),
getSessionUuid: jest.fn(),
};

beforeEach(() => {
1 change: 1 addition & 0 deletions packages/amplify-cli/src/__tests__/test-aborting.test.ts
Original file line number Diff line number Diff line change
@@ -88,6 +88,7 @@ describe('test SIGINT with execute', () => {
assignProjectIdentifier: jest.fn(),
getUsageDataPayload: jest.fn(),
calculatePushNormalizationFactor: jest.fn(),
getSessionUuid: jest.fn(),
};
mockContext.projectHasMobileHubResources = false;

63 changes: 34 additions & 29 deletions packages/amplify-cli/src/amplify-exception-handler.ts
Original file line number Diff line number Diff line change
@@ -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,55 +37,55 @@ export const handleException = async (exception: unknown): Promise<void> => {
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',
);

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);
}
Original file line number Diff line number Diff line change
@@ -53,6 +53,13 @@ export class NoUsageData implements IUsageData, IFlowData {
/* noop */
}

/**
* Noop implementation of getSessionUuid
*/
getSessionUuid(): string {
return '';
}

/**
* Noop implementation of emitError
*/
Original file line number Diff line number Diff line change
@@ -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
*/
Original file line number Diff line number Diff line change
@@ -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;
}

/**