Search This Blog


Friday, December 16, 2011

EJB3: Server independent Thread tracking utility

Useful for deadlock and monitoring...

We had a problem monitoring threads. Although it is relatively easy to initiate a thread - dump, you will only see the thread names - with related stack trace. 

The readibility depends heavily on the admin console. In Weblogic server you are able to list all monitoring threads in a table, in Glassfish's admin console you are only able to see the stats of the threadpool (although the list could be possible easily extended) - and I wouldn't like to mention JBoss's Admin-Console capabilities in this place :-).

In all that cases the names of the threads are proprietary and depend on the particular server.

In one of my past projects, I prefixed the Thread-Name with the EJB's name and was able to monitor it on every application server in similar way - using the JConsole or VisualVM. connect to Glassfish, you will need the 

url: service:jmx:rmi:///jndi/rmi://[HOST_NAME]:8686/jmxrmi  

and then choose "Remote" and enter username: admin and password: adminadmin (the default setting).

It was a J2EE 1.4 project, so I used a logger for this purpose. In Java EE 5,6 it is a perfect case for an interceptor:

public class ThreadTracker {
    public Object annotateThread(InvocationContext invocationContext) throws Exception{
        String originName = Thread.currentThread().getName();
            String tracingName = invocationContext.getMethod().getName() + " " + originName;
            return invocationContext.proceed();

A generic interceptor saves the origin Thread-Name first, then changes it before the actual method is invoked. Finally, the thread will be renamed to his origin name again. With this simple solution, you are possible to take a "snapshot" of the server's current load and see the methods currently executed.

It is much easier to find a deadlock... The interesting beans (or e.g. all facades), can be easily "instrumented" using the @Interceptors annotation.
It looks like this:

public class DummyBean implements DummyRemote {
   public String sayHello(String message){
        try {
        } catch (InterruptedException ex) {
            Logger.getLogger(DummyBean.class.getName()).log(Level.SEVERE, null, ex);
       return "Echo: " + message;
   } }

You could of course specify the interceptor in the XML-descriptor as well. No recompilation would be needed then...