My random thoughts about software engineering

An aspiring software craftsman journey, By Mahmoud Ben Hassine

Using Server Sent Events To Create A Monitoring Dashboard

Server-Sent Events (aka SSE) are part of HTML5 and allow a web page to get updates from a server. It is a one way messaging form server to clients in contrast to Web Sockets where communication is bidirectional.

In this post, I will create a monitoring dashboard that shows JVM stats of a running Tomcat server. Off we go!

1. The server side

In the server side, no need for more than a vanilla servlet that pushes JVM stats every second to its clients. Let’s see how to do that:

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/health")
public class HealthServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
            response.setContentType("text/event-stream");
            response.setCharacterEncoding("UTF-8");
            PrintWriter printWriter = response.getWriter();
            Runtime runtime = Runtime.getRuntime();
            while (true) {
                try {
                    String data = String.format("{\"free\":\"%s\",\"total\":\"%s\",\"max\":\"%s\"}",
                            runtime.freeMemory(),
                            runtime.totalMemory(),
                            runtime.maxMemory());

                    printWriter.write("data: " + data + "\n\n");
                    printWriter.flush();
                    response.flushBuffer();
                    //Do not close the writer!
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
 
}

Most of the code is self explanatory, the servlet gathers JVM memory stats from the Runtime class and creates a JSON object with current values of total, max and free memory.

The devil is in the details. Here are the two important tricks:

  • The response content type should be set to text/event-stream with response.setContentType("text/event-stream");

  • The sent event must be of the following form : data: my_data \n\n

For more details about SSE event types, please refer to the W3C SSE specification.

This servlet will be deployed in the Tomcat instance to monitor and will serve the /health URL. That’s all for the server side, easy :smile:.

2. The client side

Now let’s see how to proceed on the client side. I will create a simple HTML page that connects to previous servlet with the following javascript snippet:

var source = new EventSource("/health");
source.onmessage = function (event) {
     var data = JSON.parse(event.data);
     plot.setData(data);
     plot.draw();
};

Mainly, the client side will receive events asynchronously from the server (using the EventSource object). Whenever it receives a message, it will execute the onmessage function which will update the graph with new data. That’s all on the client side, easy too :wink:.

Source code

The complete source code and running instructions are available on GitHub here.

If you run the server and browse http://localhost:8080/dashboard.html , you will see the server’s health graph being updated every second automatically. Here is a screenshot:

sse

Summary

This example is about monitoring the server’s memory. We can imagine any sort of stats such as the number of active http sessions, the number of http requests/second, etc.

I hope you have enjoyed reading this post. We will see a more advanced Java app monitoring setup with Grafana, Dropwizard metrics and InfluxDB in an upcoming post, keep tuned.

Before leaving this page, if you have already used SSE for other use cases, do not hesitate to share your experience in comments.

Credit: the plot graphic uses the excellent flot charts library.