Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit ade77e8

Browse files
bennadelFoxandxss
authored andcommitted
Custom exception handler service cookbook.
This cookbook demonstrates how to override the core `ExceptionHandler` class with a custom service class that both logs to the console as well as sending errors to a robust error-logginer service. This error-logging service can, in turn, send errors to the server; or, to Software-as-a-Service (SaaS) products like New Relic, TrackJS, and Raygun.
1 parent 5fd6ae3 commit ade77e8

File tree

13 files changed

+330
-0
lines changed

13 files changed

+330
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='../_protractor/e2e.d.ts' />
2+
'use strict';
3+
// gulp run-e2e-tests --filter=cb-exception-handler
4+
describe('Handle exceptions', function() {
5+
6+
beforeAll(function () {
7+
browser.get('');
8+
});
9+
10+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// #docplaster
2+
// #docregion
3+
import { Component } from '@angular/core';
4+
5+
// #docregion component
6+
@Component({
7+
selector: 'my-app',
8+
template:
9+
`
10+
<p>
11+
<a (click)="throwError()">Throw an Error</a> <em>(and watch console)</em>.
12+
</p>
13+
`
14+
})
15+
// #docregion class
16+
export class AppComponent {
17+
constructor() {}
18+
19+
public throwError() {
20+
throw(new Error('No Disassemble!'));
21+
}
22+
}
23+
// #enddocregion class
24+
// #enddocregion component
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// #docregion
2+
import { BrowserModule } from '@angular/platform-browser';
3+
import { ExceptionHandler } from '@angular/core';
4+
import { NgModule } from '@angular/core';
5+
6+
import { AppComponent } from './app.component';
7+
import { CustomExceptionHandler } from './custom-exception-handler';
8+
import { ErrorLoggingService } from './error-logging.service';
9+
10+
// #docregion module
11+
@NgModule({
12+
imports: [ BrowserModule ],
13+
providers: [
14+
ErrorLoggingService,
15+
16+
// In order to override the default ExceptionHandler service, we have to provide our
17+
// custom implementation as part of the application module - if we try to do this
18+
// later on, in the App component, it will be too late.
19+
{
20+
provide: ExceptionHandler,
21+
useClass: CustomExceptionHandler
22+
}
23+
],
24+
declarations: [ AppComponent ],
25+
bootstrap: [ AppComponent ]
26+
})
27+
export class AppModule { }
28+
// #enddocregion module
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// #docregion
2+
import { ExceptionHandler } from '@angular/core';
3+
import { Injectable } from '@angular/core';
4+
5+
import { ErrorLoggingService } from './error-logging.service';
6+
7+
// #docregion class
8+
@Injectable()
9+
export class CustomExceptionHandler {
10+
private errorLogggingService: ErrorLoggingService;
11+
12+
constructor(errorLogggingService: ErrorLoggingService) {
13+
this.errorLogggingService = errorLogggingService;
14+
}
15+
16+
// Public methods.
17+
18+
public call(exception: any, stackTrace?: any, reason?: string) {
19+
this.logToConsole(exception, stackTrace, reason);
20+
21+
try {
22+
// Internally, Angular wraps Error objects inside a proxy; therefore, when we
23+
// send the error to the logging service, we want to try and unwrap the error
24+
// first so that we're more likely to send-over a native Error object.
25+
// --
26+
// CAUTION: This is NOT A DOCUMENTED BEHAVIOR - you have to look at the Angular
27+
// source code in order to see that this happens.
28+
this.errorLogggingService.log(this.unwrapError(exception));
29+
} catch (loggingError) {
30+
this.logToConsole(loggingError);
31+
}
32+
}
33+
34+
// Private methods.
35+
36+
private logToConsole(exception: any, stackTrace?: any, reason?: string) {
37+
// Even though we are replacing the core _instance_ of the ExceptionHandler, we can
38+
// still leverage the core class' static method for stringification of the error.
39+
let stringified = ExceptionHandler.exceptionToString(exception, stackTrace, reason);
40+
41+
if (console && console.group && console.log) {
42+
console.group('Custom Exception Handler');
43+
console.log(stringified);
44+
console.groupEnd();
45+
}
46+
}
47+
48+
private unwrapError(exception: any): any {
49+
while (exception.originalException) {
50+
exception = exception.originalException;
51+
}
52+
return(exception);
53+
}
54+
}
55+
// #enddocregion class
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// #docplaster
2+
// #docregion
3+
import { Injectable } from '@angular/core';
4+
5+
// #docregion class
6+
@Injectable()
7+
export class ErrorLoggingService {
8+
constructor() {}
9+
10+
// Public methods.
11+
12+
public log(error: any) {
13+
// Internal tracking.
14+
this.sendToConsole(error);
15+
this.sendToServer(error);
16+
17+
// Software-as-a-Service (SaaS) tracking.
18+
this.sendToNewRelic(error);
19+
this.sendToRaygun(error);
20+
this.sendToRollbar(error);
21+
this.sendToTrackJs(error);
22+
}
23+
24+
// Private methods.
25+
26+
private sendToConsole(error: any) {
27+
if (console && console.group && console.error) {
28+
console.group('Error Logging Service');
29+
console.error(error);
30+
console.groupEnd();
31+
}
32+
}
33+
34+
private sendToRollbar(error: any) {
35+
// Example: Rollbar.error(error);
36+
}
37+
38+
private sendToNewRelic(error: any) {
39+
// Example: newrelic.noticeError(error);
40+
}
41+
42+
private sendToRaygun(error: any) {
43+
// Example: Raygun.send(error);
44+
}
45+
46+
private sendToServer(error: any) {
47+
// ... use http service to send error to your own server.
48+
}
49+
50+
private sendToTrackJs(error: any) {
51+
// Example: trackJs.track(error);
52+
}
53+
}
54+
// #enddocregion class
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* tslint:disable */
2+
// #docregion
3+
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
4+
5+
import { AppModule } from './app.module';
6+
7+
platformBrowserDynamic().bootstrapModule(AppModule);

public/docs/_examples/cb-exception-handler/ts/example-config.json

Whitespace-only changes.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
7+
<title>
8+
Custom Exception Handler Service
9+
</title>
10+
11+
<!-- #docregion style -->
12+
<link rel="stylesheet" type="text/css" href="styles.css">
13+
<link rel="stylesheet" type="text/css" href="sample.css">
14+
<!-- #enddocregion style -->
15+
16+
<!-- Polyfill(s) for older browsers -->
17+
<script src="node_modules/core-js/client/shim.min.js"></script>
18+
19+
<script src="node_modules/zone.js/dist/zone.js"></script>
20+
<script src="node_modules/reflect-metadata/Reflect.js"></script>
21+
<script src="node_modules/systemjs/dist/system.src.js"></script>
22+
23+
<script src="systemjs.config.js"></script>
24+
<script>
25+
System.import('app')
26+
.then(function() {
27+
console.info('System.js loaded your application module.')
28+
})
29+
.catch(function(err) {
30+
console.error(err);
31+
});
32+
</script>
33+
</head>
34+
<body>
35+
36+
<h1>
37+
Custom Exception Handler Service
38+
</h1>
39+
40+
<my-app>Loading app...</my-app>
41+
42+
</body>
43+
</html>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"description": "Custom Exception Handler In Angular 2",
3+
"files": [
4+
"!**/*.d.ts",
5+
"!**/*.js",
6+
"!**/*.[1].*"
7+
],
8+
"tags": [ "cookbook" ]
9+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
a {
2+
color: #369 ;
3+
cursor: pointer ;
4+
text-decoration: underline ;
5+
}

0 commit comments

Comments
 (0)