June 1, 2018 ~ 3 min read

Building a Simple Logger Service for Ionic 3


Originally posted on Medium.

An Ionic developer’s best friend often are console statements to do some quick debugging or maybe to log the order of Ionic’s lifecycle events. Console output is awesome but you would not want to make this available in a production application as it often displays information not meant so be seen by others than you or your development team. In fact it can pose a security risk.

It is usually a good idea to remove all console.log, console.warn, console.whatever statements before releasing a production version of your app. So I do not miss any I usually add a tslint rule to my tsconfig.json to throw lint errors on all console statements. But who wants to manually remove all console statements before releasing and then adding them again when needed? Nobody I guess. You could add some custom steps to your build process to automatically remove all console statements of course, but a more elegant way I think is a custom logger service. This is why I built a custom logger service that outputs the different log levels depending on the current environment.

(Also check out this article about the environment switch we use at prototype.berlin to easily switch between different environments when serving or building our Ionic apps.)

import { Injectable } from '@angular/core';

/**
 * The possible log levels.
 */
export enum LogLevel {
  Error,
  Warning,
  Info,
  Debug,
}

@Injectable()
export class Logger {

  constructor() {}

  /**
   * Logs messages or objects  with the debug level.
   * Works the same as console.log().
   */
  public debug(...objects: any[]) {
    this.log(console.log, LogLevel.Debug, objects);
  }

  /**
   * Logs messages or objects  with the info level.
   * Works the same as console.info().
   */
  public info(...objects: any[]) {
    this.log(console.info, LogLevel.Info, objects);
  }

  /**
   * Logs messages or objects  with the warning level.
   * Works the same as console.warn().
   */
  public warn(...objects: any[]) {
    this.log(console.warn, LogLevel.Warning, objects);
  }

  /**
   * Logs messages or objects  with the error level.
   * Works the same as console.error().
   */
  public error(...objects: any[]) {
    this.log(console.error, LogLevel.Error, objects);
  }

  private log(func: Function, level: LogLevel, objects: any[]) {
    const env = window.env || 'development';
    if (env !== 'production' || (env === 'production' && level === LogLevel.Error)) {
      func.apply(console, objects);
    }
  }

}

The logger service at the moment supports four log levels: debug, info, warning and error. Of course it can be extended with some other common levels like trace or fatal, but those four are what I am usually using. In lines 51 to 54 you can see the environment filter where only errors are allowed when on a production environment, otherwise all outputs are shown. This of course can be extended as well. For example you might have a staging environment where only warnings and errors should be visible.

After adding the service to the app.module.ts it can be used straight forward like the usual console statements.

import { Injectable } from '@angular/core';

import { Logger } from '../../core/logger.service';

@Injectable()
export class SomeExampleService {

  constructor(
    private logger: Logger,
  ) {
    this.logger.debug('Yeah, the logger is working!', { foo: 'bar' });

    this.logger.info('Some informative information');

    this.logger.warn('Oh, watch out');

    this.logger.error('Oh snap!', 500);
  }

}

Console output

So if you use console statements a lot — and I do so — this simple logger service can make your life much easier. Just give it a try!