RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


When JMX Is Overkill, Build a Lightweight Monitoring Framework : Page 2

A monitoring server is critical to any server-side infrastructure, be it an e-commerce or a telecom solution. Learn how to build a DIY (do-it-yourself) monitoring system using an extensible object-oriented framework.


Under the Framework's Hood

As you can see in the class diagram (see Figure 1), the framework consists of four classes and one interface. The framework exposes only the Info interface and the LWMFramework class to the client code that invokes the framework. This way, the client is transparent to the internal implementation of the framework.

Click to enlarge
Figure 1. Framework Class Diagram
All the components you need to monitor must implement the Info interface. The isOk() method checks the status and the process() method handles corrective action:

public interface Info {
    //checks the status 
    //returns true if ok 
    //throws Exception if it could not be monitored
    public boolean isOk() throws Exception;
    //handles corrective action
    public boolean process();

The framework uses two background threads:

  1. StatusMonitor for checking the status of each component
  2. StatusManager for executing corrective action and status reporting

The StatusMonitor (see Listing 1) polls every second (or configurable interval) to see if the counter of any monitorable object expired. If so, it calls the monitor() method on the monitorable object.

Listing 1. StatusMonitor Class

public class StatusMonitor extends Thread { private final int monInterval; //in milliseconds private final Monitorable[] monArray; public void run() { while(true) { for(int cnt = 0; cnt < Integer.MAX_VALUE; cnt++) { //iterate through the array for(int i = 0; i < monArray.length; i++) { //check if counter expired if((cnt % monArray[i].getCounter()) == 0) monArray[i].monitor(); } } try { sleep(monInterval); } catch(InterruptedException ie) {} } } }

Each monitorable object (see Listing 2) is associated with a StatusManager object and an Info object. Also, the attributes such as counter (the frequency of monitoring) and criticality are part of the monitorable object.

Listing 2. Monitorable Class

public class Monitorable { private int counter; private byte criticality; private byte prevStatus; private StatusManager manager; private Info info; public void monitor() { byte currentStatus = NOT_OK; try { if(info.isOk()) { currentStatus = Monitorable.OK; } } catch(Exception ex) { currentStatus = Monitorable.COULD_NOT_BE_MONITORED; } //call setchanged if there is change in status //or if status is not ok or cud not be monitored if((currentStatus != prevStatus) || currentStatus != StatusManager.OK) { synchronized(this) { prevStatus = currentStatus; } manager.setChanged(this); } } //return the last monitored status public synchronized byte getStatus() { return prevStatus; } //recovery action public void execute() { info.process(); } }

The monitorable object keeps track of the status changes in the Info object and notifies the StatusManager thread. The communication between StatusMonitor and StatusManager is via the monitorable object.

StatusManager (see Listing 3) receives notification when the monitorable object calls the setChanged method. It then fetches the monitorable object from the queue. If the status of the monitorable object is Not Ok, it invokes the execute() method on the monitorable object. The monitorable object in turn calls the associated Info object's process() method to perform correction action.

Listing 3. StatusManager Class

public class StatusManager extends Thread { //add to the queue and //notify that the status of monitorable has changed public synchronized void setChanged (Monitorable monitorable) monQueue.add(monitorable); notifyAll(); } //get the Monitorable object from the queue public synchronized Monitorable getMonitorable() { // return the object from the queue while(monQueue.isEmpty()) { try { wait(); } catch(Exception ex) {} } return (Monitorable) monQueue.remove(0); } //report or execute corrective action private void processChange() { Monitorable monitorable = getMonitorable(); //take corrective action if(monitorable.getStatus() == NOT_OK) { monitorable.execute(); } //log or report the status } public void run() { while(true) processChange(); } }

Click to enlarge
Figure 2. Framework Sequence Diagram

Currently, the recovery task executes in the context of the StatusManager thread. StatusManager can be enhanced to maintain a pool of threads for executing recovery tasks in a separate thread.

The startup class of the framework, LWMFramework, is used for configuring and initializing the framework. The sequence diagram in Figure 2 illustrates the interaction between various framework objects. The client code starts the framework after adding all the Info objects. During startup, the StatusManager and StatusMonitor threads are launched.

StatusManager maintains a thread-safe queue of monitorable objects. The StatusManager thread fetches the monitorable object from the queue and calls the getStatus() method on it. The access to the status variable of the monitorable object is also synchronized.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date