Access Windows Performance Monitor counters from Java, Part 2

Integrate NSClient4j with Java Management Extensions

NSClient4j is a pure Java API that provides simple and quick access to Windows Performance Monitor (WPM) statistics. These statistics prove invaluable for monitoring your Windows servers and providing a baseline for activities such as capacity planning and trouble shooting. Additionally, access to low-level performance or operating statistics can be useful in your low-level code, such as the current rate of GETS against your IIS (Internet Information Server) Web server.

In this article, the continuation of my series on WPM, I present a brief introduction to Java Management Extensions (JMX) and its benefits. I then explain how to implement JMX-based services for NSClient4j and describe different methods for implementing that technology.

Changes in NSClient4j since Part 1

As a brief aside, I want to enumerate some changes and enhancements that have been made in the NSClient4j package since Part 1 of this series:

  • The main package name has migrated from com.marketwide.nagios to org.nsclient4j.
  • Calls have been added to the NSClient4j class as convenience methods:
    1. getUsedDiskSpace(String diskVol)
    2. getFreeDiskSpace(String diskVol)
    3. getTotalDiskSpace(String diskVol)
    4. getUsedPercentDiskSpace(String diskVol)
    5. getFreePercentDiskSpace(String diskVol)
  • To accommodate NSClient4j implementation in the Oracle 9i internal JVM, the source code is now fully supported under J2SE 1.3.
  • Additional error handling identifies the cause of any errors emerging from the WPM engine (e.g., "Unrecognized pattern," or "Counter not found"), and the NSClient4JException has been extended to differentiate between transport errors and WPM errors.
  • New JMX-based classes provide JMX instrumentation of the WPM engine, which is this article's focus.

Recap of basic NSClient4j functionality

To provide a quick review of the NSClient4j functionality, the code below shows a few lines of Java code connecting to an NSClient server on a Windows host and acquiring the system's context-switch rate per second.

Listing 1. Source for CLStat, a simple NSClient4j example

 public class CLStat {
  public static void main(String[] args) {
    try {
      NSClient4j client = new NSClient4j("192.168.1.4", 1248);
      System.out.println("Result:" + client.getPerfMonCounter("\\System\\Context Switches/sec"));
    } catch (NSClient4JException e) {
      System.err.println("Exception Geting Stat:" + e);
    }
  }
}

Listing 2. Run the CLStat example

 

c:\temp>set CLASSPATH=c:\nsclient4j-root\nsclient4j\dist\nsclient4j.jar;%CLASSPATH%

c:\temp>java org.nsclient4j.CLStat Result:4120.66700

Now that we have reviewed the basics of NSClient4j, let's look at JMX and how it can be implemented to support NSClient4j.

NSClient4j and JMX

The Java Management Extensions technology is a Java standard for building management and monitoring components for applications. Though NSClient4j provides a satisfactory low-level API for accessing WPM statistics (see Figure 1), a monitoring layer implemented in JMX provides both a higher standard of integration and compliance while significantly extending NSClient4j's functionality.

Figure 1. Monitoring a server directly. Click on thumbnail to view full-sized image.

Let's consider some of the advantages of a JMX layer for NSClient4j:

  • A standard API for accessing and monitoring target systems: Face it, there are enough APIs out there, and if we can implement an existing one to acquire and monitor performance data on Windows servers, we avoid API proliferation and gain a better integrated heterogeneous monitoring system. JMX instrumentation is widely implemented, and we can now add Windows servers to the list of systems and applications that JMX can monitor.
  • JMX is not, admittedly, ubiquitous, but several supported mechanisms map JMX to other monitoring and management infrastructures such as SNMP (Simple Network Management Protocol) and CIM (Common Information Model).
  • JMX provides a wide selection of additional services useful in a monitoring environment, such as gauges, events, notifications, and a series of connectivity options.
  • On a more practical level, JMX provides a better infrastructure than a custom-built framework for making this information available, and provides separation of concerns between NSClient4j's low-level data collection capabilities and JMX's monitoring capabilities. Another issue is traffic against a critical Windows server for providing performance data to numerous interested parties. JMX provides a way to proxy this traffic and simultaneously gather current statistics through only one connected agent and supply data to many subscribers.

    Now, compare Figure 1 with Figure 2.

    Figure 2. Monitoring a server using JMX as a proxy

In this article, I discuss the development and implementation of NSClient4j using different JMX options. The goal is create an NSClient4j JMX service that will scan a set of performance counters and expose functionality in JMX to query that data. To do that, we will:

  • Create an MBean and define the lifecycle of the monitoring process.
  • Implement a timer so scans can execute on a defined frequency
  • Store the results of the scans and expose them as JMX attributes

Introduction to JMX

If you are already familiar with JMX, you will not learn anything new here. However, instead of presenting a comprehensive JMX tutorial, I intend to give an idea of how JMX works. A full JMX tutorial can be found in Resources.

The central structure in a JMX service is the agent, also referred to as the JMX agent. You can think of this as a sort of component bus. The service providing components are called MBeans (management beans), which are registered with the MBeanServer at the beginning of their lifecycles. The MBeanServer provides a set of services for the registered MBeans:

  • Invocations of operations against MBeans are made to the MBeanServer, which in turn invokes against the specified registered MBean
  • The MBeanServer retrieves attributes of the registered MBeans
  • The MBeanServer acquires extensive metadata about the registered MBeans
  • The MBeanServer creates and registers new MBeans

For the full MBeanServer API, see Resources.

This architecture, as illustrated in Figure 3, excels at isolating components. For example, a client that must acquire data from a variety of different MBeans in the MBeanServer does not need any of the low-level proprietary classes in its classloader. All operations against an MBeanServer are designed to be highly abstracted to allow a wide variety of hosted MBeans. This abstraction, the rich metadata, and the isolation provided by MBeanServer creates a powerful mechanism; you will find that JMX-supported applications will integrate seamlessly with any type of MBean.

Figure 3. A generalization of the JMX architecture. Click on thumbnail to view full-sized image.

MBean identity and ObjectNames

An MBean can be a simple class that does not necessarily have the more complex lifecycle and container relationship contract as an Enterprise JavaBeans (EJB) component. However, different types of MBeans require different types of support to be registered in an MBeanServer. In this article, we review two types of MBeans: standard MBeans and dynamic MBeans.

All MBean services are exposed through the MBeanServer, so, to specifically target an MBean operation, a unique identifier is needed for each registered MBean. This identifier is an ObjectName (javax.management.ObjectName). Each MBean registered in the MBeanServer has a unique ObjectName. Figure 4 shows its basic structure.

Figure 4. ObjectName structure. Click on thumbnail to view full-sized image.

The components of an ObjectName are:

  • A domain name: A simple dot-separated compound name (e.g., org.foo.bar).
  • A set of key properties made up of name-value pairs (e.g., type=Foo, name=Bar). At least one key property is required.

The domain is separated from the properties by a colon, and the key properties are separated by commas. An example of a full ObjectName is: org.foo.bar: type=Foo, name=Bar.

See Resources for the ObjectName Javadoc.

Exposing functionality and metadata

When an object is registered as an MBean with an MBeanServer, the MBeanServer expects a mechanism to determine that object's exposed functionality. The categories of metadata are as follows:

  • Attributes: Single fields of data managed by the MBean
  • Operations: Functions with zero or more parameters implemented by the MBean
  • Constructors: Exposed constructors that the MBeanServer can use to construct new instances
  • Notifications: Notification callbacks emitted by the MBean

Our first example of an NSClient4j MBean is org.nsclient4j.NSClient4jService, a simple example of a standard MBean. Standard MBeans have static metadata defined completely by the interface the class implements. The interface must be in the package and adopt the naming convention <MBeanClassName>.MBean. So, in this instance:

The MBeanServer exposes the functionality defined in the NSClient4jServiceMBean interface.

NSClient4jService in detail

In the NSClient4jService example, I hard-coded an MBean class to track three statically defined Windows Performance Monitor counters:

  • System thread count
  • Percentage of memory in use
  • CPU utilization

The counters cannot be changed without recoding the MBean class and interface. This provides us a simple example to get started, but has obvious reuse and extensibility limitations.

Figure 5 shows the class structure of the org.nsclient4j.NSClient4jServiceMBean interface and the concrete implementation of that interface in the class org.nsclient4j.NSClient4jService.

Figure 5. NSClient4jService and MBean interface

The lifecycle of this simple MBean is as follows:

  1. The MBean class is constructed. There are two constructors, one is parameterless, and one is supplied all the runtime arguments required to run the MBean. These are:
    1. The host name of the target host to monitor.
    2. The frequency to poll the target host.
    3. The name of the scheduling MBean. (See "Scheduling Events" later in this article).
  2. The start() method is called. This creates a new NSClient4j instance for the target host and registers a scheduled callback from the JMX agent's scheduling service. The callback invokes NSClient4jService's run() method.
  3. Every time the scheduling service invokes the callback() method, the NSClient4jService uses the NSClient4j instance to update the performance counters.
  4. The JMX agent responds to requests for counter values.
  5. The stop() method is called to shut down the scheduling service callbacks and close the NSClient4j instance.

The NSClient4jService class implements the NSClient4jServiceMBean interface by convention to adopt that interface as the JMX instrumentation layer. The NSClient4jService class implements the javax.management.MBeanRegistration interface as a convenient way to get a handle to the MBeanServer, which is passed in on the preRegister() method. The NSClient4jService class implements the javax.management.NotificationListener interface so its instances can be registered as callback handlers for the scheduling service.

Running the NSClient4jService

At this point, we have a fairly simple class that has the trappings of a JMX MBean, but does not serve as one until a JMX agent loads and registers it. For an MBean like this, some JMX agents will have different ways for loading and registering. We will review some proprietary approaches later, but for now, let's examine two simple procedures for loading and running the NSClient4jService MBean using J2SE 1.5's built-in JMX agent:

  • A custom bootstrap class
  • The JMX m-let service

Custom bootstrap class

The custom bootstrap class NSClient4jServiceBootStrap implements all the required steps to create, register, and run the MBean. The class must be run in J2SE 1.5+, which has a built-in JMX agent. Calling the class on the command line results in the following actions:

  1. NSClient4jServiceBootStrap instantiates an NSClient4jService object and initializes the host name to the single command line parameter. The frequency is hard-coded to 5,000 ms.
  2. A new object name is created for the MBean called org.nsclient4j:type=Monitor,name=<host name>.
  3. The MBeanServer is acquired using the javax.management.MBeanServerFactory class.
  4. The scheduling service MBean is registered to provide scheduling services. Your JMX agent provider may be preconfigured to register a scheduling MBean off the bat, but in this simplified example, we must do so ourselves.
  5. The NSClient4jService MBean is registered and then started.

Listing 3 shows how the custom bootstrap class is invoked to monitor localhost:

Listing 3. Run the simple bootstrap class

1 2 3 4 Page 1
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.