Software Secret Weapons™  
Adding Performance Counters And SNMP Support To Graph Application posted by Pavel Simakov on 2007-05-07 16:12:12 under Linguine Watch
view comments
 


Introduction

This tutorial illustrates the use of Linguine Watch for adding real-time monitoring to an existing Java application. I have taken the famous Graph.java Java Applet that has been shipped with Java JDK for years. Every Java developer out there has seen this application. In just several minutes I have added the real-time SNMP monitoring support to this application as I describe below.

I can see you smile - this is not a complex application! What kind of monitoring is needed here? It does not need any monitoring... I think the Graph application makes a great example for illustrating a thought process that goes into adding performance counters into an application.

Basic steps for adding performance counters to your application

In order to add SNMP performance monitoring to your application with Linguine Watch you need to:

  • decide what to monitor
  • implement IPerfMonitor objects and instantiate them in your code
  • update monitors from specific points in your application
  • configure, and start IPerfAgent or ISNMPAgent in the main startup sequence of your application
  • register IPerfMonitor objects with IPerfAgent
  • create MIB file for SNMP monitoring
  • run the application, simulate some activity and view the results

These steps are the same for any project. I will now cover each step in more detail.

Decide what to monitor

When looking for things to monitor think of gauges and counters. The counters are integer numbers always increasing over time. The gauges are integer numbers with values that can increase or decrease over time. When we need to monitor a component with complex behavior, we have to identify counters and gauges in this component. Lets find one gauge and one counter metrics that we can monitor in the Graph application.

One metric we can monitor in the Graph is its stress level. After graph nodes are moved or shaken, the graph dynamically minimizes the stress level by moving nodes around. Monitoring a graph stress level will let us measure how long it takes for graph to settle down. This is a very good example of monitoring a subsystem with a complex dynamic behavior.

I have defined the stress level of the model as an average of the stress levels of all edges. The stress level of the edge is a difference between its desired length and its current length. The stress level is a typical example of a gauge monitor. I will use standard gauge monitor implementation provided in Linguine Watch class SimpleGaugeMonitor.

Second metric to monitor is the mouse activity. We can monitor how many mouse clicks user has made while moving the graph nodes around. We are specifically interested in the graph nodes being clicked and dragged. We will ignore the "Scramble" and "Shake" buttons being pressed.

It might not be as exciting as monitoring a stress level, but it is a very good example of monitoring tasks in general. I have defined mouse activity as number of times mouse button was pressed down and number of times it was released. We can use two separate counters these two numbers. Interestingly that mouse can't be pressed unless it was released and vise versa. This makes both counters related as they both reflect different state of the same logical task. I will use standard task monitor in Linguine Watch class TaskExecutionMonitor.

One more thing we can monitor is the memory usage in the Java Virtual Machine (JVM). I will use standard JVM monitor in Linguine Watch class VirtualMachineMonitor.

Implement IPerfMonitor objects and instantiate them in your code

It is sufficient to add only one oy-lw.jar file to the classpath. This jar file has no dependencies. Certain Java classes need to imported into the project.

 
	import com.oy.shared.lw.LinguineSNMPWatch;
	import com.oy.shared.lw.perf.monitor.SimpleGaugeMonitor;
	import com.oy.shared.lw.perf.monitor.TaskExecutionMonitor;
	import com.oy.shared.lw.perf.monitor.VirtualMachineMonitor;

The main class LinguineSNMPWatch must be declared and instantiated. It contains the main registry of performance monitors and SNMP agent. It does not became active, however, until start() method is called later on.

 
	...
	LinguineSNMPWatch watch = new LinguineSNMPWatch();	
	...

We will use standard monitors for this tutorial and do not yet need to implement a custom monitor. The instances of standard performance monitors need to be created. The constructor usually takes class name, monitor name and description. The combination of the class name and the human readable monitor name must be unique.

 
	...
	VirtualMachineMonitor jvmMon = new VirtualMachineMonitor();
	TaskExecutionMonitor mouseMon = new TaskExecutionMonitor(
		Graph.class, "MOUSE DRAG", "Monitors mouse activity.");
	SimpleGaugeMonitor stressMon = new SimpleGaugeMonitor(
		Graph.class, "STRESS", "Monitors stress in the graph.");
	...

Update monitors from specific points in your application

Each monitor value must be updated from one specific place of the application. The model stress level must be calculated in the place where edges are inspected and resized in the original code.

 
	...
	double stress = 0;    	
	for (int i = 0 ; i < nedges ; i++) {
		...   
		stress += edges(i).len - len;	   	    
	}		
	stressMon.setValue(Math.round(Math.abs(stress)) / nedges);	
	...

The mouse activity monitor must be updated in two places where mouse clicks are handled in the existing code.

 
	public void mousePressed(MouseEvent e) {
    		mouseMon.incStarted();
		...
	}

public void mouseReleased(MouseEvent e) { ... mouseMon.incCompleted(); }

Configure and start IPerfAgent or ISNMPAgent

The IPerfAgent monitoring agent need to be configured. The various configuration options are summarized in a separate document. We will enable a periodic snapshot file in addition to SNMP support. All configuration options must be set before agent is started with start(). This method can throw an exception that must be caught.

 
	...
	String home = System.getProperty("user.home") + "/";
	
	watch.getPerfAgentContext().setSnapshotFileName(home + GraphPanel.class.getName() + ".html");
	try {
    		watch.start();    	
	} catch(Exception ie){
		throw new RuntimeException(ie); 
	}
	...

Register IPerfMonitor objects with IPerfAgent

After an agent was started each performance monitor instance must be registered with it. The monitor becames available from SNMP agent immediately after addMonitor() is called.

 
	...
    	watch.getPerfAgent().addMonitor(stressMon);
    	watch.getPerfAgent().addMonitor(mouseMon);
    	watch.getPerfAgent().addMonitor(jvmMon);
	...

Create MIB file for SNMP monitoring

With Linguine Watch MIB files are generated automatically and don't need to be written by hand. The MIB file can be created at any moment after agent has been started. The MIB file options like company name and web address can be specified when agent is configured. The generated MIB file will contain definitions of all the performance monitors registered with the agent at the time of generation. Please review the MIB file generated for this project.

 
	...		
	watch.getSNMPAgent().generateMIBFile(home + GraphPanel.class.getName() + ".mib");
	...

Run the application, simulate some activity and view the results

Now compile and start the Graph application. In order to monitor it with SNMP, start SNMP monitoring software of your choice, AdventNet SNMP Utilities 4 package for example. Open MIB file for this project (located in C:\Documents and Settings\%USER_NAME% folder) and load it into the SNMP Utilities MIB Browser. Select "stress_gauge" and "mouse_drag.completed" values for monitoring. Specify the host name where Graph application was started, probably "localhost", if you run Graph and SNMP monitoring station on the same host.

Now we can play with the Graph and observe real-time changes to the performance counters. The sample chart is presented in the picture. The "stress_gauge" in in red, the "mouse_drag.completed" is in green. The values are updated once every second.

As expected, the performance counters immediately reflect my actions in the Graph application. I performed the following action with the Graph:

  • clicked a node and moved it, waited a bit while model settled
  • clicked "Scramble" button, did not click on the nodes, waited a bit while model settled
  • maximized the application, dragged the "fixed" node (in red with the caption "joe") from one corner of the screen to another, waited a bit while model settled

If you don't plan to use SNMP, you do not have to. Since we have specified snapshot file name, Linguine Watch will create periodic snapshot every 5 s, with each snapshot containing 360 most recent data rows for performance counter values. The size of the snapshot and its update frequency as well as many other options can be specified before agent is started the same way we have specified snapshot file name. Please review the snapshot file corresponding to the chart above.

It is ok to be using the snapshot files while you are developing your application. It is best to switch to SNMP monitoring software once you are ready for production. Undoubtedly, using SNMP will dramatically professionalize your monitoring efforts.

Provide clean shutdown

Clean shutdown is a must. It is best to unregister monitors before stopping an agent. It is a good practice to unregister monitors in the order reverse to the order, in which they were registered.

 
	...		
	watch.getPerfAgent().removeMonitor(jvmMon);
    	watch.getPerfAgent().removeMonitor(mouseMon);
    	watch.getPerfAgent().removeMonitor(stressMon); 

watch.stop(); ...

No comments yet


Leave a comment


  Copyright © 2004-2007 by Pavel Simakov SourceForge.net Logo