2016-06-23 12:47:54 -04:00
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
|
2017-01-27 16:19:00 -05:00
|
|
|
import {ERROR_ORIGINAL_ERROR, getDebugContext, getOriginalError} from './errors';
|
|
|
|
|
2015-02-16 08:35:27 -05:00
|
|
|
|
2015-03-31 18:47:11 -04:00
|
|
|
/**
|
2016-09-23 18:05:43 -04:00
|
|
|
* @whatItDoes Provides a hook for centralized exception handling.
|
2015-04-14 00:00:52 -04:00
|
|
|
*
|
2016-09-23 18:05:43 -04:00
|
|
|
* @description
|
2015-04-14 00:00:52 -04:00
|
|
|
*
|
2016-09-23 18:05:43 -04:00
|
|
|
* 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.
|
2015-04-14 00:00:52 -04:00
|
|
|
*
|
2016-09-23 18:05:43 -04:00
|
|
|
* ### Example
|
2015-04-14 00:00:52 -04:00
|
|
|
*
|
2016-09-23 18:05:43 -04:00
|
|
|
* ```
|
2016-08-30 21:07:40 -04:00
|
|
|
* class MyErrorHandler implements ErrorHandler {
|
2016-09-23 18:05:43 -04:00
|
|
|
* handleError(error) {
|
2015-04-14 00:00:52 -04:00
|
|
|
* // do something with the exception
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
2016-08-16 14:15:01 -04:00
|
|
|
* @NgModule({
|
2016-08-25 03:50:16 -04:00
|
|
|
* providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
|
2016-08-16 14:15:01 -04:00
|
|
|
* })
|
|
|
|
* class MyModule {}
|
2015-04-14 00:00:52 -04:00
|
|
|
* ```
|
2016-09-23 18:05:43 -04:00
|
|
|
*
|
2016-05-25 18:00:05 -04:00
|
|
|
* @stable
|
2015-03-31 18:47:11 -04:00
|
|
|
*/
|
2016-08-25 03:50:16 -04:00
|
|
|
export class ErrorHandler {
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
_console: Console = console;
|
2015-07-22 20:13:42 -04:00
|
|
|
|
2016-08-26 17:43:42 -04:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
rethrowError: boolean;
|
|
|
|
|
|
|
|
constructor(rethrowError: boolean = true) { this.rethrowError = rethrowError; }
|
2015-07-23 21:00:19 -04:00
|
|
|
|
2016-08-25 03:50:16 -04:00
|
|
|
handleError(error: any): void {
|
|
|
|
this._console.error(`EXCEPTION: ${this._extractMessage(error)}`);
|
2015-07-23 21:00:19 -04:00
|
|
|
|
2017-01-27 16:19:00 -05:00
|
|
|
if (error instanceof Error) {
|
|
|
|
const originalError = this._findOriginalError(error);
|
|
|
|
const originalStack = this._findOriginalStack(error);
|
|
|
|
const context = this._findContext(error);
|
2015-07-23 21:00:19 -04:00
|
|
|
|
2017-01-27 16:19:00 -05:00
|
|
|
if (originalError) {
|
|
|
|
this._console.error(`ORIGINAL EXCEPTION: ${this._extractMessage(originalError)}`);
|
|
|
|
}
|
2015-07-22 20:13:42 -04:00
|
|
|
|
2017-01-27 16:19:00 -05:00
|
|
|
if (originalStack) {
|
|
|
|
this._console.error('ORIGINAL STACKTRACE:');
|
|
|
|
this._console.error(originalStack);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context) {
|
|
|
|
this._console.error('ERROR CONTEXT:');
|
|
|
|
this._console.error(context);
|
|
|
|
}
|
2015-07-22 20:13:42 -04:00
|
|
|
}
|
|
|
|
|
2015-07-23 21:00:19 -04:00
|
|
|
// We rethrow exceptions, so operations like 'bootstrap' will result in an error
|
2016-08-25 03:50:16 -04:00
|
|
|
// when an error happens. If we do not rethrow, bootstrap will always succeed.
|
|
|
|
if (this.rethrowError) throw error;
|
2015-07-23 21:00:19 -04:00
|
|
|
}
|
|
|
|
|
2015-10-09 20:21:25 -04:00
|
|
|
/** @internal */
|
2016-08-25 03:50:16 -04:00
|
|
|
_extractMessage(error: any): string {
|
|
|
|
return error instanceof Error ? error.message : error.toString();
|
2015-09-10 18:25:36 -04:00
|
|
|
}
|
|
|
|
|
2015-10-09 20:21:25 -04:00
|
|
|
/** @internal */
|
2016-08-25 03:50:16 -04:00
|
|
|
_findContext(error: any): any {
|
|
|
|
if (error) {
|
2017-01-27 16:19:00 -05:00
|
|
|
return getDebugContext(error) ? getDebugContext(error) :
|
|
|
|
this._findContext(getOriginalError(error));
|
2015-07-23 21:00:19 -04:00
|
|
|
}
|
2016-09-23 18:05:43 -04:00
|
|
|
|
|
|
|
return null;
|
2015-07-23 21:00:19 -04:00
|
|
|
}
|
|
|
|
|
2015-10-09 20:21:25 -04:00
|
|
|
/** @internal */
|
2017-01-27 16:19:00 -05:00
|
|
|
_findOriginalError(error: Error): any {
|
|
|
|
let e = getOriginalError(error);
|
|
|
|
while (e && getOriginalError(e)) {
|
|
|
|
e = getOriginalError(e);
|
2015-07-23 21:00:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
2015-10-09 20:21:25 -04:00
|
|
|
/** @internal */
|
2017-01-27 16:19:00 -05:00
|
|
|
_findOriginalStack(error: Error): string {
|
2016-09-23 18:05:43 -04:00
|
|
|
let e: any = error;
|
|
|
|
let stack: string = e.stack;
|
2017-01-27 16:19:00 -05:00
|
|
|
while (e instanceof Error && getOriginalError(e)) {
|
|
|
|
e = getOriginalError(e);
|
2016-08-25 03:50:16 -04:00
|
|
|
if (e instanceof Error && e.stack) {
|
|
|
|
stack = e.stack;
|
2015-07-23 21:00:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return stack;
|
2015-02-16 08:35:27 -05:00
|
|
|
}
|
|
|
|
}
|
2017-01-27 16:19:00 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|