Riena/Getting Started with Client Monitoring
Getting Started with Client Monitoring
Oh, no, stop! No, that's of course NOT the intent of Client Monitoring.
The problem that we want to help solving with Client Monitoring is to automatically provide the operators of business applications with measurements about the health and/or usage of a system. With this information a system can be optimized (e.g. bugs fixed, user interface improved, etc.) before the user of the system stumbles upon these issues.
Furthermore the automatically provided information can be much more precise than bug reports entered by the user - can because the developers of the application are now responsible for providing the necessary information, not the user. Remember the targeted user of a Riena application is not a developer.
Possible kind of measurements:
- logging data, e.g. certain events produced by Eclipse's LogService
- usage data
- more technical, e.g. bundle state change
- user interface usage tracking
- tracking of application function usage
The Client Monitoring requires two bundles
- org.eclipse.riena.monitor.common - containing classes and interfaces that are common to both client and server side of the application. This is a necessity when using Riena's communication
- org.eclipse.riena.monitor.client - containing the aliens - ehm - no the workhorses
The structure of the Client Monitoring is quite simple. There are a bunch of collectors gathering the required information and passing them to the aggregator. The aggregator puts this information in a store and activates the sender. The sender transmits the information to the receiver which is usually a Riena remote service. Activation of the sender is usually triggered by the collectors but can also triggered by any other component.
Collectors gather the information that should be transferred to the server. They have to either implement the interface
org.eclipse.riena.monitor.client.ICollector or extend
org.eclipse.riena.monitor.client.AbstractCollector - extending the
AbstractCollector is easier. There are already a few ready to use collectors, e.g the
LogServiceCollector. All collectors have to be defined with the extension point
LogServiceCollector listens to log service events and records them. It has to be defined with something like that:
<extension point="org.eclipse.riena.monitor.collectors"> <collector category="LogCollector" maxItems="50" class="org.eclipse.riena.monitor.client.LogServiceCollector: collectRange=1..3; triggerRange=1, 2"> </collector> </extension>
category gives the collector a unique name. This is because the same class implementing a collector can be used for different purposes. The attribute
maxItems defines the maximum number of logged items that shall be kept within the local store. The attribute
class defines the collector class and contains additional configuration settings. These settings are collector specific.
In the example above there are two required parameters
triggerRange. Both parameters are of type range. A range defines a set of integers (see
- 1..3 - is a interval containing 1, 2 and 3
- 1,2 - are simply the values 1 and 2
- 1..3, 5,7 - is a interval containing 1, 2, 3, 5 and 7
These integers are the log levels defined by
org.osgi.service.log.LogService. So, for the above defined
LogServiceCollector this means collect (collectRange) all logs that are INFO (3), WARNING (2) or ERROR (1) and trigger transmission (triggerRange) on WARNING (2) or ERROR (1).
With the configuration capabilities of the
LogServiceCollector it also possible to define another collector that listens to custom log levels, i.e. application specific log levels, e.g.
<extension point="org.eclipse.riena.monitor.collectors"> <collector category="CustomCollector" maxItems="250"> class="org.eclipse.riena.monitor.client.LogServiceCollector: collectRange=-2..0; triggerRange=-2" </collector> </extension>
org.eclipse.riena.internal.monitor.client.Aggregator is implemented as a OSGi service and responsible for
- the configuration of the client monitoring, e.g. evaluating the extensions (collector, store and sender)
- life cycle
- aggregating all the information from the collectors
- and delegating tasks to the store and the sender
The aggregator is not meant to be replaced by custom implementations.
There is already a simple store implementation
org.eclipse.riena.internal.monitor.client.SimpleStore that stores the collected items within compressed and encrypted files.
This simple store gets configured with:
extension point="org.eclipse.riena.monitor.store"> <store name="SimpleStore" class="org.eclipse.riena.monitor.client.SimpleStore:cleanupDelay=1 h"> </store> </extension>
This simple store performs cleanups (i.e. removable of transmitted items) within given periods defined by the
cleanupDelay property. This period is defined with a simple syntax that does not allow fractions but allows to use time units, e.g. 1 h 30 m 20 s 3 ms.
It is of course possible to define another store implementation with this extension point. The store just has to implement
Same as with the store there is also a simple sender implementation
org.eclipse.riena.monitor.client.SimpleSender. This implementation expects that an OSGi service for the interface
org.eclipse.riena.monitor.common.IReceiver exists. This service is than used for transferring the items to the receiver. Within Riena the receiver is usually a server component and the service is a remote service that has been made accessible with Riena communications (see Riena communications how to do that).
The sender has to be configured like this:
extension point="org.eclipse.riena.monitor.sender"> <sender name="SimpleSender" class="org.eclipse.riena.monitor.client.SimpleSender:retryTime=20 m"> </sender> </extension>
The simple sender can be configured with a
retryTime property. This time specifies the duration between retries when sending has failed. The syntax for the
retryTime is the same as for the
cleanupDelay of the store.
The receiver is usually a server component that is exposed to the client as a Riena remote service. There is (yet) no ready to use simple receiver because it is too dependent on the customers use case. I.e. what should happen with the transmitted items? Should they be stored in a database or in the file system? Should administrators be notified when certain patterns occur? And, and ... To register the receiver on the client you need something like that:
new RemoteServiceFactory().createAndRegisterProxy(IReceiver.class, "http://localhost:8080/hessian/CollectibleReceiverWS", PROTOCOL_HESSIAN, context);
While on the server there needs to be something like this to publish the service:
Hashtable<String, String> properties = new Hashtable<String, String>(3); properties.put(RSDPublisherProperties.PROP_IS_REMOTE, Boolean.TRUE.toString()); properties.put(RSDPublisherProperties.PROP_REMOTE_PROTOCOL, REMOTE_PROTOCOL_HESSIAN); properties.put(RSDPublisherProperties.PROP_REMOTE_PATH, "/CollectibleReceiverWS"); IReceiver monitoringReceiver = new SimpleMonitoringReceiver(); context.registerService(IReceiver.class.getName(), monitoringReceiver, properties);
Client information provider
Sometimes it might be useful to know a little bit more about the creator of the collected information, e.g. it´s host name or ip address. To provide the client monitoring with this information it is necessary define a org.eclipse.riena.monitor.client.IClientInfoProvider which exactly does that. The information gathered from that provider enriches the collected data and will of course also be transferred to the server.
There is already a configurable org.eclipse.riena.monitor.clientSimpleClientInfoProvider which is capable of gathering Java system properties plus a few more special properties. You need to define something like this:
<extension point="org.eclipse.riena.monitor.clientinfoprovider"> <clientInfoProvider name="SimpleClientInfoProvider" class="org.eclipse.riena.monitor.client.SimpleClientInfoProvider:user.name,x-host.name"> </clientInfoProvider> </extension>
In this example there are two properties: "user.name" and "x-host.name". This configuration will gather the Java system property "user.name" and the synthetic property "x-host.name" which resolves to InetAddress.getLocalHost().getHostName(). This results into a client information like this user.name=sliebig,x-host.name=pc4723489 Currently there are the following synthetic properties:
- x-host.address - retrieves the host's ip address as given by InetAddress.getLocalHost().getHostAddress()
- x-host.name - retrieves the host's name as given by InetAddress.getLocalHost().getHostName()
- x-host.canonicalname - retrieves the host's canonical name as given by InetAddress.getLocalHost().getCanonicalHostName()
And of course it possible to write your own IClientInfoProvider.
Integrating client monitoring is simple:
- add the common bundle to both the client and the server
- configure the collectors, the store, the sender and maybe an client information provider on the client
- create a receiver on the server and register it as a remote service on the client