One issue that seems to surface in every project I work on is the need to collect metrics about the various aspects of application performance. To simplify adding metric-tracking capability to my applications, I’ve created a set of Java classes that I can add to any project and reference throughout the running code to accumulate data.
Define your metrics
The first step in collecting metrics is defining what measurements you’ll actually need. As you develop more applications, you’ll develop a library of common metrics for different types of programs.
The set of classes I use to collect metrics takes advantage of a properties file to define available metrics and what different types to apply to those metrics. I’ve categorized metrics within the collection system into five types:
- · Time stamp
- · Elapsed time
- · Indicator
- · Static
- · Average
You may decide to expand on these five types, but I’ve found that they cover most of the items you would collect in a typical application.
The Time Stamp is simply a date and time value. Typically, it’s used to store the exact time of an event.
The Elapsed Time metric is similar to a time stamp, except that it reports the amount of time that’s elapsed since the metric was set. You could calculate the elapsed time from a time stamp value, but themetric classes reports the number without requiring further calculations.
The most common metric type is Indicator, since it’s basically a count. Each time an indicator metric is set, the value is incremented to an updated count.
A Static metric is a numeric value that retains only the last or previous setting.
Average metrics track measurements and maintain a running average.
Metrics are stored in long values, so the totals are limited to 263-1.
Descriptions for the metrics are read from a property file, shown in Listing A, by the metric manager class. In addition to the individual metrics, a log interval and host are set in the properties file. Each metric is defined by assigning a number, name, description, and a reset value. The name is used for logging the metric (I use log4j for logging) and the reset property defines whether this metric is reset each time it is reported. The reset is useful for sending metrics to another collection program that expects only changed values. A reset value of true will clear the value in each metric once it has been logged.
Control the metrics
The metrics are set up and controlled by a management class named MetricManager. The MetricManager is a Singleton that reads in the available metrics and sets the initial values for those metrics. The MetricManager class is shown in Listing B.
More on Singleton patterns
A Singleton pattern ensures that there is only one instance of a class and provides a single point of access to that instance. For another example of a Singleton pattern, see Building Your Own JDBC Connection Pool.
The MetricManager implements an interface called TimerCallBack that initiates logging each time the log interval in the property file is reached. This implementation uses a custom TaskTimer class, shown in Listing C. One improvement to this set of classes would be to use the standard timer facilities available in Java.
The MetricManager class includes various methods for adding metrics from other classes. The add method is overridden to allow adding integers, longs, and Calendars. A shutdown method ensures that the MetricManager class has an opportunity to log existing values before the class is destroyed. Another class, MetricId, stores static constants for easy reference (MetricId also is used in Listing B). These static constants are used by various classes to reference the appropriate metric during an add method call.
The MetricManager class accumulates metrics from the properties file and uses that information to store each defined metric in a Metric class. The Metric class, shown in Listing D, defines the functionality necessary to store each metric. Most of the Metric class implementation is designed to accumulate and output the metric values. This class could be changed to an interface, and a different implementation of the interface could support the type of data for each individual metric. In my current approach, the types are all handled by a single class that is aware of the different types.
To use the metrics tracking classes, an individual class must import the appropriate package and obtain an instance of the MetricManager. Listing E includes a sample class that implements the metrics and adds to one of the values.
This sample class declares a static class variable to hold a reference to the MetricManager. Next, the code uses the MetricManager to add values to the metrics for application started and running time by referencing the MetricId class constants. You can add these lines of code throughout application routines to track various values for operations and other organizational needs.
Knowledge is power
The classes used to track metrics in this article illustrate a framework you can use to implement your own metrics tracking. These classes are ready to compile. Tracking vital metrics in your application is essential in managing an application, and now you have a starting point.