2016-06-23 09:47:54 -07: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
|
|
|
|
*/
|
|
|
|
|
2016-04-28 17:50:03 -07:00
|
|
|
import {BaseWrappedException} from './base_wrapped_exception';
|
|
|
|
import {isListLikeIterable} from './collection';
|
2016-06-08 16:38:52 -07:00
|
|
|
import {isBlank, isPresent} from './lang';
|
2015-07-23 18:00:19 -07:00
|
|
|
|
|
|
|
class _ArrayLogger {
|
|
|
|
res: any[] = [];
|
|
|
|
log(s: any): void { this.res.push(s); }
|
2015-08-24 11:35:27 -07:00
|
|
|
logError(s: any): void { this.res.push(s); }
|
2015-07-23 18:00:19 -07:00
|
|
|
logGroup(s: any): void { this.res.push(s); }
|
|
|
|
logGroupEnd(){};
|
|
|
|
}
|
2015-02-16 14:35:27 +01:00
|
|
|
|
2015-03-31 22:47:11 +00:00
|
|
|
/**
|
2015-04-13 21:00:52 -07:00
|
|
|
* Provides a hook for centralized exception handling.
|
|
|
|
*
|
2015-05-20 09:48:15 -07:00
|
|
|
* The default implementation of `ExceptionHandler` prints error messages to the `Console`. To
|
|
|
|
* intercept error handling,
|
2015-04-13 21:00:52 -07:00
|
|
|
* write a custom exception handler that replaces this default as appropriate for your app.
|
|
|
|
*
|
2015-10-19 15:37:32 +01:00
|
|
|
* ### Example
|
2015-04-13 21:00:52 -07:00
|
|
|
*
|
|
|
|
* ```javascript
|
|
|
|
*
|
|
|
|
* class MyExceptionHandler implements ExceptionHandler {
|
|
|
|
* call(error, stackTrace = null, reason = null) {
|
|
|
|
* // do something with the exception
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
2016-07-14 00:28:08 +10:00
|
|
|
* bootstrap(MyApp, [{provide: ExceptionHandler, useClass: MyExceptionHandler}])
|
2015-07-22 17:13:42 -07:00
|
|
|
*
|
2015-04-13 21:00:52 -07:00
|
|
|
* ```
|
2016-05-25 15:00:05 -07:00
|
|
|
* @stable
|
2015-03-31 22:47:11 +00:00
|
|
|
*/
|
2015-02-16 14:35:27 +01:00
|
|
|
export class ExceptionHandler {
|
2015-09-04 15:09:02 -07:00
|
|
|
constructor(private _logger: any, private _rethrowException: boolean = true) {}
|
2015-07-22 17:13:42 -07:00
|
|
|
|
2015-07-23 18:00:19 -07:00
|
|
|
static exceptionToString(exception: any, stackTrace: any = null, reason: string = null): string {
|
|
|
|
var l = new _ArrayLogger();
|
|
|
|
var e = new ExceptionHandler(l, false);
|
|
|
|
e.call(exception, stackTrace, reason);
|
2016-06-08 16:38:52 -07:00
|
|
|
return l.res.join('\n');
|
2015-07-23 18:00:19 -07:00
|
|
|
}
|
2015-07-22 17:13:42 -07:00
|
|
|
|
2015-07-23 18:00:19 -07:00
|
|
|
call(exception: any, stackTrace: any = null, reason: string = null): void {
|
|
|
|
var originalException = this._findOriginalException(exception);
|
|
|
|
var originalStack = this._findOriginalStack(exception);
|
|
|
|
var context = this._findContext(exception);
|
|
|
|
|
2015-09-10 15:25:36 -07:00
|
|
|
this._logger.logGroup(`EXCEPTION: ${this._extractMessage(exception)}`);
|
2015-07-23 18:00:19 -07:00
|
|
|
|
|
|
|
if (isPresent(stackTrace) && isBlank(originalStack)) {
|
2016-06-08 16:38:52 -07:00
|
|
|
this._logger.logError('STACKTRACE:');
|
2015-09-04 15:09:02 -07:00
|
|
|
this._logger.logError(this._longStackTrace(stackTrace));
|
2015-07-23 18:00:19 -07:00
|
|
|
}
|
2015-07-22 17:13:42 -07:00
|
|
|
|
|
|
|
if (isPresent(reason)) {
|
2015-09-04 15:09:02 -07:00
|
|
|
this._logger.logError(`REASON: ${reason}`);
|
2015-07-23 18:00:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isPresent(originalException)) {
|
2015-09-10 15:25:36 -07:00
|
|
|
this._logger.logError(`ORIGINAL EXCEPTION: ${this._extractMessage(originalException)}`);
|
2015-07-23 18:00:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isPresent(originalStack)) {
|
2016-06-08 16:38:52 -07:00
|
|
|
this._logger.logError('ORIGINAL STACKTRACE:');
|
2015-09-04 15:09:02 -07:00
|
|
|
this._logger.logError(this._longStackTrace(originalStack));
|
2015-07-22 17:13:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isPresent(context)) {
|
2016-06-08 16:38:52 -07:00
|
|
|
this._logger.logError('ERROR CONTEXT:');
|
2015-09-04 15:09:02 -07:00
|
|
|
this._logger.logError(context);
|
2015-07-22 17:13:42 -07:00
|
|
|
}
|
|
|
|
|
2015-09-04 15:09:02 -07:00
|
|
|
this._logger.logGroupEnd();
|
2015-07-23 18:00:19 -07:00
|
|
|
|
|
|
|
// We rethrow exceptions, so operations like 'bootstrap' will result in an error
|
|
|
|
// when an exception happens. If we do not rethrow, bootstrap will always succeed.
|
2015-09-04 15:09:02 -07:00
|
|
|
if (this._rethrowException) throw exception;
|
2015-07-23 18:00:19 -07:00
|
|
|
}
|
|
|
|
|
2015-10-09 17:21:25 -07:00
|
|
|
/** @internal */
|
2015-09-10 15:25:36 -07:00
|
|
|
_extractMessage(exception: any): string {
|
2016-02-25 12:04:59 -08:00
|
|
|
return exception instanceof BaseWrappedException ? exception.wrapperMessage :
|
|
|
|
exception.toString();
|
2015-09-10 15:25:36 -07:00
|
|
|
}
|
|
|
|
|
2015-10-09 17:21:25 -07:00
|
|
|
/** @internal */
|
2015-07-23 18:00:19 -07:00
|
|
|
_longStackTrace(stackTrace: any): any {
|
2016-06-08 16:38:52 -07:00
|
|
|
return isListLikeIterable(stackTrace) ? (<any[]>stackTrace).join('\n\n-----async gap-----\n') :
|
2015-07-27 15:47:42 -07:00
|
|
|
stackTrace.toString();
|
2015-07-22 17:13:42 -07:00
|
|
|
}
|
|
|
|
|
2015-10-09 17:21:25 -07:00
|
|
|
/** @internal */
|
2015-07-22 17:13:42 -07:00
|
|
|
_findContext(exception: any): any {
|
2015-07-23 18:00:19 -07:00
|
|
|
try {
|
2016-02-25 12:04:59 -08:00
|
|
|
if (!(exception instanceof BaseWrappedException)) return null;
|
2015-07-23 18:00:19 -07:00
|
|
|
return isPresent(exception.context) ? exception.context :
|
|
|
|
this._findContext(exception.originalException);
|
|
|
|
} catch (e) {
|
|
|
|
// exception.context can throw an exception. if it happens, we ignore the context.
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-09 17:21:25 -07:00
|
|
|
/** @internal */
|
2015-07-23 18:00:19 -07:00
|
|
|
_findOriginalException(exception: any): any {
|
2016-02-25 12:04:59 -08:00
|
|
|
if (!(exception instanceof BaseWrappedException)) return null;
|
2015-07-23 18:00:19 -07:00
|
|
|
|
|
|
|
var e = exception.originalException;
|
2016-02-25 12:04:59 -08:00
|
|
|
while (e instanceof BaseWrappedException && isPresent(e.originalException)) {
|
2015-07-23 18:00:19 -07:00
|
|
|
e = e.originalException;
|
|
|
|
}
|
|
|
|
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
2015-10-09 17:21:25 -07:00
|
|
|
/** @internal */
|
2015-07-23 18:00:19 -07:00
|
|
|
_findOriginalStack(exception: any): any {
|
2016-02-25 12:04:59 -08:00
|
|
|
if (!(exception instanceof BaseWrappedException)) return null;
|
2015-07-23 18:00:19 -07:00
|
|
|
|
|
|
|
var e = exception;
|
|
|
|
var stack = exception.originalStack;
|
2016-02-25 12:04:59 -08:00
|
|
|
while (e instanceof BaseWrappedException && isPresent(e.originalException)) {
|
2015-07-23 18:00:19 -07:00
|
|
|
e = e.originalException;
|
2016-02-25 12:04:59 -08:00
|
|
|
if (e instanceof BaseWrappedException && isPresent(e.originalException)) {
|
2015-07-23 18:00:19 -07:00
|
|
|
stack = e.originalStack;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return stack;
|
2015-02-16 14:35:27 +01:00
|
|
|
}
|
|
|
|
}
|