DEV Community

Raghav Garg
Raghav Garg

Posted on

Angular Universal, add Error Logger like Sentry.

This article primarily focuses on how to capture production errors of Angular Universal app. We will be using Sentry as the example module for capturing the errors on both the platforms client and server.

The main thing to focus here is the SDK provided by Sentry for client and server are different. Also, the server’s SDK should never be loaded on the client because it will not be able to find any node modules on the browser.

To load client SDK we will use app.module.ts (This file runs on both the platform)

To load server SDK we will use app.server.module.ts (This file runs only on the server, so we will be sure that our server SDK is only loading on the server)

This is how our own implementation of common ErrorLogger will look like.

// error-logger.ts

import { ErrorHandler } from '@angular/core';
import { environment } from '../environments/environment';

export class ErrorLogger implements ErrorHandler {

    static initWith(sentry: any) {
        return () => new ErrorLogger(sentry);
    }

    constructor(private sentry: any) {
        if (environment.production) {
            this.sentry.init({ dsn: environment.sentryDsn });
        }
    }

    handleError(error: any): void {
        if (environment.production) {
            this.sentry.captureException(error.originalError || error);
        }
        throw error; // for default behaviour rather than silentely dying
    }
}

Now, to override the default behavior for error handling of Angular, we need to add a provider ErrorHandler with our own custom implementation. We will use useFactory to create an instance of our ErrorLogger with the correct SDK provided from *.module.ts like:

// app.module.ts

import { ..., ErrorHandler } from '@angular/core';
import * as SentryBrowser from '@sentry/browser'; // browser SDK

import { ErrorLogger } from './error-logger';

...
providers: [
  ...
  { provide: ErrorHandler, useFactory: ErrorLogger.initWith(SentryBrowser) }
]
// app.server.module.ts

import { ..., ErrorHandler } from '@angular/core';
import * as SentryNode from '@sentry/node'; // server SDK, should not load on browser

import { ErrorLogger } from './error-logger';

...
providers: [
  ...
  { provide: ErrorHandler, useFactory: ErrorLogger.initWith(SentryNode) }
]

The static initWith method will act as a factory and returns the instance of our custom ErrorLogger but with correct Sentry, SDK initiated according to the platform.

Hope, it helps someone. :)

Top comments (0)