Logging with Angular

Share on facebook
Share on google
Share on twitter
Share on linkedin

This post is going to cover logging and how to implement logging in an Angular app. The implementation of this is based on how I implemented continuous delivery for a client.

Why log?

The purpose of logging is to get detailed information of how the system is running, both runtime information of how the system has been used, but also in case of errors for easy error detection and error handling. I have often seen proper front-end logging being neglected in front-end applications because the team felt that logging the backend was sufficient. What a shame! Not having logging in the front-end give you huge blind spots in your application awareness as you are not logging the UI that the client is actually interacting with. That means if the application is failing and not contacting the back-end, you would never know anything has gone wrong. Yirks!

Logging vs Monitoring

Logging and monitoring are often used interchangeably, but even though one could argue they have some overlap, they serve different purposes.

Logging is about being aware of certain events in the system, such as errors and specific actions where monitoring is about continuously checking the health of the system. If a server is running out of resources or is throwing errors on the OS level, you might not notice this with logging but only with monitoring of the application.

What to log?

In general, you want to log specific events in the system and errors, such as HTTP requests and exceptions.

Often you want to hook in logging to all HTTP request and log request times and payloads, as these give you important metrics about how long your users are waiting for requests. Also, you want to be aware of when your users are experiencing errors and log these as well, including information about actions and application state that caused the error, for easier error tracing.

The ELK stack

A common technology stack for logging is the ELK stack consisting of ElasticSearch, Logstash, and Kibana. ElasticSearch is for storing and querying logs, Logstash is for processing logs before they are stored in ElasticSearch and Kibana is the UI interface for querying logs.

Implementing logging in an Angular app

Let’s go through how to implement logging in your Angular Application. We are going to start with creating a logging service that can log to ElasticSearch and then hook it into global error handling and HTTP requests. This is implemented on my logging demo app.

Create logging service

The first step is to implement a logging service that is able to send logs to ElasticSearch.

For actually performing the logging we are going to create an Angular agnostic ts class for logging called Logger:

This logger class got a method log for logging a message. A buffer using debounceTime is minimizing the amount of logs send to elasticSearch by only sending logs if log hasn’t been called in 5 seconds. Here it will flush the buffer, create the log payload and combine the buffer using the reduce operator.

After this we are just doing a good old XMLHttpRequest sending the log payload to the log endpoint. This endpoint should be set in the environment file.

This class is used in LogService which is wrapping the logger class for doing the actual logging in the Angular app:

This service contains three ways to log: logHttpInfo, logError and logInfo. Feel free to add more log levels like debug and warning but these are the log levels we are using in this demo.

Global error handler logging

Now that we have a service that can log to ElasticSearch, let’s set it up to log errors by hooking it into Angular’s global error handler provider.

First, we create a service called global error handler:

This will catch errors, create an error string with stack trace, log using the logging service and rethrow the error so it shows in the console.

Note how it is logging as warning or error depending on if error is comming from the application code (it contains /src/app/) and
sentencesForWarningLogging string array, a list of sentences that will make the error be logged as warning if they are included in the error message.

It is hooked into the app with:

HTTP request logging

When handling HTTP calls in Angular I recommend using an adapter pattern. This means that instead of working with Angular’s HttpClient overall in your code base you wrap the Angular HttpClient in your own HttpClient adapter. From here you can apply custom logic when doing logging, such as log information about the HTTP requests and handle HTTP status codes and your application will use the same HTTP client interface regardless if Angular changes its HttpClient (like it did when Angular went from doing http calls with Http to HttpClient).

Final words

In this post, we learned why logging is important in the front-end and how it serves a different purpose than monitoring. The also saw how to setup logging in your Angular app by creating a logging service, that can log to ElasticSearch (or what you use for storing logs) and how to hook this service into global error handling and HTTP requests.

Do you want to become an Angular architect? Check out Angular Architect Accelerator.

Related Posts and Comments

How to Set up a CI pipeline with Azure Pipelines and Nx

It goes without saying that having a CI pipeline for your Angular apps is a must. Setting one up for regular Angular apps is fairly straightforward but when you have an Nx monorepo there are certain other challenges that you have to overcome to successfully orchestrate a “build once, deploy many” pipeline. This post will

Read More »

How to Set Up Git Hooks in an Nx Repo

Git hooks can be used to automate tasks in your development workflow. The earlier a bug is discovered, the cheaper it is to fix (and the less impact it has). Therefore it can be helpful to run tasks such as linting, formatting, and tests when you are e.g. committing and pushing your code, so any

Read More »

The Stages of an Angular Architecture with Nx

Long gone are the times when the frontend was just a dumb static website. Frontend apps have gotten increasingly complex since the rise of single-page application frameworks like Angular. It comes with the price of increased complexity and the ever-changing frontend landscape requires you to have an architecture that allows you to scale and adapt

Read More »

The Best Way to Use Signals in Angular Apps

Since Angular 16, Angular now has experimental support for signals and there is a lot of confusion in the community about whether this is going to replace RxJS or how it should be used in an app in combination with RxJS. This blog post sheds some light on what I think is the best way

Read More »

High ROI Testing with Cypress Component Testing

Testing is one of the most struggled topics in Angular development and many developers are either giving up testing altogether or applying inefficient testing practices consuming all their precious time while giving few results in return. This blog post will change all this as we will cover how I overcame these struggles the hard way

Read More »