Sun GlassFish Enterprise Server v3 Prelude Add-On Component Development Guide

Updating the Monitorable Object Tree

A monitorable object is a component, subcomponent, or service that can be monitored. Enterprise Server uses a tree structure to track monitorable objects.

Because the tree is dynamic, the tree changes as components of the Enterprise Server instance are added, modified, or removed. Objects are also added to or removed from the tree in response to configuration changes. For example, if monitoring for a component is turned off, the component's monitorable object is removed from the tree.

To enable system administrators to access statistics for all components in the same way, you must provide statistics for an add-on component by updating the monitorable object tree. Statistics for the add-on component are then available through the Enterprise Server administrative commands get(1), list(1), and set(1). These commands locate an object in the tree through the object's dotted name.

For more information about the tree structure of monitorable objects, see How the Monitoring Tree Structure Works in Sun GlassFish Enterprise Server v3 Prelude Administration Guide.

To make an add-on component a monitorable object, you must add the add-on component to the monitorable object tree.

To update the statistics for an add-on component, you must add the statistics to the monitorable object tree, and create event listeners to gather statistics from events that represent these statistics. At runtime, these listeners must update monitorable objects with statistics that these events contain. The events are sent by event provider classes. For information about how to create event provider classes and send events, see Defining Statistics That Are to Be Monitored.

Updating the monitorable object tree involves the following tasks:

Creating Event Listeners

An event listener gathers statistics from events that an event provider sends. To enable an add-on component to gather statistics from events, create listeners to receive events from the event provider. The listener can receive events from the add-on component in which the listener is created and from other components.

To create an event listener, write a Java class to represent the listener. The listener can be any Java object.

Ensure that the class that you write meets these requirements:

A listener is called in the same thread as the event method. As a result, the listener can use thread locals. If the monitored system allows access to thread locals, the listener can access thread locals of the monitored system.


Note –

A listener that is not registered to listen for events is never called by the framework. Therefore, unregistered listeners do not consume any computing resources, such as memory or processor cycles.


Subscribing to Events From Event Provider Classes

To receive events from event provider classes, a listener must subscribe to the events. Subscribing to events also specifies the provider and the type of events that the listener will receive.

To subscribe to events from event provider classes, write one method in your listener class to process each type of event. To specify the provider and the type of event, annotate the method with the org.glassfish.flashlight.client.ProbeListener annotation. In the @ProbeListener annotation, specify the provider and the type as follows:

"component-name:provider-name:app-name:event-type"

Note –

The @ProbeListener annotation is an unstable interface and is subject to change.


component-name

The name of add-on component that is to send the event. This parameter must match the parameter that is defined when the event provider is registered. See Registering an Event Provider.

provider-name

The name of the provider. This parameter must match the parameter that is defined when the event provider is registered. See Registering an Event Provider.

application-name

The name of the application that the add-on component represents. This parameter must match the parameter that is defined when the event provider is registered. See Registering an Event Provider.

event-type

The type of the event. This type is defined in the event provider interface. For more information, see Identifying the Event Type.

In the method body, provide the code to update monitoring statistics in response to the event.


Example 5–4 Subscribing to Events From Event Provider Classes

This example shows the code for subscribing to events of type begin from the tx component. The provider of the component is TxManager. The body of the begin method contains code to increase the transaction count txcount by 1 each time that an event is received.

The definition of the begin event type is shown in Example 5–1.

The code for sending begin events is shown in Example 5–3.

...
import org.glassfish.flashlight.client.ProbeListener;
...
public class TxListener {
    AtomicInteger txCount = ....;

    @ProbeListner("tx:TxManager::begin")
    public void begin(String txId) {
      txCount++;
    }
  }

Registering an Event Listener

Registering an event listener enables the listener to receive callbacks from the Enterprise Server event infrastructure. The listener can then collect data from events and update monitorable objects in the object tree. These monitorable objects form the basis for monitoring statistics.

At runtime, the Enterprise Server event infrastructure registers listeners for an event provider when the event provider is started and unregisters them when the event provider is shut down. As a result, listeners have no dependencies on other components.

To register a listener, invoke the org.glassfish.flashlight.client.ProbeClientMediator.registerListener method in the class that represents your add-on component. In the method invocation, pass the listener object as a parameter.

The registerListener method returns a collection of ProbeClientMethodHandle objects. To enable a listener to turn on or turn off monitoring, pass this collection to your listener class. In your listener class, invoke methods of the ProbeClientMethodHandle objects to turn on and turn off monitoring.

For information about how to register an event provider, see Registering an Event Provider.


Example 5–5 Registering an Event Listener

This example shows the code for registering the event listener TxListener for the add-on component that is represented by the class TransactionManagerImpl.

Code for the following methods of the TxListener class is beyond the scope of this example:

...
import org.glassfish.flashlight.client.ProbeClientMediator;
...
public class TransactionManagerImpl {

    @Inject
    private ProbeClientMediator pcm;

...
    TxListener txL = new TxListener(txmNode);
    Collection<ProbeClientMethodHandle> handles = pcm.registerListener(txL);
    txL.setProbeListenerHandles(handles);
...
}

Adding Statistics for a Component to the Monitorable Object Tree

Adding statistics for a component to the monitorable object tree makes the component and its statistics monitorable objects.

Adding a statistics for a component to the monitorable object tree involves the following tasks:

Creating a TreeNode Object to Represent a Component

To a create a TreeNode object to represent a component in the monitorable object tree, invoke the static method createTreeNode of the org.glassfish.flashlight.datatree.factory.TreeNodeFactory class. Invoke this method in the class that represents your component.

In the invocation of the createTreeNode method, pass the following information as parameters to the method:

Creating Objects to Represent a Component's Statistics

Create one object to represent each statistic that you are adding to the monitorable object tree. Create the objects in your listener class or in the class that represents your add-on component. Each object must be an implementation of an interface that extends org.glassfish.flashlight.datatree.TreeNode.


Note –

The TreeNode is an unstable interface and is subject to change.


To specify the name of the node in the monitorable object tree that the object represents, invoke the object's setName method. In the invocation of the setName method, pass a string that contains the name of the node as a parameter to the method.

The object that represents a statistic must also provide methods for computing the statistic from event data.

The org.glassfish.flashlight.statistics package provides the following utility classes to gather and compute statistics data:

Average

Provides averages.

Counter

Provides a counter that a class can use to maintain count.

TimeStats

Provides timing information in seconds.

TimeStatsMillis

Provides timing information in milliseconds.

TimeStatsNanos

Provides timing information in nanoseconds.


Note –

The classes in the org.glassfish.flashlight.statistics package are unstable interfaces and are subject to change.


The org.glassfish.flashlight.statistics.factory package provides a factory class for each utility class as shown in the following table.

Utility Class 

Factory Class 

Average

AverageFactory

Counter

CounterFactory

TimeStats

TimeStatsFactory

TimeStatsMillis

TimeStatsFactory

TimeStatsNanos

TimeStatsFactory

Getting the server Node Object

The server node object is the parent of the TreeNode object that represents the component in the monitorable object tree.

To get the server node object, invoke the get method of the org.glassfish.flashlight.MonitoringRuntimeDataRegistry class. In the invocation of the get method, pass the string server as a parameter.

Adding an Object to the Tree

To add an object to the tree, invoke the addChild method of the object's parent object. In the invocation of the addChild method, pass the TreeNode object that you are adding as a parameter.

The parent object depends on whether the object represents an add-on component or a statistic:

Dotted Names for an Add-On Component's Statistics

The Enterprise Server administrative commands get(1), list(1), and set(1) locate a statistic through the dotted name of the statistic. The dotted name of a statistic for an add-on component is determined from the names of the TreeNode objects that represent the statistic and the component in the monitorable object tree as follows:

server.componenent-treenode-name.statistic-treenode-name
componenent-treenode-name

The name of the TreeNode object that represents the component in the monitorable object tree. This name is passed In the invocation of the createTreeNode method that creates the object. For more information, see Creating a TreeNode Object to Represent a Component.

statistic-treenode-name

The name of the TreeNode object that represents the statistic in the monitorable object tree. This name is passed In the invocation of the setName method. For more information, see Creating Objects to Represent a Component's Statistics.

Example of Adding Statistics for a Component to the Monitorable Object Tree


Example 5–6 Adding Statistics for a Component to the Monitorable Object Tree

This example shows the code for adding the totaltransactioncount statistic to the monitorable object tree. To add this statistic, objects are added to the monitorable object tree as follows:

...
import org.glassfish.flashlight.client.ProbeListener;
import org.glassfish.flashlight.datatree.TreeNode;
import org.glassfish.flashlight.datatree.factory.TreeNodeFactory;
import org.glassfish.flashlight.statistics.Counter;
...
public class TransactionManagerImpl {

    @Inject
    private MonitoringRuntimeDataRegistry mrdr;

    private TreeNode serverNode;
    private Counter totalTxCount = CounterFactory.createCount();

    public void init (){
        ...
        TreeNode txNode = TreeNodeFactory.createTreeNode("tx", null, "transactions");
        TreeNode serverNode = getServerNode();
        serverNode.addChild(txNode);
        ...
        totalTxCount.setName("totaltransactioncount");
        txNode.addChild(totalTxCount);
        ...
    }
...
    private TreeNode getServerNode() {
        TreeNode serverNode = null;
        if (mrdr.get("server") != null) {
            serverNode = mrdr.get("server");
        } else {
            serverNode = TreeNodeFactory.createTreeNode("server", null, "server");
            mrdr.add("server", serverNode);
        }
        return serverNode;
    }
...
}