Skip to content

POST by using fetch appender #36

Open
@padoauk

Description

@padoauk

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());
    }
  }
});

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions