Skip to content

Commit

Permalink
fix: provide generic exception handling functionality
Browse files Browse the repository at this point in the history
Introduce a log helper with static functions to get exception message /
exception stack whatever is thrown or provided.

Closes: hyperledger#1702
Signed-off-by: Michael Courtin <michael.courtin@accenture.com>
  • Loading branch information
m-courtin authored and Leeyoungone committed Jan 13, 2022
1 parent 81570f5 commit f9213f6
Show file tree
Hide file tree
Showing 4 changed files with 408 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
Bools,
Logger,
LoggerProvider,
LogHelper,
Servers,
} from "@hyperledger/cactus-common";

Expand Down Expand Up @@ -241,7 +242,8 @@ export class ApiServer {

return { addressInfoCockpit, addressInfoApi, addressInfoGrpc };
} catch (ex) {
const errorMessage = `Failed to start ApiServer: ${ex.stack}`;
const stack = LogHelper.getExceptionStack(ex);
const errorMessage = `Failed to start ApiServer: ${stack}`;
this.log.error(errorMessage);
this.log.error(`Attempting shutdown...`);
try {
Expand Down Expand Up @@ -296,9 +298,10 @@ export class ApiServer {
await this.getPluginImportsCount(),
);
return this.pluginRegistry;
} catch (e) {
} catch (ex) {
this.pluginRegistry = new PluginRegistry({ plugins: [] });
const errorMessage = `Failed init PluginRegistry: ${e.stack}`;
const stack = LogHelper.getExceptionStack(ex);
const errorMessage = `Failed init PluginRegistry: ${stack}`;
this.log.error(errorMessage);
throw new Error(errorMessage);
}
Expand Down
100 changes: 100 additions & 0 deletions packages/cactus-common/src/main/typescript/logging/log-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { RuntimeError } from "run-time-error";

export class LogHelper {
public static getExceptionStack(exception: unknown): string {
// handle unknown exception input
const defaultStack = "NO_STACK_INFORMATION_INCLUDED_IN_EXCEPTION";
const invalidStack = "INVALID_STACK_INFORMATION";
let stack = defaultStack;
let exceptionHandled = false;

// 1st need to check that exception is not null or undefined before trying to access the wanted stack information
if (exception) {
if (exception instanceof RuntimeError) {
// handling RuntimeError stack inclusive nested / cascaded stacks
stack = this.safeJsonStringify(exception);
exceptionHandled = true;
}

if (!exceptionHandled && typeof exception === "object") {
// 2nd need to check if a stack property is available
if (Object.hasOwnProperty.call(exception, "stack")) {
// 3rd check if the stack property is already of type string
if (
typeof (exception as Record<string, unknown>).stack === "string"
) {
stack = (exception as { stack: string }).stack;
} else {
// need to stringify stack information first
stack = this.safeJsonStringify(
(exception as { stack: unknown }).stack,
invalidStack,
);
}
}
}
}
return stack;
}

public static getExceptionMessage(exception: unknown): string {
// handle unknown exception input
const defaultMessage = "NO_MESSAGE_INCLUDED_IN_EXCEPTION";
const invalidException = "INVALID_EXCEPTION";
const invalidMessage = "INVALID_EXCEPTION_MESSAGE";
const customExceptionPrefix = "A CUSTOM EXCEPTION WAS THROWN: ";
let message = defaultMessage;
let exceptionHandled = false;

// 1st need to check that exception is not null or undefined before trying to access the wanted message information
if (exception) {
if (typeof exception === "object") {
// 2nd need to check if a message property is available
if (Object.hasOwnProperty.call(exception, "message")) {
// 3rd check if the message property is already of type string
if (
typeof (exception as Record<string, unknown>).message === "string"
) {
message = (exception as { message: string }).message;
} else {
// need to stringify message information first
message = this.safeJsonStringify(
(exception as { message: unknown }).message,
invalidMessage,
);
}
exceptionHandled = true;
}
}

// handling of custom exceptions
if (!exceptionHandled) {
// check if thrown custom exception is a string type only -> directly use it as exception message
if (typeof exception === "string") {
message = exception;
} else {
// custom exception is of a different type -> need to stringify it
message =
customExceptionPrefix &&
this.safeJsonStringify(exception, invalidException);
}
}
}
return message;
}

private static safeJsonStringify(
input: unknown,
catchMessage = "INVALID_INPUT",
): string {
let message = "";

try {
message = JSON.stringify(input);
} catch (error) {
// stringify failed maybe due to cyclic dependency
message = catchMessage;
}
return message;
}
}
1 change: 1 addition & 0 deletions packages/cactus-common/src/main/typescript/public-api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { LoggerProvider } from "./logging/logger-provider";
export { LogHelper } from "./logging/log-helper";
export { Logger, ILoggerOptions } from "./logging/logger";
export { LogLevelDesc } from "loglevel";
export { Objects } from "./objects";
Expand Down
Loading

0 comments on commit f9213f6

Please sign in to comment.