stritti / log4js

Log4js - The Logging Framework for JavaScript with no runtime dependencies
https://stritti.github.io/log4js/
Apache License 2.0
449 stars 57 forks source link

POST by using fetch appender #36

Open padoauk opened 5 years ago

padoauk commented 5 years ago

Hi.

log4js is a nice framework. I'd like to propose simpler ajax appender by using fetch API. In the following, data to be POSTed are kept as an object just before it is fetched. Therefore ObjectLayout is used.

If you like, include such capability in log4js. Thanks.

/**
 *  ajax by fetch appender
 */
 Log4js.ObjectLayout = function(){
 };

 Log4js.ObjectLayout.prototype = Log4js.extend(new Log4js.Layout(), {
  format: function(loggingEvent){
    let useragent = "unknown";
    try {
      useragent = navigator.userAgent;
    } catch(e){
      useragent = "unknown";
    }

    let referer = "unknown";
    try {
      referer = location.href;
    } catch(e){
      referer = "unknown";
    }

    const obj = {};
    obj.logger = loggingEvent.categoryName;
    obj.level = loggingEvent.level.toString();
    obj.message = `${loggingEvent.message}`;
    obj.referer = referer;
    obj.useragent = useragent;
    obj.timestamp = new Date();
    obj.exception = loggingEvent.exception;

    return obj;
  }
});

Log4js.FetchAppender = function(url){
  this.isInProgress = false;
  this.loggingUrl = url || "logging.log4js";
  this.threshold = 1;
  this.timeout = 2000;
  this.loggingEventMap = new Log4js.FifoBuffer();
  this.layout = new Log4js.ObjectLayout();
  this.httpRequest = null;
};

Log4js.FetchAppender.prototype = Log4js.extend( new Log4js.Appender(),{
  doAppend: function(loggingEvent){
    log4jsLogger && log4jsLogger.trace("> FetchAppender.append");

    if (this.loggingEventMap.length() <= this.threshold || this.isInProgress === true) {
      this.loggingEventMap.push(loggingEvent);
    }

    if (this.loggingEventMap.length() >= this.threshold && this.isInProgress === false) {
      //if threshold is reached send the events and reset current threshold
      this.send();
    }

    log4jsLogger && log4jsLogger.trace("< FetchAppender.append");
  },

  doClear: function () {
    log4jsLogger && log4jsLogger.trace("> FetchAppender.doClear");
    if (this.loggingEventMap.length() > 0) {
      this.send();
    }
    log4jsLogger && log4jsLogger.trace("< FetchAppender.doClear");
  },

  setThreshold: function (threshold) {
    log4jsLogger && log4jsLogger.trace("> FetchAppender.setThreshold: " + threshold);
    this.threshold = threshold;
    log4jsLogger && log4jsLogger.trace("< FetchAppender.setThreshold");
  },

  setTimeout: function (milliseconds) {
    this.timeout = milliseconds;
  },

  send: function(){
    if (0 < this.loggingEventMap.length()) {
      this.isInProgress = true;
      const a = [];
      for (var i = 0; i < this.loggingEventMap.length() && i < this.threshold; i++) {
        a.push(this.layout.format(this.loggingEventMap.pull()));
      }
      postData(this.loggingUrl, a)
        .then(data => console.log(JSON.stringify(data))) // JSON-string from `response.json()` call
        .catch(error => console.error(error));
    }
    this.isInProgress = false;

    function postData(url = ``, data = {}) {
      return fetch(url, {
        method:      "POST",
        mode:        "cors", // no-cors, cors, *same-origin
        cache:       "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
        credentials: "same-origin", // include, same-origin, *omit
        headers: {
          "Content-Type": "application/json; charset=utf-8",
        },
        redirect: "follow",
        referrer: "no-referrer",
        body: JSON.stringify(data),
      })
        .then(response => response.json());
    }
  }
});