2015-05-20 12:48:15 -04:00
|
|
|
import {Injectable} from 'angular2/di';
|
2015-07-23 21:00:19 -04:00
|
|
|
import {isPresent, isBlank, print, BaseException} from 'angular2/src/facade/lang';
|
2015-02-16 08:35:27 -05:00
|
|
|
import {ListWrapper, isListLikeIterable} from 'angular2/src/facade/collection';
|
2015-07-23 21:00:19 -04:00
|
|
|
|
|
|
|
class _ArrayLogger {
|
|
|
|
res: any[] = [];
|
|
|
|
log(s: any): void { this.res.push(s); }
|
|
|
|
logGroup(s: any): void { this.res.push(s); }
|
|
|
|
logGroupEnd(){};
|
|
|
|
}
|
2015-02-16 08:35:27 -05:00
|
|
|
|
2015-03-31 18:47:11 -04:00
|
|
|
/**
|
2015-04-14 00:00:52 -04:00
|
|
|
* Provides a hook for centralized exception handling.
|
|
|
|
*
|
2015-05-20 12:48:15 -04:00
|
|
|
* The default implementation of `ExceptionHandler` prints error messages to the `Console`. To
|
|
|
|
* intercept error handling,
|
2015-04-14 00:00:52 -04:00
|
|
|
* write a custom exception handler that replaces this default as appropriate for your app.
|
|
|
|
*
|
|
|
|
* # Example
|
|
|
|
*
|
|
|
|
* ```javascript
|
|
|
|
*
|
|
|
|
* class MyExceptionHandler implements ExceptionHandler {
|
|
|
|
* call(error, stackTrace = null, reason = null) {
|
|
|
|
* // do something with the exception
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
2015-07-22 20:13:42 -04:00
|
|
|
* bootstrap(MyApp, [bind(ExceptionHandler).toClass(MyExceptionHandler)])
|
|
|
|
*
|
2015-04-14 00:00:52 -04:00
|
|
|
* ```
|
2015-03-31 18:47:11 -04:00
|
|
|
*/
|
2015-03-16 17:44:14 -04:00
|
|
|
@Injectable()
|
2015-02-16 08:35:27 -05:00
|
|
|
export class ExceptionHandler {
|
2015-07-23 21:00:19 -04:00
|
|
|
constructor(private logger: any, private rethrowException: boolean = true) {}
|
2015-07-22 20:13:42 -04:00
|
|
|
|
2015-07-23 21:00:19 -04: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);
|
|
|
|
return l.res.join("\n");
|
|
|
|
}
|
2015-07-22 20:13:42 -04:00
|
|
|
|
2015-07-23 21:00:19 -04: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);
|
|
|
|
|
|
|
|
this.logger.logGroup(`EXCEPTION: ${exception}`);
|
|
|
|
|
|
|
|
if (isPresent(stackTrace) && isBlank(originalStack)) {
|
|
|
|
this.logger.log("STACKTRACE:");
|
|
|
|
this.logger.log(this._longStackTrace(stackTrace))
|
|
|
|
}
|
2015-07-22 20:13:42 -04:00
|
|
|
|
|
|
|
if (isPresent(reason)) {
|
2015-07-23 21:00:19 -04:00
|
|
|
this.logger.log(`REASON: ${reason}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isPresent(originalException)) {
|
|
|
|
this.logger.log(`ORIGINAL EXCEPTION: ${originalException}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isPresent(originalStack)) {
|
|
|
|
this.logger.log("ORIGINAL STACKTRACE:");
|
|
|
|
this.logger.log(this._longStackTrace(originalStack));
|
2015-07-22 20:13:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isPresent(context)) {
|
2015-07-23 21:00:19 -04:00
|
|
|
this.logger.log("ERROR CONTEXT:");
|
|
|
|
this.logger.log(context);
|
2015-07-22 20:13:42 -04:00
|
|
|
}
|
|
|
|
|
2015-07-23 21:00:19 -04:00
|
|
|
this.logger.logGroupEnd();
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
if (this.rethrowException) throw exception;
|
|
|
|
}
|
|
|
|
|
|
|
|
_longStackTrace(stackTrace: any): any {
|
|
|
|
return isListLikeIterable(stackTrace) ? (<any>stackTrace).join("\n\n-----async gap-----\n") :
|
|
|
|
stackTrace;
|
2015-07-22 20:13:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
_findContext(exception: any): any {
|
2015-07-23 21:00:19 -04:00
|
|
|
try {
|
|
|
|
if (!(exception instanceof BaseException)) return null;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_findOriginalException(exception: any): any {
|
2015-07-22 20:13:42 -04:00
|
|
|
if (!(exception instanceof BaseException)) return null;
|
2015-07-23 21:00:19 -04:00
|
|
|
|
|
|
|
var e = exception.originalException;
|
|
|
|
while (e instanceof BaseException && isPresent(e.originalException)) {
|
|
|
|
e = e.originalException;
|
|
|
|
}
|
|
|
|
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
_findOriginalStack(exception: any): any {
|
|
|
|
if (!(exception instanceof BaseException)) return null;
|
|
|
|
|
|
|
|
var e = exception;
|
|
|
|
var stack = exception.originalStack;
|
|
|
|
while (e instanceof BaseException && isPresent(e.originalException)) {
|
|
|
|
e = e.originalException;
|
|
|
|
if (e instanceof BaseException && isPresent(e.originalException)) {
|
|
|
|
stack = e.originalStack;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return stack;
|
2015-02-16 08:35:27 -05:00
|
|
|
}
|
|
|
|
}
|