Monitoring Live Angular Apps with Azure Application Insights
Azure Application Insights with Angular

Monitoring Live Angular Apps with Azure Application Insights

I previously explained how to add App Insights to a .NET Core Web API so that we can monitor the performance and failure rates of our APIs. What about client-side applications? In this post, I will show you how you can add Azure Application Insights telemetry to an Angular application. Having monitoring in both browser and server will shed light into how the application is performing as a whole. I will also show you how to add trace logging and tracking unhandled exceptions with Azure Application Insights in Angular.

Setup Azure Account

First of all, create your free Azure account here. Once that’s done, create a new Resource Group – name it wisely as you cannot change it later.

Navigate to the new resource group and click Add.

Create new resource in azure

In the add resource screen, search for Application Insights and click Create.

Azure will take some time (usually a few seconds) to create the new Application Insights resource. Once it is created, navigate to the resource and find your Instrumentation Key from the right hand side of the screen.

The instrumentation key uniquely identifies the resource you created on Azure. It is also the glue between your applications and Azure. You can use this key with both the server (API) or the browser (front-end).

You will use this instrumentation key later in this post to enable telemetry.

Add Application Insights Package

Install the official Application Insights JavaScript SDK to your Angular application.

npm install @microsoft/[email protected]

The command above will install all dependencies to enable Application Insights. This package includes all types needed to enable telemetry in an Angular application written with TypeScript.

Enable Telemetry in Angular

We now need to enable Azure telemetry in Angular using the code below:

import { ApplicationInsights } from '@microsoft/applicationinsights-web';
  
const appInsights = new ApplicationInsights({
  config: {
    instrumentationKey: 'INSTRUMENTATION_KEY',
  }
});

appInsights.loadAppInsights();

Please ensure to not import classes from @microsoft/applicationinsights-analytics-js namespace.

I recommend enabling App Insights inside the root component of your application. For most cli-generated Angular applications, this would be the app.component.ts. This is how it should look like:

import { Component, OnInit } from '@angular/core';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'AngularAppInsightsDemo';

  private appInsights = new ApplicationInsights({
    config: {
      instrumentationKey: 'YOUR_INSTRUMENTATION_KEY_GOES_HERE'
    }
  });

  ngOnInit() {
    this.appInsights.loadAppInsights();
  }
}

We create a new instance of ApplicationInsights class with configuration. The configuration must include the Instrumentation Key you see in your Azure portal.

Send Telemetry Data to Azure

You can send telemetry data to Azure portal using various methods available on the ApplicationInsights instance. This class allows you to log messages, exceptions, track events, collect performance metrics and even custom events.

The great thing about App Insights is that all telemetry is buffered and automatically sent to the Azure Portal when the user session ends i.e. browser tab is closed. This is especially useful in production environment as it does not introduce HTTP calls with every log but very annoying in development.

However, we can manually trigger an immediate send of all buffered telemetry data whenever we like using the flush method.

this.appInsights.flush();

Logging Messages with Severity Levels

One of the available methods on the ApplicationInsights class is trackTrace. This method accepts a parameter of type ITraceTelemetry, which has message and severityLevel properties.

We can use trackTrace method to log information-level messages to the Azure Portal.

// Log a diagnostic scenario such entering or leaving a function
this.appInsights.trackTrace({
  message: 'App initialised at ' + new Date().toString(),
  severityLevel: SeverityLevel.Information
});

The severityLevel is an enum that defines the level of the message we are logging.

// SeverityLevel.ts (from @microsoft/applicationinsights-web)
export declare enum SeverityLevel {
    Verbose = 0,
    Information = 1,
    Warning = 2,
    Error = 3,
    Critical = 4,
}

Regardless of the severity level, all data logged with trackTrace will appear in the Traces section of Azure Logs. Each log is classified as trace but has a severity level associated, which you can see in the Azure Portal.

Azure App Insights Trace Logs

Logging Exceptions

While the trace method helps you specify a level for the log, logging errors as trace is not a great idea. The reason is that your app could have so much trace logs and the danger is that finding errors in trace logs is a nightmare.

You should always log exceptions with trackException method.

// Log an exception that you have caught
this.appInsights.trackException({
  exception: new Error('My bug-free app throws an error')
});

There is more exception parameters available if you want to include more details about the error. As you may have guessed, all exceptions appear in the Portal under Logs > Exceptions.

Azure Exception Logs

Logging Unhandled Exceptions

By default, Azure Application Insights automatically catches all unhandled exceptions and sends them to the Portal. However, this does not work for Angular applications because Angular framework swallows unhandled exceptions. In order to log unhandled exceptions to Azure, you must implement a global error handler in your Angular app and use trackException method to send errors to the Azure Portal.

Create a Global Error Handler

Create a new file in your project, call it global-error-handler.ts and paste the following code:

import { ErrorHandler, Injectable, Injector } from '@angular/core';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {

    constructor(private injector: Injector) { }

    handleError(error: Error) {
        const appInsights = this.injector.get(ApplicationInsights);
        appInsights.trackException({ exception: error });
    }
}

This class is now responsible for catching all unhandled errors. We can log these errors to the Azure Portal using the handleError function. Notice how the class has a dependency on Injector. It uses the Injector to get an instance from Angular’s dependency injection container.

In order for this class to work properly, we need to provide a singleton instance of ApplicationInsights, instead of creating a new instance in the app.component.ts.

Provide a ApplicationInsights and Global Error Handler

We now want to take advantage of Dependency Injection in Angular to use a singleton instance of ApplicationInsights class. We can achieve this with a factory function inside the root module.

// .. omitted
providers: [
  {
    provide: ApplicationInsights,
    useFactory: appInsightsFactory
  },
  {
    provide: ErrorHandler,
    useClass: GlobalErrorHandler
  }
],
  bootstrap: [AppComponent]
})
export class AppModule { }

export function appInsightsFactory(): ApplicationInsights {
  return new ApplicationInsights({
    config: {
      instrumentationKey: 'INSTRUMENTATION_KEY'
    }
  });
}

In addition to the appInsights singleton, we provide our custom global error handler in the providers array.

Update app.component.ts

As we are now providing a singleton instance of ApplicationInsights, we can update app.component.ts to use this instance via constructor injection.

import { Component, OnInit } from '@angular/core';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'AngularAppInsightsDemo';

  constructor(private appInsights: ApplicationInsights) { }

  ngOnInit() {
    this.appInsights.loadAppInsights();

    throw new Error('An unhandled exception never happens, really.');
  }
}

ngOnInit event simulates an unhandled exception by throwing a new error. Our global error handler catches this and sends it to the Azure Portal.

Globally handled error

Tracking Individual Users

You may want to track individual users in your application. You can achieve this with setAuthenticatedUserContext method, which accepts a user id.

this.appInsights.setAuthenticatedUserContext(userId);

You would ideally call this function when the user session starts e.g. on successful login.

Just make sure to clear user id when they log out, or whenever the session ends.

this.appInsights.clearAuthenticatedUserContext();

Summary

Adding Azure Application Insights to an Angular application is really easy but getting started with is a bit difficult due to lack of documentation. In this post, I showed you how to add Azure Application Insights to an Angular app. Do you use App Insights in your Angular app? Drop a comment below, if you have any questions or suggestions!

Umut Esen

Umut is a certified Microsoft Certified Solutions Developer and has an MSc in Computer Science. He is currently working as a senior software developer for Royal London. He is the primary author and the founder of onthecode.

Leave a Reply

Close Menu

Free Template

Get your Angular Material application template to kick-start your next project.