Real time logging using JMS, log4j and websocket

In our daily life, we may sometime want to take the server log into the browser.  We have a lot of solutions to get this working. I am going to explain some interesting solution for real-time logging using log4j, JMS and websocket.

We all are familiar with log4j, so we don’t need much more explanation.  Normally, we use fileAppender to write logs into file.  Apache log4j has a feature to send the log messages to a JMS borker, which is called JMSAppender.

Here, in this example, I am using ActiveMQ as message broker. It is an open source message broker written in java together with a full Java Message Service client. We can use activeMQ by embedding into tomcat or by installing and running as a different server. Normally activeMQ start listening to a default TCP port 61616.

To use ActiveMQ as a destination of our messages, we need to configure JMS appender properly. The code sample below shows example configuration.

log4j.rootLogger=INFO, stdout, jms

## Be sure that ActiveMQ messages are not logged to ‘jms’ appender
log4j.logger.org.apache.activemq=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c – %m%n

## Configure ‘jms’ appender. You’ll also need jndi.properties file in order to make it work
log4j.appender.jms=org.apache.log4j.net.JMSAppender
log4j.appender.jms.InitialContextFactoryName=org.apache.activemq.jndi.ActiveMQInitialContextFactory
log4j.appender.jms.ProviderURL=tcp://localhost:61616
log4j.appender.jms.TopicBindingName=logTopic
log4j.appender.jms.TopicConnectionFactoryBindingName=ConnectionFactory

The important thing is not to send ActiveMQ logs to JMS appender, as it can cause errors since the broker will want to log before the connection is established. You will also need a JNDI configuration, so that appender can find appropriate topic to send log messages to. The example jndi.properties file can look like this:

topic.logTopic=logTopic

Now our log4j is ready to send all log messages to the message broker (ActiveMQ).

We can use websocket for real time logging into the browser. If you want to know more about websocket click here. The idea is that we need to create a websocket server from which we consume all the log messages from the message broker and send it to the requested websocket client.

For creating websocket server,  we can use Apache tomcat WebSocketServlet API.

http://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/websocket/WebSocketServlet.html

Sample code:

LogViewerServlet .java

package com.inapp.inharness.common;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;

import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;

@WebServlet (“/log”)
public class LogViewerServlet extends WebSocketServlet {

                   @Override
                    protected StreamInbound createWebSocketInbound(String arg0,
                                                                                                       HttpServletRequest arg1) {
                                            return new LogInbound();
                    }
}

LogInbound.java

package com.inapp.inharness.common;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;

import javax.jms.Connection;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQObjectMessage;
import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.WsOutbound;
import org.apache.log4j.spi.LoggingEvent;

public class LogInbound extends MessageInbound implements MessageListener {

         @Override
          protected void onBinaryMessage(ByteBuffer arg0) throws IOException {
          }

@Override
 protected void onTextMessage(CharBuffer arg0) throws IOException {
}

@Override
protected void onOpen(WsOutbound outbound) {
             super.onOpen(outbound);
            try {
                        ActiveMQConnectionFactory factory = new                                ActiveMQConnectionFactory(“tcp://localhost:61616″);
                        Connection conn = factory.createConnection();
                        Session sess = conn.createSession(false,                    Session.AUTO_ACKNOWLEDGE);
                      conn.start();
                       MessageConsumer consumer = sess.createConsumer(

                                 sess.createTopic(“logTopic”));
                       consumer.setMessageListener(this);
         } catch (Exception e) {
                      e.printStackTrace();
         }
}

@Override
protected void onClose(int status) {
         super.onClose(status);
}

@Override
public void onMessage(Message message) {
            try {
                      LoggingEvent event =

     (LoggingEvent) ((ActiveMQObjectMessage) message).getObject();
                  this.getWsOutbound()
                                         .writeTextMessage(
                                                  CharBuffer.wrap(“[" + event.getLevel() + "]["
                                                                      + event.getLoggerName() + "]“
                                                                      + event.getMessage()));

                     } catch (Exception e) {
                              e.printStackTrace();
                     }
             }

}

 Now the server side is ready.

How to access these log message from a browser? The answer is websocket client.

The below code can be used to create a client in javascript.

<!DOCTYPE HTML>
<html>
           <head>
                          <script type=”text/javascript”>
                                      function WebSocketTest()   {
                                                 if (“WebSocket” in window) {
                                                          alert(“WebSocket is supported by your Browser!”);
                                                         // Let us open a web socket
                                                         var ws = new                       WebSocket(“ws://localhost:8080/inharness/log”);
                                                        ws.onopen = function()  {
                                                                               };

                                                         ws.onmessage = function (evt) {
                                                                    var received_msg = evt.data; // this is the log message                                                                                                                                   // sent from the server.
                                                                      alert(“Message is received…”);
                                                           };
                                                          ws.onclose = function() {
                                                                   // websocket is closed.
                                                                    alert(“Connection is closed…”);
                                                           };
                                            }    else    {
                                                        // The browser doesn’t support WebSocket
                                                        alert(“WebSocket NOT supported by your Browser!”);
                                                 }
                         }
                     </script>
           </head>
            <body>
                      <div id=”sse”>
                                    <a href=”javascript:WebSocketTest()”>Run WebSocket</a>
                    </div>
            </body>
</html>

This is how we implement real time logging using log4j , JMS and websocket.

One thought on “Real time logging using JMS, log4j and websocket

  1. WebSocketServlet is deprecated in tomcat r8.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>