Introduction

Before anything can be reported, the application have to expose it's state to the monitoring infrastructure. In Commons Monitoring vocabulary this is called instrumentation of the application. Commons Monitoring defines a simple lightweight API for this purpose.

Concepts

Monitors

The application exposes it's state based on monitors . A monitor is an abstraction for any element in the application that can expose state or resource consumption. This can be a code fragment, a web application URI, a JDBC query, some business object data, etc. It is identified by :

  • a name that is the human readable representation of the exposed state
  • a category that matches technical layering of the application ("web", "model", "dao"...)
  • a subsystem that associate the monitor to a functional subsystem in the application ("admin", "accounts management" ...)

Only the name is required, but category and subsystem is a nice way to group monitors by technical or functional criteria.

Repository

Monitors are registered in a repository, that ensure a monitor is unique for a name/category/subsytem Key. The repository is used to retrieve existing monitors and create new ones. The default repository implementation creates new Monitor instance when a non-existing one is requested, so you don't have to wory about monitors management.

            Monitor monitor = repository.getMonitor( "MyService.myMethod" );
            Monitor monitor = repository.getMonitor( "SoapEndpoint.process", "soap" );
            Monitor monitor = repository.getMonitor( "/admin/userEdit.do", "struts", "user management" );
        
You can use a custom repository by extending one of the provided implementations. You can also use the ConfigurableImplementationsRepository implementation, when you only want to configure custom implementation classes for StopWatches and Monitors.

Counters and Gauges

Monitors manage a set of StatValues that the application uses to expose state. The monitor only identifies where the data comes from, and the statValues handle the monitored data. There is two types of values that application can use, depending on the data to be exposed :

  • a Counter is used to expose cumulative events. The value a counter maintains will grow during the application life : time elapsed by some code to execute, number of bytes or lines proceeded by a batch process, number of requests on a web URI...
    A counter is used by application using the add() method to expose how the counter must increment when some operation have proceeded.
  • a Gauge is used to expose an internal state that increases and decreases during application life : concurrent threads, open connections, active users...
    A gauge is used by the application using the incremenet() and decrement() methods to expose the application state changes. The set() method can also be used to force an initial value or to expose an absolute value when the application does not compute it's state as a change from a previous value. Typically, a connectionManager component will use increment/decrement to expose active connections, and a fileSystemMonitor will use set to expose free space on disks.

In both cases, the statValues compute statistical information from what the application exposes, like min / max / mean and standard deviation, that in many case is more informative than the current value. Available statistical indicators are limited as a StatValue does not maintain all the individual elements as a serie but only aggregates, to avoid memory over-consumption.

The default monitor implementation will create the required Gauge/Counters implementation when a statValue is requested by the application.

Role

A monitor can handle many statValues. StatValues are identified in a monitor by a role, that describes the data beeing computed. There is predefined roles for performances, concurrency monitoring and failures count, but any other relevant counter/gauge can be registered to a monitor.

            final static Role BYTES = new Role( "bytes", Unit.BYTES, Counter.class );

            static Monitor monitor = repository.getMonitor( "SoapEndpoint.process" );
            static Counter bytes = monitor.getCounter( BYTES );

            public void process( SOAPMessage message )
            {
                // Process a SOAP message

                // retrieve the custom Counter for the "byte" role
                bytes.add( SOAPMessage.getSize(), Unit.BYTES );
            }
        
A role can be considered as a statValue prototype. It defines :
  • The name of the statValue inside the monitor
  • The unit used for data gathered by the statValue
  • The statValue type, beeing either Counter.class or Gauge.class

Units

Counters and Gauge knows the data type they hold, based on the Role used to create them : Any data set/addition is checked for unit to be compatible. "compatible" means the passed values can be converted to the same primary unit, "primary" beeing the finest unit available for a data type. For example, Unit.SECONDS, is compatible with Unit.MILLIS as they share the same primary unit Unit.NANOS.

You can define your own units on the same basis, to ensure good usage of your monitors and cleaner reporting. You can also pass data to a statValue with any compatible Unit, as the statValue will internally handle any required conversion.

StopWatches

Performance monitoring is first-class use case of Commons Monitoring. The org.apache.commons.monitoring.StopWatch class provides the necessary tooling to compute and monitor code or service invocation performances. A StopWatch is created by the repository for a monitor. The stopwatch is initialy "started", and will compute elapsed time until it is stopped by the application. The application MUST ALLWAYS stop the StopWatches it has created ! To ensure this, always use a finally block :

            StopWatch stopWatch = repository.start( myMonitor );
            try
            {
                // Do something that takes time and requires monitoring
            }
            finally
            {
                stopWatch.stop();
            }
        

You can nest stopWatches, in many case by monitoring some high-level process (for example web request rendering time) and nested low-level service (remote service invocation, JDBC request...). The monitor maintains statistics about those informations as the PERFORMANCE and RESPONSE_TIME counters. First one only computes performance of the target code, not sub-processes.

The default StopWatch implementation can be extended to support some custom features. ExecutionStopWatch for example adds support for a list of all stopwatches beeing used in the current thread, so that you can trace the activity if you detect bad performances of the global process. To use a custom StopWatch class, simply setup the repository using new DefaultRepository( MyCustomStopWatch.class ).

Helpers

The Monitoring class is a convenience utility class to make application instrumentation as simple as possible. To monitor application performance, simply do :

        public void myMethodToGetMonitored()
        {
            StopWatch stopWatch = Monitoring.start( "MyClass.myMethod" );
            try
            {
                // Do something that takes time and requires monitoring
            }
            finally
            {
                stopWatch.stop();
            }
        }
        
The StopWatch class will compute the time elapsed during code execution and report it to the monitor "MyClass.myMethod".

Other helper classes are provided for simplier use with commons frameworks. The org.apache.commons.monitoring.aop package contains for example classes for use with AOP frameworks to automagically instrument application components.