In many case, the application itself can take advantage of the monitoring infrastructure either to adapt it's behavior or to compute finest state to expose.
For example, the application can switch between two implementations of a component depending
on the business process load. A monitor that computes this load can be used by the application to
detect the overload and switch to a lightweight implementation. To implement this, the application
may use the monitor and programmatically (in a
if then else block) select the
implementation to use. A more elegant way is to attach a Listener to the Gauge that monitors the load.
Repository, Monitors and StatValues support listeners. The
allows custom code to get notified when a value is updated. This is a nice way to detect some
value to increase abnormally and to adapt application behavior. The main advantage is that such
listener can be reused and don't require code intrusive changes in the monitored components.
Monitor.Listener allows the application to get evolved when a new StatValue is registered
to the monitor. The application can register new statValues (or automagically creates new ones
when requested) at any moment, and this listener can be used to get notified and pre-configure the
statValue before it gets used.
Repository.Listener can be used by the application to get notified any time a new monitor
instance is created, for example to register a Monitor.Listener !
A listener can be used to detect that a business process exceed a maximum execution time. Just counting such overload events is informative but don't give finest info about the context and how to improve application scalability.
The StopWatches used to monitor execution can be registered in the
class that maintain the set of active stopWatches for the current thread. It is recommended
to let the stopWatches register themselves and cleaning the stack by configuring the Repository to use
ExecutionStopWatch StopWatch implementation.
When the Listener on the business process detects some overload, it can look at the ExecutionStack for the most time-consuming sub-process and log contextual information of what exactly happened. This is really useful to detect bottlenecks and concurrency issues, as the application can auto-diagnostic itself JUST when the bottlenecks occurred, with execution context available.
Listeners are low-level hooks to observe the monitored state and the state exposed by the application.
A higher level is provided via the
Secondary repositories are used to observe the monitored state for a period of time, where Listeners
are used to observe individual monitoring events.
When a SecondaryRepository is created, it registers all the required listeners to maintain a set or secondary monitors / counters / gauges in sync with the "primary" repository. A secondary gauge will share the initial state of the primary gauge. A secondary counter will start with initial value set to 0. The secondary repository can so be used to monitor the application during a period as if monitoring had just been reseted. It can then be detached from the primary repository, and will then not get notified anymore on application monitoring events.
Secondary repositories are the first-class component for building a time-based monitoring console. See reporting section for more information on there usage for this use case.