/ lib / core / logger.js
logger.js
  1  require('colors');
  2  let fs = require('./fs.js');
  3  const date = require('date-and-time');
  4  
  5  const DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss:SSS';
  6  const LOG_REGEX = new RegExp(/\[(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d:\d\d\d)\] (?:\[(\w*)\]:?)?\s?\s?(.*)/gmi);
  7  
  8  class Logger {
  9    constructor(options) {
 10      this.events = options.events || {emit: function(){}};
 11      this.logLevels = Object.keys(Logger.logLevels);
 12      this.logLevel = options.logLevel || 'info';
 13      this.logFunction = options.logFunction || console.log;
 14      this.logFile = options.logFile;
 15      this.context = options.context;
 16    }
 17  
 18    /**
 19     * Parses the logFile, returning an array of JSON objects containing the
 20     * log messages.
 21     * @param {Number} limit specifies how many log messages to return from the
 22     *  end of the log file
 23     * @returns {Array} array containing
 24     *  - msg: the log message
 25     *  - logLevel: log level (ie 'info', 'debug')
 26     *  - name: process name (always "embark")
 27     *  - timestamp: timestamp of log message (milliseconds since 1/1/1970)
 28     */
 29    parseLogFile(limit) {
 30      let matches;
 31      let logs = [];
 32      const logFile = fs.readFileSync(this.logFile, 'utf8');
 33      while ((matches = LOG_REGEX.exec(logFile)) !== null) {
 34       // This is necessary to avoid infinite loops with zero-width matches
 35       if (matches.index === LOG_REGEX.lastIndex) {
 36         LOG_REGEX.lastIndex++;
 37       }
 38  
 39       if (matches && matches.length) {
 40         logs.push({
 41           msg: [matches[3]],
 42           logLevel: matches[2],
 43           name: 'embark',
 44           timestamp: date.parse(matches[1], DATE_FORMAT).getTime()
 45         });
 46       }
 47      }
 48  
 49      // if 'limit' is specified, get log lines from the end of the log file
 50      if(limit && limit > 0 && logs.length > limit){
 51        logs.slice(limit * -1);
 52      }
 53      return logs;
 54    }
 55  }
 56  
 57  Logger.logLevels = {
 58    error: 'error',
 59    warn: 'warn',
 60    info: 'info',
 61    debug: 'debug',
 62    trace: 'trace'
 63  };
 64  
 65  Logger.prototype.registerAPICall = function (plugins) {
 66    const self = this;
 67  
 68    let plugin = plugins.createPlugin('dashboard', {});
 69    plugin.registerAPICall(
 70      'ws',
 71      '/embark-api/logs',
 72      (ws, _req) => {
 73        self.events.on("log", function (logLevel, logMsg) {
 74          ws.send(JSON.stringify({msg: logMsg, msg_clear: logMsg.stripColors, logLevel: logLevel}), () => {});
 75        });
 76      }
 77    );
 78  };
 79  
 80  Logger.prototype.writeToFile = function (_txt) {
 81    if (!this.logFile) {
 82      return;
 83    }
 84    const formattedDate = [`[${date.format(new Date(), DATE_FORMAT)}]`]; // adds a timestamp to the logs in the logFile
 85    fs.appendFileSync(this.logFile, "\n" + formattedDate.concat(Array.from(arguments)).join(' '));
 86  };
 87  
 88  Logger.prototype.error = function () {
 89    if (!arguments.length || !(this.shouldLog('error'))) {
 90      return;
 91    }
 92    this.events.emit("log", "error", ...arguments);
 93    this.logFunction(...Array.from(arguments).map(t => { return t ? t.red : t; }));
 94    this.writeToFile("[error]: ", ...arguments);
 95  };
 96  
 97  Logger.prototype.warn = function () {
 98    if (!arguments.length || !(this.shouldLog('warn'))) {
 99      return;
100    }
101    this.events.emit("log", "warn", ...arguments);
102    this.logFunction(...Array.from(arguments).map(t => { return t ? t.yellow : t; }));
103    this.writeToFile("[warning]: ", ...arguments);
104  };
105  
106  Logger.prototype.info = function () {
107    if (!arguments.length || !(this.shouldLog('info'))) {
108      return;
109    }
110    this.events.emit("log", "info", ...arguments);
111    this.logFunction(...Array.from(arguments).map(t => { return t ? t.green : t; }));
112    this.writeToFile("[info]: ", ...arguments);
113  };
114  
115  Logger.prototype.debug = function () {
116    if (!arguments.length || !(this.shouldLog('debug'))) {
117      return;
118    }
119    this.events.emit("log", "debug", ...arguments);
120    this.logFunction(...arguments);
121    this.writeToFile("[debug]: ", ...arguments);
122  };
123  
124  Logger.prototype.trace = function () {
125    if (!arguments.length || !(this.shouldLog('trace'))) {
126      return;
127    }
128    this.events.emit("log", "trace", ...arguments);
129    this.logFunction(...arguments);
130    this.writeToFile("[trace]: ", ...arguments);
131  };
132  
133  Logger.prototype.dir = function (txt) {
134    if (!txt || !(this.shouldLog('info'))) {
135      return;
136    }
137    this.events.emit("log", "dir", txt);
138    this.logFunction(txt);
139    this.writeToFile("[dir]: ", ...arguments);
140  };
141  
142  Logger.prototype.shouldLog = function (level) {
143    return (this.logLevels.indexOf(level) <= this.logLevels.indexOf(this.logLevel));
144  };
145  
146  module.exports = Logger;