IceMaster

Instrumentation Facility

The Ice run time can be instrumented using observer interfaces that monitor many aspects of the run time's internal objects and activities, including connections, threads, servant dispatching, proxy invocations, endpoint lookups and connection establishment. We refer to these internal objects and activities as "instrumented objects" in the discussion below. The application is responsible for implementing the instrumentation observer interfaces. Note however that an implementation of these interfaces is provided by the Metrics Facet, so most applications do not need to implement them and can instead collect metrics through the MetricsAdmin facet. The definition of the instrumentation interfaces can be found in the Ice/Instrumentation.ice Slice file.

The Ice run time uses the Ice::Instrumentation::CommunicatorObserver interface to obtain observers for instrumented objects created by the run time:

The Ice run time calls the appropriate get...Observer operation each time a new instrumented object is created. The implementation of these methods should return an observer, or nil if the implementation does not want to monitor the instrumented object. This observer is associated with the instrumented object and receives notifications of any changes to its attributes or state. All observer interfaces derive from the Ice::Instrumentation::Observer base interface:

The attach operation is called upon association of the observer with the new instrumented object. The detach operation is called when the object is destroyed. The failed operation is called to report any failures that might occur during the lifetime of the instrumented object. Observer specializations provide additional operations for monitoring other attributes. For example, here is the Ice::Instrumentation::ConnectionObserver interface:

The sentBytes and receivedBytes methods are called by the Ice connection when new bytes are received or sent over the connection.

Shown below is an implementation of the communicator and connection observer interfaces to record sent and received bytes on a per-connection basis. The observer dumps how many bytes were received and sent for the connection when it is detached:

You can install a CommunicatorObserver object on either the client or the server side (or both). Here is some example output produced by installing our CommunicatorObserver and ConnectionObserver object implementations in a simple server:

In addition to the operations for retrieving observers, the CommunicatorObserver interface also defines a setObserverUpdater operation that is called by the Ice run time on initialization to provide an updater object to the CommunicatorObserver implementation. This updater object can be used to "refresh" some of the created observers. The updater object provided by the Ice run time implements the following interface:

The CommunicatorObserver implementation can call these operations to update the observers associated with Ice connections or threads. When one of these operations is called, the Ice run time calls the matching get...Observer method on the CommunicatorObserver interface for each of the instrumented objects. For example, if you call updateConnectionObservers, your implementation of getConnectionObserver will be called again for each Ice connection in the communicator. The previous parameter to getConnectionObserver represents the observer that is currently associated with the connection.

This mechanism can be used to re-configure the observers associated with instrumented objects. For instance, the application might not wish to instrument connections all the time but only when needed. It can use the observer updater to enable or disable the instrumentation. Here is the example above modified to provide this functionality:

As you can see in the example above, special care needs to be taken with respect to synchronization. The Ice run time can call observers with Ice internal locks held to guarantee consistency of the information passed to the get...Observer methods. It is therefore important that the implementation of your observers performs quickly and does not create deadlocks. Your observers should not make remote invocations or call Ice APIs that require acquiring locks on instrumented objects.