Friday, May 09, 2008

Writing a RHQ plugin Part 2

In the last post I showed the general architecture of RHQ and where plugins live. So we can now start writing one.

The scenario revisited

Our plugin should be able to connect to a http server, issue a HEAD request on the base url (e.g.
http://localhost/) and return the http return code as trait and the time it took as numeric data (see below).

To make things easier for the purpose of this series of postings, we will have the agent running on the machine the RHQ server lives on and we will just try to get data from the Servers http connector at port 7080 (the default port).

What do we need ?

In order to write our plugin we basically need three things

  • A plugin descriptor. This contains metadata about the plugin: which metrics should be collected, what operations does it support etc.

  • A discovery component. This part discovers the actual resource(s) and delivers them to the Inventory.

  • A plugin component. This component executes operations and gathers the measurement data etc.

So lets have a look into those three parts.

Plugin descriptor

The plugin descriptor is described by an XML Schema that you can find in svn. The basic structure is as follows:

(Click for pdf version), Graphic done with

The desciptor consists of a few sections. First you can express dependencies to other plugins. This is allows reuse of existing plugins and is useful when you e.g. want to write a plugin that itself needs the JMX plugin, so that it can do its work.

The next are a row of platform/server/service sections. Each of those can have the same (XML-)content as the platform that is shown as an example - they are all of the same (XML-) data type (as a platform/server/service) as each is a kind of resource type, as you already know from the first part.


<service name="CheckHttp">
<metric property="responseTime"
description="How long did it take to connect"
displayName="Time to get the response"

The name of a <service> and the other ResourceTypes (platform, server) must be unique for a plugin. So it is not allowed to have two services named "CheckHttp" within our example plugin, but you could write a Tomcat5 and a separate Tomcat6 plugin that both have a service with the name "connector".

For the start we are especially interested in one of the sub elements: metric for our example plugin, so I will describe this here in a little more detail. For all other tags refer to the XML Schema that has a lot of comments.


This is a simple element with a bunch of attributes and no child tags. You have already seen an example above.
Attributes of it are:

property: name of this metric. Can be obtained in the code via getName()
  • description: A human readable description of the metric

  • displayName: The name that gets displayed

  • dataType: Type of metric (numeric / trait /...)

  • units: The measurement units for numerical dataType

  • displayType: if set to "summary", the metric will show at the indicator charts and collected by default

  • defaultOn: Shall this metric collected by default

  • measurementType: what characteristics do the numerical values have (trends up, trends down, dynamic). The system will for trends* metrics, automatically create additional per minute metrics.

For the sample plugin we will use a metric with numerical dataType for the response time and a dataType of trait for the Status code. Traits are meant to be data values that only rarely change like OS version, IP Address of an ethernet interface or the hostname. RHQ is intelligent enough to only store changed traits to conserve space.

Discovery component

The discovery component will be called by the InventoryManager in the agent to discover resources. This can be done by a process table scan (e.g. for the Postgres plugin) or by any other means (if your plugin wants to look for JMX-based resources, then it can just query the MBeanServer. Well, actually there is a JMX-Plugin that can do that for you in clever ways).

The most important thing here is that the Discovery component must return the same unique key each time for the same resource.

The DiscoveryComponent needs to implement org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent and you need to implement discoverResources().
The usual code block that you will see in discoverResources() is:

Set<DiscoveredResourceDetails> result = new HashSet<DiscoveredResourceDetails>();
for ( ... ) {
DiscoveredResourceDetails detail = new DiscoveredResourceDetails(
configuration, // can be null if no confi
return result;

Basically the context passed in gives you a lot of information, that you can use to discover the resource and create a DiscoveredResourceDetails object per discovered resource. The list of result objects is then returned to the caller. Simple - eh?

Plugin component

The plugin component is the part of the plugin that does the work after the discovery has finished.
For each of the "basic functions" in the plugin descriptor, it needs to implement an appropriate Facet:

Descriptor elementFacet
<metric> MeasurementFacet
<operation> OperationFacet

Each Facet has its own methods to implement. In the case of the MeasurementFacet this is e.g. getValues(MeasurementReport report, Set metrics). The report passed in is where you add your results. The metrics is a list of metrics for which data should be gathered. This can be all ouf your definied <metric>s at once or only a few of them - this depends on the schedules the user configured in the GUI.

Ok, that's it for now. In the next post we will do some coding and get our plugin to work.

Part 1
Part 3
Part 4
Part 5

Technorati Tags:
, ,

No comments: