|
| 1 | +include ../_util-fns |
| 2 | + |
| 3 | +a(id='top') |
| 4 | +:marked |
| 5 | + When Angular executes the vast majority of our application code, it does so within the |
| 6 | + context of a `try-catch` block. And, when it catches errors, it sends them to the |
| 7 | + default `ExceptionHandler` which, in turn, logs them to the browser console. This is |
| 8 | + great for debugging in our development environment; but, in a production setting, it |
| 9 | + would be helpful to track these errors more explicitly. To do this, we can implement a |
| 10 | + custom exception handler class. |
| 11 | + |
| 12 | +:marked |
| 13 | + **See the [live example](/resources/live-examples/cb-exception-handler/ts/plnkr.html)**. |
| 14 | + |
| 15 | +:marked |
| 16 | + First though, let's think about what we might want to do with errors in a production |
| 17 | + environment. Perhaps we want to `POST` them, over HTTP, to our server for logging. Or, |
| 18 | + maybe we're using a client-side error-tracking service like New Relic, TrackJS, or |
| 19 | + Raygun. We can create an `ErrorLoggingService` class that is responsible for routing |
| 20 | + errors to different destinations: |
| 21 | + |
| 22 | ++makeExample('cb-exception-handler/ts/app/error-logging.service.ts', 'class', 'app/error-logging.service.ts')(format='.') |
| 23 | + |
| 24 | +:marked |
| 25 | + Once we have this error-logging class, we can start piping errors into it through the |
| 26 | + use of a custom exception handler. Since the entire Angular platform depends on proper |
| 27 | + exception handling, we have to override the `ExceptionHandler` in the providers of our |
| 28 | + **application module**. To do this, we have to associate our custom exception handler |
| 29 | + class — `CustomExceptionHandler` — with the core `ExceptionHandler` |
| 30 | + dependency-injection (DI) token. This way, when the Angular internals request an |
| 31 | + instance of `ExceptionHandler`, they will be provided with an instance of our |
| 32 | + `CustomExceptionHandler`. |
| 33 | + |
| 34 | ++makeExample('cb-exception-handler/ts/app/app.module.ts', '', 'app/app.module.ts (root module for bootstrapping)')(format='.') |
| 35 | + |
| 36 | +:marked |
| 37 | + The default `ExceptionHandler` service only has one public method, `.call()`. As such, |
| 38 | + our custom exception handler only has to implement the `.call()` method. Inside this |
| 39 | + `.call()` method, we're going to log the errors to the console and send them over to |
| 40 | + the `ErrorLoggingService` instance. |
| 41 | + |
| 42 | ++makeExample('cb-exception-handler/ts/app/custom-exception-handler.ts', 'class', 'app/custom-exception-handler.ts')(format='.') |
| 43 | + |
| 44 | +:marked |
| 45 | + When Angular passes an error into the application exception handler, it doesn't |
| 46 | + necessarily pass-in the raw error object — it may pass-in a wrapped error. This |
| 47 | + is _not a documented behavior_; but, if we look at the source code for the core |
| 48 | + `ExceptionHandler` class, we can see that it does this. As such, in our custom |
| 49 | + exception handler, we attempt to unwrap the root error — traversing the |
| 50 | + `.originalException` object path — before sending it to the |
| 51 | + `ErrorLoggingService`. |
| 52 | + |
| 53 | +:marked |
| 54 | + At this point, we've overridden the core `ExceptionHandler` and laid the ground-work |
| 55 | + for powerful error logging. Now, we just need to `throw()` an error in our application |
| 56 | + and confirm that it's being seen by both the `CustomExceptionHandler` and the |
| 57 | + `ErrorLoggingService` classes |
| 58 | + |
| 59 | ++makeExample('cb-exception-handler/ts/app/app.component.ts', 'component', 'app/app.component.ts')(format='.') |
| 60 | + |
| 61 | +:marked |
| 62 | + When we run this application and trigger an error, we can see it getting logged to the |
| 63 | + console by both the custom exception handler and our error-logging service: |
| 64 | + |
| 65 | +figure.image-display |
| 66 | + img(src='/resources/images/cookbooks/custom-exception-handler/custom-exception-handler-animation.gif' alt='Custom exception handler in Angular2.') |
| 67 | + |
| 68 | +:marked |
| 69 | + Here's the complete solution: |
| 70 | + |
| 71 | ++makeTabs( |
| 72 | + ` |
| 73 | + cb-exception-handler/ts/app/main.ts, |
| 74 | + cb-exception-handler/ts/app/app.module.ts, |
| 75 | + cb-exception-handler/ts/app/custom-exception-handler.ts, |
| 76 | + cb-exception-handler/ts/app/error-logging.service.ts, |
| 77 | + cb-exception-handler/ts/app/app.component.ts |
| 78 | + `, |
| 79 | + '', |
| 80 | + ` |
| 81 | + main.ts, |
| 82 | + app.module.ts, |
| 83 | + custom-exception-handler.ts, |
| 84 | + error-logging.service.ts, |
| 85 | + app.component.ts |
| 86 | + ` |
| 87 | +) |
| 88 | + |
| 89 | +:marked |
| 90 | + [Back to top](#top) |
0 commit comments