Enterprise Java

Server side logging from browser side JavaScript code

Application logging is something we all do in our applications that get deployed on an application server, right? Using frameworks like Log4J or Logback seems like a no-brainer to most Java developers. But what about the code we’ve written that is running in those pesky browsers? I guess that, apart from the occasional console.log() statement used during debugging, we don’t give much thought to JavaScript logging. I find this situation very regrettable since nowadays the trend appears to be to move our application logic to the browser. And with it, interesting events happening in the browser might go unnoticed, or any bugs that will happen, no matter how well we’ve developed and tested our client side code, might prove needlessly hard to reproduce and therefore fix. In this blog post I’ll demonstrate a very basic setup to log messages from the browser on the server using some very basic JavaScript with jQuery, and a simple Spring controller with Slf4J.

Server side code

Assuming you already have an existing Spring web application up and running and are using SLF4J for your application logging, all we have to do is add an additional @Controller that will take care of logging any incoming messages.

Our JSLogger controller

package it.jdev.demo;

import java.lang.invoke.MethodHandles;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;

@Controller
@RequestMapping(value = "/js-log")
public class JSLogger {

    private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.Lookup.class);

    @RequestMapping(method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void logError(final HttpServletRequest request, @RequestBody(required = true) final String logMessage) {
        final String ipAddress = request.getRemoteAddr();
        final String hostname = request.getRemoteHost();
        LOGGER.warn("Received client-side logmessage (" + ipAddress + "/" + hostname + "): " + logMessage);
    }

}

JavaScript code

For the JavaScript part of our logging solution we’ll add a JS file called jdev.js. In it we’ll define a module named JDEV.logging that will contain a method called logToServer(). This method will send an Ajax message to our controller with a little bit of help from jQuery. Just make sure that the url variable points to the endpoint configured in our controller’s @RequestMapping.

Our JavaScript logging module

var JDEV = JDEV || {};


JDEV.namespace = function(ns_string) {
	var parts = ns_string.split('.');
	var parent = JDEV;

	// strip redundant leading global
	if (parts[0] === "JDEV") {
		parts = parts.slice(1);
	}
	for (var i = 0; i < parts.length; i += 1) {
		// create a property if it doesn't exist
		if (typeof parent[parts[i]] === "undefined") {
			parent[parts[i]] = {};
		}
		parent = parent[parts[i]];
	}
	return parent;
};


JDEV.namespace('logging');
JDEV.logging = (function() {

	var logToServer = function(logMessage) {
		var logEventObject = {
			"message" : logMessage,
			"location" : location.href,
			"browser" : navigator.userAgent,
		};
		var logMsg = JSON.stringify(logEventObject);
		var url = "js-log";
		$.ajax({
			type : "POST",
			url : url,
			data : logMsg,
			contentType : "application/json",
			cache : "false",
		});
	}
	
	return {
		logToServer : logToServer,
	}

})();

All that is left to do, is include jQuery and our jdev.js file in our html pages, and instead of calling console.log() use our new logging method:

Wiring up the JS code

	<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
	<script type="text/javascript" src="js/jdev.js"></script>
	<script type="text/javascript">
		$(document).ready(function() {
		    JDEV.logging.logToServer("Hi from the browser...");
		});
	</script>
</body>
</html>

If everything is set up correctly, you should wind up with a similar log entry:
WARN : Received client-side logmessage (127.0.0.1/localhost): {"message":"Hi from the browser...","location":"http://localhost:8080/demo/","browser":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36"}

Wrapping up

I’ve demonstrated a very simple design making it possible to log entries in your server side log that originate from browser side JavaScript code. Of course, you can elaborate on this example, e.g. by adding the possibility to send along the Log Level with the Ajax call.

Reference: Server side logging from browser side JavaScript code from our JCG partner Wim van Haaren at the JDev blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Gianluca
Gianluca
9 years ago

It’s a good idea, but what about the increased http traffic between the client and server? It could be an performace issue.

Regards,
Gianluca

James
James
9 years ago

http://log4javascript.org

This is log4j, but on the browser. There is an AjaxAppender that you can configure, and one of the parameters is how many trace statements make up a batch to send to the server.

Back to top button