Access Windows Performance Monitor counters from Java, Part 1

Use a simple Java API to gather valuable performance statistics

For those running Java applications or services, the Windows Performance Monitor (WPM) contains a treasure trove of valuable information—see Figure 1. There are hundreds (or thousands) of performance statistics called counters that are available in real time and measure critical system performance factors. This article outlines a simple way to access those performance statistics from Java.

Figure 1. Windows Performance Manager. Click on thumbnail to view full-sized image.

The problem is that accessing WPM can be quite challenging as it is a native Windows service and few, if any, Java APIs are available for accessing the information it provides from Java. Some research revealed three main ways of reading the WPM data with Java:

  • Configure WPM to log specific performance counters: WPM can take a configurable set of counters and log them to a file on a configured frequency. Windows XP and Windows 2003 also allow WPM data to be logged directly to an ODBC (Open Database Connectivity) datasource. Once this data has been logged to its final destination, it should be trivial enough to read the logging file using the java.io or java.nio packages. If you are fortunate enough to be able to log directly to an ODBC datasource, then the WPM counter data will be accessible through the java.sql JDBC (Java Database Connectivity) packages. The deficiencies of this approach are:

    • No real time or frequency control: With this approach, you cannot simply request data when you want it. You must wait for WPM to log a counter to the persisted source. Then you must go out and get the data. These two factors typically involve some sort of polling process, which grows tiresome since you cannot get some data exactly when you want it, and you will get other data even when you don't want it. Worst of all, you may spend more time grappling with I/O or JDBC issues than you will actually reading WPM counter data.
    • Inflexible counter configuration: Every time you decide to add or remove a counter to the list persisted to the WPM counter log, you will need to go to the WPM console and reconfigure the logging options. This may also require a configuration (or code) change in your monitor application that retrieves data from the persisted store.
  • Native (Java Native Interface) interface to WPM: I have to fess up and say I generally hate working with Windows-native APIs. Any day of the week, I would rather hook into a nice Java jar file than a nasty dynamic link library hidden three layers deep. However, if you enjoy this sort of thing, several resources are available for guiding you through using a native interface to read WPM counters from Java. They usually involve either using Microsoft's own JVM with its native Windows interfaces or using JNI to directly communicate with the Windows-native API. Say what you will about proprietary Microsoft Java technology, it is certainly not portable. As far as the JNI solutions go, they appear to need constant changes depending on the versions of Windows and Java you use. The end product is not particularly portable either, since it will only run on Win32.
  • WMI: Windows Management Interface is a scripting interface to the management internals of all Win32 platforms since Windows 98. Some analogize it with Java Management Extensions (JMX) for Windows. WMI makes all sorts of Win32 internals accessible, including WPM counters. The integration of WMI and Java is not provided for, with the exception of Microsoft's proprietary Java VM implementation.

A simple and pure Java API provides a better approach for accessing WPM.

NSClient4j

NSClient4j is a pure Java client that provides a simple API for accessing WPM performance counter data. It uses a Windows service called NSClient. NSClient was originally written as a plug-in component for a system called Nagios, which is a system-monitoring package that runs on Linux. Nagios is a larger monitoring and alerting system that needed a solution for querying NT performance statistics from Linux, and, as a result, NSClient was born. Figure 2 outlines how Nagios works.

Figure 2. What Nagios does. Click on thumbnail to view full-sized image.

NSClient is a native Windows service that listens on a configurable port for requests, receives requests, looks up the corresponding WPM counter value (among other things), and returns the value as a simple string. In its original inception, it was called by a native Linux Nagios plug-in called checknt. However, since the protocol is fairly straightforward, and Java can manage communication through sockets, NSClient4j is simply a Java class that communicates with NSClient. Using the Java API, a developer can connect to NSClient, issue a request for a WPM counter value, and read the response—see Figure 3.

Figure 3. Relationship between NSClient and NSClient4j. Click on thumbnail to view full-sized image.

In Figure 3, NSClient4j asks the NT system how many context switches currently occur per second. Since NSClient4j is pure Java, it can run on any platform with a supported JVM. Figure 4 shows a class diagram of NSClient4j's main classes.

Figure 4. NSClient4j class diagram. Click on thumbnail to view full-sized image.

Install NSClient

Before we get into some examples of how to use NSClient4j, let's review how to install NSClient, since it is a prerequisite. Installing NSClient is simple:

  1. Download NSClient from Resources.
  2. The latest version, as of this writing, is 1.07.1, so you will need to unzip the file Distrib-1.07.1.zip into a dedicated directory on your target (to be monitored) Windows system.
  3. Navigate to that directory in a command shell. This example will assume you have unzipped the file into C:\NSClient.
  4. Depending on whether you are running Windows NT 4 or Windows 2000/2003/XP, navigate into the directory Win_NT4_Bin or Win_2k_XP_Bin, respectively.
  5. Execute the command pNSClient.exe /install. You should see a message pop up like this:

    Figure 5. Successful install message
  6. To later uninstall it, you can execute pNSClient.exe /uninstall.
  7. The service is now installed and must be started. To do this, you can execute the command net start NSClient or go to the services applet in the Administrative Control panel for Windows and start the service named Net Saint NT Agent.

Now that NSClient is installed, we're ready to test NSClient4j.

Command line example of NSClient4j

The following example shows how to code a simple command line client that displays the WPM counter value for the passed host name and counter name. There are two phases to getting a WPM counter reading:

  1. Connect to the target NSClient in one of the constructors to the NSClient4j class. There is one mandatory parameter, the host name (or IP address). The optional parameters are the port number and password. The port number defaults to 1248 and password defaults to None but, for security considerations, these can be changed. See "A Final Note on Securing NSClient" below. Accordingly, the constructor options are as follows:

     public NSClient4j(String hostName) throws NSClient4JException
    public NSClient4j(String hostName, int portNumber) throws NSClient4JException
    public NSClient4j(String hostName, int portNumber, String password)  throws NSClient4JException
    public NSClient4j(String hostName, String password)  throws NSClient4JException
    
    
  2. Call the getPerfMonCounter(String counterName) method.

That's pretty much it. Here's a simple command line example:

 1 package com.marketwide.nagios;
2
3 /**
4 * <p>Title: CLStat</p>
5 * <p>Description: Net Saint NT Client For Java Command Line Example</p>
6 * <p>
7 * <p>
8 * @author Whitehead (nwhitehe@yahoo.com)
9 * @version 1.0
10 */
11
12 public class CLStat {
13   public static void main(String[] args) {
14     try {
15       NSClient4j client = new NSClient4j(args[0]);
16       System.out.print("Result:" + client.getPerfMonCounter(args[1]));
17     } catch (NSClient4JException e) {
18       System.err.println("Exception Geting Stat:" + e);
19     }
20   }
21 }

Here is an example of how I can get my file server's context switch rate:

 C:\JBProjects\NSClient4J> set CLASSPATH=%CLASSPATH%;.\nsclient4j.jar
C:\JBProjects\NSClient4J>java com.marketwide.nagios.CLStat 192.168.1.103 "\System\Context Switches/sec"
Result:3393.68772

That's about as simple as an NSClient4j example gets. One counter you may be interested in accessing frequently is the CPU utilization. Here is an example:

 C:\JBProjects\NSClient4J>java com.marketwide.nagios.CLStat 192.168.1.103 "\Processor(_Total)\% Processor Time"
Result:99.99995

Two things to note: First, the counter's naming convention may seem a bit peculiar. The reason: because it is peculiar; but it is somewhat consistent. I provide further explanation in the following section.

Second, the result indicates my processor time is about 100 percent, which is not actually true. It appears that the inquiry into the CPU utilization rate actually causes the CPU utilization to jump to (nearly) 100 percent during the instant of time which the inquiry occurs. This seems in line with the Heisenberg Uncertainty Principle, which can be summarized as nothing can be measured without affecting what you are trying to measure. All the same, NSClient offers an alternate CPU measurement provided in NSClient4j as the method getCPUUsage(). To offer some consistency, a symbolic shortcut is provided in the getPerfMonCounter(String counterName) call. If you request the counter name CPU, under the covers, the alternate method will be called and return a better reflection of your system's CPU utilization. The following call displays how to retrieve the CPU utilization of the target NT server.

 C:\JBProjects\NSClient4J>java com.marketwide.nagios.CLStat 192.168.1.103 CPU
Result:8

Counter naming

I now return to a discussion on counter naming. For the most part, counter naming is intuitive. A performance counter has somewhere between two and four parts to its fully qualified name. The first part is the host name, which we disregard in this case since it is not needed. (It can prove useful in other scenarios, but that's another story.) The remaining three parts are:

  1. Performance object: A counter's general category. For example: Processor, Memory, TCP.

  2. Counter: The specific characteristic of the performance object you are interested in. For example, Processor contains the following counters, among others: % Processor Time, % User Time and Interrupts/sec.
  3. Instance: Some counters further break down the granularity of the counter itself into instances. For example, the Processor's counters can apply to a specific CPU number or the total CPU resources, which on my super 32 CPU file server would be either a number between 0 and 32, or _Total.

When a counter lacks an instance, it has an intuitive name. For example:

  • Performance object: Memory
  • Counter: % Committed Bytes In Use

The instances, however, add some confusion. Consider this name that tells us the total bytes per second being transferred by my wireless 802.11G network card (as opposed to my internal regular 10/100 Ethernet Card):

  • Performance object: Network Interface
  • Counter: Bytes Total/sec
  • Instance: D-Link AirPlus DWL-G650 Wireless Cardbus Adapter[rev.C] - Packet Scheduler Miniport

In summary:

  • Without instance: \<performance object>\<counter name>
  • With instance: \<performance object>(<instance name>)\<counter name>

Figure 6 should help you navigate the conversion of a WPM counter from the application to your code.

Figure 6. How full counter names map to the WPM GUI. Click on thumbnail to view full-sized image.

Other nifty features of NSClient (and therefore NSClient4j)

NSClient has some extra built-in features to enhance Nagios's ability to monitor the health of Windows servers. Most are also available in NSClient4j as follows:

  • java.util.Date getFileDate(String filename): Returns the date a file was last modified.
  • java.lang.String getNSClientVersion(): Returns the version of the NSClient service.
  • java.util.Date getUpTimeDate(): Returns the date the Windows server started. There are also methods to return the days, hours, minutes, or seconds since the Windows server started.
  • boolean isServiceUp(String serviceName): Returns true if the named service is running on the target Windows server and false if it is not.
  • boolean isProcessUp(String processName): Returns true if the named process is running on the target Windows server and false if it is not.

A final note on securing NSClient

As mentioned previously, NSClient's default password is None, which is built into NSClient4j, as it also is in its Linux brethren, checknt. The same applies to the default port of 1248. For added security, these can be overridden as follows:

  1. Open the Windows Registry Editor by invoking regedit.exe
  2. Find the branch called "My Computer\HKEY_LOCAL_MACHINE\SOFTWARE\NSClient\Params"
  3. You can now edit the password or port values
  4. Once they have been edited, you will need to restart the NetSaint NT Agent service to initiate the new values

In the next example, I change the password to mypassword and the port to 10007. The example is a follow up to the simple CLStat we looked at before, enhanced to account for a custom port and password. It also uses the parameter-less constructor and the correspondingly required init() method (see line 24):

1 2 Page 1