Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

log object in log4javascript

I want to log objects using log4javascript. For example consider the following code:

function LogObject() {
var blah = {
    one: 42,
    two: "486"
};
logger.Info(blah);

Assuming that logger is instance of log4javascript logger that is properly set up:

var logger = log4javascript.getLogger("InternalLogger");
var ajaxAppender = new log4javascript.AjaxAppender(url),
jsonLayout = new log4javascript.JsonLayout(false, false);
ajaxAppender.setLayout(jsonLayout);
ajaxAppender.addHeader("Content-Type", "application/json");
logger.addAppender(ajaxAppender);

I am expecting the result to the following: request payload contains array of messages first of which is my object serialized into JSON. What I see is array of messages first of which has string "Object object" (like toString() method was invoked). How can I achieve that?

like image 671
seeker Avatar asked Aug 13 '13 09:08

seeker


2 Answers

JsonLayout formats the logging event (which includes log level, timestamp and logger name in addition to the log message(s)) as JSON rather than the log message, which is pretty much assumed to be a string. The reason for this is to avoid a dependency on a JSON library for older browsers; generating JSON for the simple, known data that JsonLayout deals with is no problem without a JSON library but handling arbitrary objects definitely requires one.

The workaround I'd suggest is simply to format the message before you pass it to the logging call:

logger.info( JSON.stringify(blah) );
like image 190
Tim Down Avatar answered Sep 29 '22 02:09

Tim Down


We were following @Tim Down's suggestion

logger.info( JSON.stringify(blah) );

But we had performance issues since the JSON.stringify happens before logger.info is called, therefore it will always happen even if the logging level is set to ignore this log.

In order to work around this I wrote a new lazy layout so that the stringification only happens if the log is actually output. In order to be more flexible it also alows passing a function, in which case it outputs the result of running said function.

Usage:

logger.trace("Received ", widget, " which has ", ()  => countFrimbles(widget), ' frimbles');

Implementation:

function LazyFormatLayout() { }
LazyFormatLayout.prototype = new log4javascript.Layout();
LazyFormatLayout.prototype.format = function (loggingEvent) {
    var time = loggingEvent.timeStamp.toTimeString().split(/\s/)[0];

    var head = time + ' ' + loggingEvent.logger.name + ' [' + loggingEvent.level.name + '] - ';
    var body = loggingEvent.messages.map(function (arg) {
        try {
            switch (typeof (arg)) {
                case 'function':
                    return arg();
                case 'object':
                    return JSON.stringify(arg);
            }
        }
        catch (e) {
            return '<<error while logging: ' + e.stack + '>>';
        }
        return arg;

    }).join('');
    if (!loggingEvent.exception)
        return head + body;

    return head + body + ' ==> Exception: ' + loggingEvent.exception.stack;
}

LazyFormatLayout.prototype.ignoresThrowable = function () { return false; };
LazyFormatLayout.prototype.toString = function () { return "LazyFormatLayout"; };
like image 30
Motti Avatar answered Sep 29 '22 04:09

Motti