JavaScript Logging

When "Capturing client-side JavaScript errors" showed up in the "adopt" section in the ThoughtWorks Technology Radar I was reminded that I couldn't find a JavaScript logger which met my requirements, when I wrote my first JavaScript heavy web application (in 2011). Since the ones I looked at back then are still the top hits on google (log4js & log4javascript), I guess there might still be a need for custom solutions. However, if one of them fits your needs, you should probably not roll your own...

I had basically two requirements
  • multiple appenders (console & web service)
  • fine granular configuration

I implemented a logger "module" (no fancy and module, just the plain revealing module pattern), a console appender module and a service appender module.

The logger offers the usual log methods, checks if the corresponding level is enabled and then forwards the calls to the registered appenders:


isLogLevelEnabled = function (logLevel) { 
	return app.config.logger['is' + logLevel + 'Enabled'] === true;     
},
debug = function (message, category) {
	log(category, "Debug", message);
},
// ...
error = function (message, category) {
	log(category, "Error", message);
},
log = function (category, logLevel, message) {
	if (isLogLevelEnabled(logLevel)) {
		for (var i = 0; i < appenders.length; i++) {
				appenders[i].log(category, logLevel, message);
		}
	}
},


The service appender checks a again if the log level is enabled (specifically for the service appender, so you can log different level with different appenders). It also allows you to enable logging for specific users by setting a cookie. This could be handy when you need debug an issue of a specific user.


var log = function (category, logLevel, message) {
    if (isLogLevelEnabled(logLevel) || isUserEnabled()) {
        var logData = { 'category': category, 'logLevel': logLevel, 'message': message };
        $.post(app.config.serviceAppender.logServiceUrl, logData);
    }
},
    isLogLevelEnabled = function (logLevel) {
        return app.config.serviceAppender['is' + logLevel + 'Enabled'] === true;
    },
    isUserEnabled = function () {
        return typeof (app.config.serviceAppender.allowServiceLoggingByCookie) !== 'undefined' &&
            app.config.serviceAppender.allowServiceLoggingByCookie === true &&
                $.cookie("enableServiceLogging") === "true";
    };


The config is set by defining the app.config object, which you probably what to load from a database or some other storage you can edit without deploying your site.


window.app.config = {};
window.app.config.logger = { isDebugEnabled: false, isInfoEnabled: true, isWarnEnabled: true, isErrorEnabled: true };
window.app.config.serviceAppender = {
    allowServiceLoggingByCookie: true, logServiceUrl: '@Url.Content("~/api/log")',
    isDebugEnabled: false, isInfoEnabled: false, isWarnEnabled: true, isErrorEnabled: true
};
window.app.config.consoleAppender = {
    isDebugEnabled: false, isInfoEnabled: true,
    isWarnEnabled: true, isErrorEnabled: true
};


You can check out the sample project. It is a F5-ready ASP.NET MVC application, although nothing about the logger is .NET specific.
comments powered by Disqus