akalogger.js

/**
 * akalogger
 * Copyright (c) 2018 - Present, PyroclasticMayhem
 * This code is licensed under the MIT License
 */

'use strict';

// Import dependencies
const fs = require('fs');
const os = require('os');
const chalk = require('chalk');

/** Class representing a logger */
class Logger {
  /**
   * Create a logger
   * @param {Object} options - The options for logger
   * @param {Boolean} [options.timestampEnabled=true] - Include timestamp in logged item
   * @param {String} [options.timestampColor='dim'] - Color for timestamp
   * @param {Object} [options.levels] - Settings for different logger levels
   * @param {Object} [options.levels.log] - Settings for the level log
   * @param {Boolean} [options.levels.log.logToConsole=true] - Log level log to console
   * @param {Boolean} [options.levels.log.logToFile=true] - Log level log to file
   * @param {Boolean} [options.levels.log.logToSentry=false] - Log level log to Sentry
   * @param {String} [options.levels.log.color='white'] - Color for log type label
   * @param {Object} [options.levels.debug] - Settings for the level debug
   * @param {Boolean} [options.levels.debug.logToConsole=true] - Log level debug to console
   * @param {Boolean} [options.levels.debug.logToFile=true] - Log level debug to file
   * @param {Boolean} [options.levels.debug.logToSentry=false] - Log level debug to Sentry
   * @param {String} [options.levels.debug.color='white'] - Color for log type label
   * @param {Object} [options.levels.error] - Settings for the level error
   * @param {Boolean} [options.levels.error.logToConsole=true] - Log level error to console
   * @param {Boolean} [options.levels.error.logToFile=true] - Log level error to file
   * @param {Boolean} [options.levels.error.logToRaven=true] - Log level error to Sentry
   * @param {String} [options.levels.error.color='white'] - Color for log type label
   * @param {Object} [options.levels.info] - Settings for the level info
   * @param {Boolean} [options.levels.info.logToConsole=true] - Log level info to console
   * @param {Boolean} [options.levels.info.logToFile=true] - Log level info to file
   * @param {Boolean} [options.levels.info.logToSentry=false] - Log level info to Sentry
   * @param {String} [options.levels.info.color='white'] - Color for log type label
   * @param {Object} [options.levels.warn] - Settings for the level warn
   * @param {Boolean} [options.levels.warn.logToConsole=true] - Log level warn to console
   * @param {Boolean} [options.levels.warn.logToFile=true] - Log level warn to file
   * @param {Boolean} [options.levels.warn.logToSentry=false] - Log level warn to Sentry
   * @param {String} [options.levels.warn.color='white'] - Color for log type label
   * @param {String} [options.file] - Path to text file to log to
   * @param {String} [options.raven.url] - Sentry url
   * @param {Object} [options.raven.config] - Sentry config
   */
  constructor (options = {}) {
    this.timestampEnabled = options.timestampEnabled !== undefined ? options.timestampEnabled : true;
    this.timestampColor = options.timestampColor !== undefined ? options.timestampColor : 'dim';
    this.levels = {
      'log': {
        logToConsole: options.levels && options.levels.log && options.levels.log.logToConsole !== undefined ? options.levels.log.logToConsole : true,
        logToFile: options.levels && options.levels.log && options.levels.log.logToFile !== undefined ? options.levels.log.logToFile : true,
        logToSentry: options.levels && options.levels.log && options.levels.log.logToSentry !== undefined ? options.levels.log.logToSentry : false,
        color: options.levels && options.levels.log && options.levels.log.color !== undefined ? options.levels.log.color : 'white'
      },
      'debug': {
        logToConsole: options.levels && options.levels.debug && options.levels.debug.logToConsole !== undefined ? options.levels.debug.logToConsole : true,
        logToFile: options.levels && options.levels.debug && options.levels.debug.logToFile !== undefined ? options.levels.debug.logToFile : true,
        logToSentry: options.levels && options.levels.debug && options.levels.debug.logToSentry !== undefined ? options.levels.debug.logToSentry : false,
        color: options.levels && options.levels.debug && options.levels.debug.color !== undefined ? options.levels.debug.color : 'cyan'
      },
      'error': {
        logToConsole: options.levels && options.levels.error && options.levels.error.logToConsole !== undefined ? options.levels.error.logToConsole : true,
        logToFile: options.levels && options.levels.error && options.levels.error.logToFile !== undefined ? options.levels.error.logToFile : true,
        logToSentry: options.levels && options.levels.error && options.levels.error.logToSentry !== undefined ? options.levels.error.logToSentry : true,
        color: options.levels && options.levels.error && options.levels.error.color !== undefined ? options.levels.error.color : 'red'
      },
      'info': {
        logToConsole: options.levels && options.levels.info && options.levels.info.logToConsole !== undefined ? options.levels.info.logToConsole : true,
        logToFile: options.levels && options.levels.info && options.levels.info.logToFile !== undefined ? options.levels.info.logToFile : true,
        logToSentry: options.levels && options.levels.info && options.levels.info.logToSentry !== undefined ? options.levels.info.logToSentry : false,
        color: options.levels && options.levels.info && options.levels.info.color !== undefined ? options.levels.info.color : 'blue'
      },
      'warn': {
        logToConsole: options.levels && options.levels.warn && options.levels.warn.logToConsole !== undefined ? options.levels.warn.logToConsole : true,
        logToFile: options.levels && options.levels.warn && options.levels.warn.logToFile !== undefined ? options.levels.warn.logToFile : true,
        logToSentry: options.levels && options.levels.warn && options.levels.warn.logToSentry !== undefined ? options.levels.warn.logToSentry : false,
        color: options.levels && options.levels.warn && options.levels.warn.color !== undefined ? options.levels.warn.color : 'yellow'
      }
    };
    if (options.file) {
      this.writeStream = fs.createWriteStream(options.file, { flags: 'a' });
    }
    if (options.raven && options.raven.url) {
      this.raven = require('raven');
      this.raven.config(options.raven.url, options.raven.config).install();
    }
  }

  /**
   * Get timestamp
   * @return {String} - The timestamp
   * @private
   */
  get timestamp () {
    return this.timestampEnabled ? new Date().toLocaleString() + ' ' : '';
  }

  /**
   * Log message
   * @param {String} level - Level of log
   * @param {Array} message - Array containing message to log
   * @private
   */
  logMessage (level, message) {
    if (this.levels[level].logToConsole) { console.log(chalk[this.timestampColor](this.timestamp) + chalk[this.levels[level].color].bold(`[${level.toUpperCase()}] `) + Array.prototype.join.call(message, ' ')); }
    if (this.writeStream && this.levels[level].logToFile) { this.writeStream.write(this.timestamp + `[${level.toUpperCase()}] ` + Array.prototype.join.call(message, ' ') + os.EOL); }
    if (this.raven && this.levels[level].logToSentry) {
      let ravenLevel = level;
      let ravenCaptureType = 'captureMessage';

      switch (ravenLevel) {
        case 'log':
          ravenLevel = 'info';
          break;
        case 'warn':
          ravenLevel = 'warning';
          ravenCaptureType = 'captureException';
          break;
      }

      this.raven[ravenCaptureType](Array.prototype.join.call(message, ' '), { level: ravenLevel });
    }
  }

  /** Standard Log */
  log () {
    this.logMessage('log', arguments);
  }

  /** Debug Log */
  debug () {
    this.logMessage('debug', arguments);
  }

  /** Error Log */
  error () {
    this.logMessage('error', arguments);
  }

  /** Info Log */
  info () {
    this.logMessage('info', arguments);
  }

  /** Warn Log */
  warn () {
    this.logMessage('warn', arguments);
  }
}

module.exports = Logger;