/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import {ERROR_ORIGINAL_ERROR, getDebugContext, getOriginalError} from './errors'; /** * @whatItDoes Provides a hook for centralized exception handling. * * @description * * The default implementation of `ErrorHandler` prints error messages to the `console`. To * intercept error handling, write a custom exception handler that replaces this default as * appropriate for your app. * * ### Example * * ``` * class MyErrorHandler implements ErrorHandler { * handleError(error) { * // do something with the exception * } * } * * @NgModule({ * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}] * }) * class MyModule {} * ``` * * @stable */ export class ErrorHandler { /** * @internal */ _console: Console = console; /** * @internal */ rethrowError: boolean; constructor(rethrowError: boolean = true) { this.rethrowError = rethrowError; } handleError(error: any): void { this._console.error(`EXCEPTION: ${this._extractMessage(error)}`); if (error instanceof Error) { const originalError = this._findOriginalError(error); const originalStack = this._findOriginalStack(error); const context = this._findContext(error); if (originalError) { this._console.error(`ORIGINAL EXCEPTION: ${this._extractMessage(originalError)}`); } if (originalStack) { this._console.error('ORIGINAL STACKTRACE:'); this._console.error(originalStack); } if (context) { this._console.error('ERROR CONTEXT:'); this._console.error(context); } } // We rethrow exceptions, so operations like 'bootstrap' will result in an error // when an error happens. If we do not rethrow, bootstrap will always succeed. if (this.rethrowError) throw error; } /** @internal */ _extractMessage(error: any): string { return error instanceof Error ? error.message : error.toString(); } /** @internal */ _findContext(error: any): any { if (error) { return getDebugContext(error) ? getDebugContext(error) : this._findContext(getOriginalError(error)); } return null; } /** @internal */ _findOriginalError(error: Error): any { let e = getOriginalError(error); while (e && getOriginalError(e)) { e = getOriginalError(e); } return e; } /** @internal */ _findOriginalStack(error: Error): string { let e: any = error; let stack: string = e.stack; while (e instanceof Error && getOriginalError(e)) { e = getOriginalError(e); if (e instanceof Error && e.stack) { stack = e.stack; } } return stack; } } export function wrappedError(message: string, originalError: any): Error { const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message: originalError }`; const error = Error(msg); (error as any)[ERROR_ORIGINAL_ERROR] = originalError; return error; }