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:
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:
The return value of all callback methods in the listener must be void.
Because the methods of your event provider class may be entered by multiple threads, the listener must be thread safe.
The listener must have the same restrictions as a Java Platform, Enterprise Edition (Java EE) application. For example, the listener cannot open server sockets, or create threads.
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.
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.
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"
The @ProbeListener annotation is an unstable interface and is subject to change.
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.
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.
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.
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.
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 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.
To turn on monitoring, invoke the enable method. If monitoring is turned on, a functional implementation of methods in is generated when the event provider is registered.
To turn off monitoring, invoke the disable method. If monitoring is turned off, a nonoperational implementation of methods in is generated when the event provider is registered.
For information about how to register an event provider, see Registering an Event Provider.
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:
The TxListener constructor
The setProbeListenerHandles method
... 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 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 the component in the monitorable object tree
Creating objects to represent the component's statistics in the monitorable object tree
Getting the server node object
Adding each object to the tree
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:
A string that contains the name of the node
An instance of the class that represents the component
A string that describes the category of the component
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.
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:
Provides averages.
Provides a counter that a class can use to maintain count.
Provides timing information in seconds.
Provides timing information in milliseconds.
Provides timing information in nanoseconds.
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 |
---|---|
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.
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:
If the object represents an add-on component, the parent is the server node object.
If the object represents a statistic, the parent is the TreeNode object that represents the add-on component.
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
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.
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.
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:
The component that is represented by the class TransactionManagerImpl is added as a child of the server node of the tree. The name of the node is tx. The category is transactions. The dotted name of the monitorable object that represents the component is server.tx.
The totaltransactioncount statistic is added as a child of the tx node of the tree. The dotted name of the monitorable object that represents the statistic is server.tx.totaltransactioncount.
... 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; } ... }