Excalibur Instrument - Overview

Why Instrument Was Created

Instrument was created out of a desire to provide a standard API for adding profiling or instrumentation hooks into an application or class. As any application grows in complexity the ability to understand the interactions and resource usages of its individual components becomes increasingly difficult.

Logging tools have helped by making it possible to maintain debug and informational log messages throughout the code. This output can be enabled or disabled at will and then used to help understand the flow of an application.

However, while logging is indispensable in many areas, it is not very useful at tracking quantitative information over time. There was a need to be able to collect information over time to be able to monitor quantities like memory usage, pool sizes, counts, and durations over time.

When To Use Instrument

Instrument is an API for enabling the collection of qualitative information from a component. The API itself has no dependencies on the Avalon framework and can thus be used to instrument any application.

Instrumenting an application should be thought of in the same way as adding support for logging. Just like logging, instrumentation can be very useful in all phases of an applications life. During development, information collected can be invaluable to help track down bottlenecks, leaks, or simply in understanding the flow of a system. Once an application has been released, the instrument output can be used to monitor the resources consumed by the application as well as the loads that are placed on it over time.

Portability

The Instrument API has been carefully designed in such a way as to remove any limitations on where components making use of the API can be used. Most logger APIs require that a logger be configured before components making use of their APIs will function correctly. Failing to configure the component with a logger will using result in NullPointerExceptions or similar problems.

Instrumentation takes a different approach by providing an opaque API which makes it possible for a component providing instrumentation output to function the same whether the output is being collected or not. Output is provided to the outside world by making use of Instrument instances within the component. The component will work identically even if run in an environment which is completely unaware of the Instrument API. This should remove all portability fears.

Performance

Another concern with any tool like this is performance. Many users ask, "How will instrumenting my component affect its performance." The answer is that the Instrument API was designed from the beginning with performance in mind. When a component implementing the Instrumentable interface is instantiated, it must be registered with an InstrumentManager. Upon registration, the component is queried for a list of any Instruments or child Instrumentables that it would like to publish. If the component is never registered, or until the time that the registered Instument output is actually needed, the Instruments them selves are effectively noops in the code. For this reason, other than in the case of an extremely tight loop, instruments can be added to code without any fear of a negative impact on their performance.

When an InstrumentManager receives a request for output from a particular Instrument, there will be a slight performance hit caused by the actual collection of the output. However, the collection of data points has been designed to avoid affecting performance as much as possible.

Core Concepts

When working with the Instrument API, there are two main classes that you need to be aware of.

The first is the Instrumentable interface. This interface must be implemented by any class wishing to be registered with an InstrumentManager and then publish Instrument output. The interface provides methods used by an InstrumentManager to query the component for its name, Instruments, as well as any child Instrumentable objects. See the Instrumentables section for more information.

The second is the Instrument interface. It should not be necessary to implement this interface yourself. The Instrument API provides to two implementations which have so far covered all requred types of output. The first is the CounterInstrument which is used to count the number of times an event takes place. The second is the ValueInstrument which is useful for tracking changes in a value over time. Examples of the later are memory allocation, pool sizes and durations. See the Instruments section for more information.

The Instrument API also provides InstrumentManager and InstrumentManageable interfaces. The InstrumentManager interface must be implemented by any class which wishes to act as an InstrumentManager. In most cases the DefaultInstrumentManager can be used. It is provided by the Instrument Manager project.

The InstrumentManageable interface should be implemented by any component which needs to be able to have access to the InstrumentManager. In most cases, only elements of a container need to implement this interface.

In order to make use of the Instrumentation added to components, they must be registered with an Instrument Manager. If an Instrument Manager aware container is used, this will be automatic. Currently, both the Excalibur Component Manager and Excalibur Fortress know how to manage and register Instrumentable components.

Once an application is running with an active, users can connect to the InstrumentManager and request instrumentation output from any registered Instrument in the application. The most common method of connecting to an InstrumentManager is to make use of the Instrument Client. The Instrument Client provides a Swing based GUI that makes it easy to monitor several Instruments at once. For other options read over the documentation of the Instrument Manager.

by Leif Mortenson