In my previous post, I talked about catching all errors in Angular with a global error handler. If you want to keep the errors you capture, you need to implement a reliable logging mechanism. Today, I want to explain how to enable Angular logging in your applications with ngx logger package.

Importance of logging

As a developer, you are responsible for every line of code you write. If a bug surfaces in the application, you need to pinpoint the issue and provide a fix for it.

Undoubtedly, this is easier said than done within a real-world project. In most cases, it can take hours (if not days) to reproduce the issue before you can even fix it.

When implemented properly, logging can save your as* big time. Not only will logging save you hours of debugging in the long run but also give you confidence about your solutions.

Basic logging in JavaScript

Logging in vanilla JavaScript is pretty simple – just use the console object as shown below.

console.log('info log');
console.warn('warning log');Code language: JavaScript (javascript)

Although very simple, the console logging can limit what you can do with your logs. Think about it, you are going to be adding log statements all over the project.

What if…

  • you want to disable logging temporarily
  • enable logging only in production
  • ignore certain log levels
  • send logs to server

It is possible to implement these requirements by hand. You could provide it as a service in your Angular application.

However, infrastructure concerns like logging are essential in any application and you shouldn’t really spend your time building and maintaining these features. Unless there are strict company policies, you should make use of libraries instead of re-inventing the wheel.

Getting started with ngx-logger

ngx-logger is a very simple logging library for Angular applications.

It offers the following features:

  • Pretty printing to the console
  • Enable logging based on the level specified
  • Control log level based on the current environment
  • Send log messages to server via HTTP for centralised logging
  • Indicates log location and line number

Getting up and running with ngx-logger is easy, just create a new Angular app and pull the package from npm:

npm install ngx-loggerCode language: Bash (bash)

Import the library in the root module i.e. app.module.ts:

import { LoggerModule, NgxLoggerLevel } from 'ngx-logger';Code language: TypeScript (typescript)

Finally, import LoggerModule.forRoot in your application module. This is where we can configure the logger:

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
    LoggerModule.forRoot({
      serverLoggingUrl: 'http://localhost:68552/', // Replace with YOUR API
      level: NgxLoggerLevel.TRACE,
      serverLogLevel: NgxLoggerLevel.ERROR,
      disableConsoleLogging: false
    })
  ],
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }Code language: TypeScript (typescript)

With the above configuration in place, we can start logging anywhere in the application.

export class AppComponent {
  constructor(private logger: NGXLogger) {
    this.logger.debug("Debug message");
    this.logger.info("Info message");
    this.logger.log("Default log message");
    this.logger.warn("Warning message");
    this.logger.error("Error message");
  }
}Code language: TypeScript (typescript)

Here we are injecting the NGXLogger as a dependency to the component class, giving us access to the NGXLogger instance.

When you run the application, you will see the log messages in the browser console.

Console Output from ngx-logger

You will notice that there are errors relating to the server-side logging. This is because we told ngxlogger to send errors to the server at /api/logs end-point. Since this URL does not exist, we get an error message.

Angular logging configuration

Let’s take a closer look at the configuration object:

LoggerModule.forRoot({
   serverLoggingUrl: 'http://localhost:68552/', // Replace with YOUR API,
   level: NgxLoggerLevel.TRACE,
   serverLogLevel: NgxLoggerLevel.ERROR,
   disableConsoleLogging: false
})Code language: TypeScript (typescript)

level defines the minimum log level in the browser. Available levels are: TRACE, DEBUG, INFO, LOG, WARN, ERROR, FATAL and OFF. These values come from NgxLoggerLevel class.

serverLoggingUrl is where you give the full path to your api end-point for logging to server. This is optional, if you don’t need logs to be sen’t to server, delete this line.

serverLogLevel defines the minimum log level for server-side logging.

disableConsoleLogging is a flag which helps you to turn console logging completely off.

Environment specific logging in Angular

A common requirement in a real-wold application is environment specific logging. This simply means that you want to configure logging differently, depending on the environment the app is running.

For example, you may wish to only log errors in production environment while keeping all log levels enabled in development environment.

To do this, we need to use environment variables of our Angular application.

Let’s import environment object in app.component.ts, which allows us to initialise logging configuration with environment-specific details.

import { environment } from 'src/environments/environment';

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
    LoggerModule.forRoot({
      serverLoggingUrl: `${environment.apiUrl}api/logs`,
      level:environment.logLevel,
      serverLogLevel: environment.serverLogLevel,
      disableConsoleLogging: false
    })
  ],
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }Code language: TypeScript (typescript)

There are two environments in a cli-generated Angular application: development and production. These environments are defined in the Angular.json file, and located under src folder of the project.

The idea is that the same variable exists in each environment file, providing different values corresponding to the environment.

Let’s update the development environment:

import { NgxLoggerLevel } from 'ngx-logger';

export const environment = {
  production: false,
  apiUrl: 'http://localhost:68552/', // Replace with local API
  logLevel: NgxLoggerLevel.WARN,
  serverLogLevel: NgxLoggerLevel.OFF
};Code language: TypeScript (typescript)

When you run the application with ng serve, the development environment configuration will be used: only the warn logs & above will be logged on the browser. The server-side logging is turned off as we just want to see the errors in the console during development.

Let’s also update the production environment (environment.prod.ts):

import { NgxLoggerLevel } from 'ngx-logger';

export const environment = {
  production: true,
  apiUrl: 'http://api.myservice.com/api/', // Replace with remote API
  logLevel: NgxLoggerLevel.OFF,
  serverLogLevel: NgxLoggerLevel.ERROR
};Code language: TypeScript (typescript)

Our production configuration states that there will be no browser logging and only errors will be logged to the server at the specified API URL.

You can test this by starting your application in production mode via ng serve --configuration=production.

Logging to server

Logging in Angular happens within the browser of each user, which we cannot access. Sending logs to the server allows us to store them somewhere safe like log files or even a database.

I think this is the most useful feature of ngx-logger.

In order for this feature to work, you need an API that exposes a POST endpoint for accepting a log object.

ngx-logger POSTs an object for each log message your API endpoint.

For example:

{
  "level": 5,
  "additional": [],
  "message": "Error",
  "timestamp": "2020-02-02T11:42:40.153Z",
  "fileName": "main.js",
  "lineNumber": 87,
  "columnNumber": 26
}Code language: JSON / JSON with Comments (json)

Please ensure you import HttpClientModule and set the serverLoggingUrl correctly.

Your API implementation will vary depending on the server stack. Here is an example endpoint for .NET Core Web API:

[HttpPost]
public IActionResult Post([FromBody] LogDto dto)
{
    var msg = $"MESSAGE: {dto.Message} - " +
              $"FILE: {dto.FileName} - " +
              $"LEVEL: {dto.Level} - " +
              $"LINENUMBER: {dto.LineNumber} - " +
              $"TIMESTAMP: {dto.Timestamp:F}" +
              $"USER: {User.Identity.Name}";
    _logger.LogError(msg);
    return Ok();
}Code language: C# (cs)

And there you have it! You can checkout the code on GitHub.

I would like to find out how you perform logging in your apps, let me know in the comments.

Umut Esen

Software Engineer specialising in full-stack web application development.

Leave a Reply

This Post Has 16 Comments

  1. Asif

    Do these logs print when you make an IPA, install it on iPhone and then connect via XCode? We are having trouble doing that.

  2. Mikec711

    So, config question (may be more angular scoped but) … a customer calls and i want to change the log level for that customer. Can I have the customer export (unix) into their own environment and pick it up from there? ie: i want customer A to go to debug but want the rest of the world to stay at warning. Thanks

  3. Terry J. Davis

    Just pulled down the app. I’m running Angular 9.

    this.logger.debug does not write to the console. I have to use this.logger.warn instead.

    environment.ts:
    export const environment = {
    production: false,
    name: ‘dev’,
    logLevel: NgxLoggerLevel.DEBUG,
    serverLogLevel: NgxLoggerLevel.OFF
    };

    app.module.ts:
    LoggerModule.forRoot({
    level: environment.logLevel,
    serverLogLevel: environment.serverLogLevel,
    disableConsoleLogging: false
    })

  4. Taufique

    Hello Umut Esen,
    I have followed line by line everything is working for me, but my concern is that I want to send these logs to the node server please help me if possible.

  5. Like!! I blog quite often and I genuinely thank you for your information. The article has truly peaked my interest.

  6. Asad Naeem

    After following your example line by line. I found these errors in the browser. I am using Angular 9.
    core.js:6185 ERROR NullInjectorError: R3InjectorError(AppModule)[NGXLogger -> NGXMapperService -> HttpBackend -> HttpBackend -> HttpBackend]:
    NullInjectorError: No provider for HttpBackend!

    1. Umut Esen

      NGXLogger requires an Http client to post logs to APIs so you would need to provide that dependency in your root/core module.

      1. Neeraj

        Any Update, I am also facing same issue, i want to call my interceptor but due to HttpBackend its skipping my interceptor.

    2. Elijah

      I’m learning this, what was the exact solution to getting past this NullInjectorError?

  7. amit

    I tried with latest `ngx-logger` npm and somehow I’m not getting an error that
    POST http://localhost:4200/api/logs/ not found.

    Is this dependent on specific version?

    1. Umut Esen

      Nope, it is still going strong! I have however started using Azure Application insights for automatic logging!

  8. gaurav

    how can we pass the payload from the angular, can you send the code snippet , thanks for your response

  9. gaurav

    our api is of get or post ? my api is not getting called , can you help

    1. Umut Esen

      Thanks for your comment. I have added an example POST API implementation in the post.