JMX Plugin Tutorial

Tutorial: JMX Measurement Plugin

This tutorial will lead you through writing, testing, and deploying a simple JMX measurement plugin that auto-discovers and collects several metrics from Sun JVM. We hope that you will be able to extrapolate from this simple example to your own needs for discovering and monitoring a remote JMX-enabled application.

JMX plugins target remote JMX-enabled applications. They extract metrics from the Java services via MBeans. One of the main tasks of writing a JMX plugin is determining which metrics to monitor via those MBeans. JMX plugins are templatized and so you will not need to write any Java code. All you need to do is write an XML descriptor.

Learn more about JMX plugins and measurement plugins.

See the Plugins Tutorial overview for general plugin information.

Procedural Overview for Writing a JMX Measurement Plugin

  1. Configure the JMX-enabled application for remote connections.
  2. Determine which metrics to collect in the plugin.
  3. Review the sample JMX measurement Plugin descriptor and copy it for your own use.
  4. See what this plugin will show in the HQ UI.
  5. Understand each component of the descriptor and tailor the XML descriptor to reflect your own plugin.
  6. Test the plugin.
  7. Deploy the plugin.

Feedback is welcome. Click Add Comment at the bottom of the page.

How the Plugin Fits Into HQ's Inventory Model

When writing a resource plugin, it is important to take into account the HQ inventory model and its relationship to the structure of a plugin.  A plugin should implement a hierarchy that reflects the hierarchy of the inventory model; it should not be flat. The tutorials and example plugins in the Plugin Development Center illustrate how the servers and services (and, less frequently, platforms) being targeted by the plugin are organized according to the inventory model.

For example, to discover a service, first discover its hosting server, and then discover the services running on the server. For a more specific example: SNMP has multiple network interfaces. Each of those network interfaces should be mapped to/treated as a separate service in the plugin, not all combined into one big platform.

One of the benefits of modeling a plugin after the Inventory Model is that you can then implement actions (gathering metrics, controlling, etc.) at each inventory level and there will no confusion or difficulty about which level of resource the plugin should be acting on.

This plugin fits into the HQ inventory model by starting at the (Sun JVM) server level and organizing services (in this case, only one: Garbage Collector) under it. Other plugins targeting only a service could bypass the server and be organized directly under the platform on which it is run.

back to top

Step 1. Configure the JMX-Enabled Application for Remote Connection

In order to manage a JMX-enabled application from HQ, it must be configured to accept remote connections. Many such applications have the remote connector enabled by default; those which do not often require changing a line or two of their configuration.

Learn more about configuring for remote connection.

back to top

Step 2. Determine Which Metrics to Collect in the Plugin

You can find appropriate metrics to collect from MBeans in several ways:

To find metrics using JConsole:

  1. Run JConsole.
    JConsole will discover all Java processes on a host that has JMX enabled and will enumerate all the available MBeans.
  2. Find the MBean attribute of interest and its value.
    A numeric value indicates that the attribute is capable of being returned as a metric. This includes two statistic types:
    • javax.management.j2ee.statistics.CountStatistic (gets the count)
    • javax.management.j2ee.statistics.RangeStatistic (gets the current value)
      A non-numeric value indicates that the attribute is not appropriate for collection by the plugin.
  3. Record the MBean name, for use in the XML descriptor.

back to top

Step 3. Review the Sample JMX Measurement Plugin Descriptor

The sample JMX plugin XML descriptor below collects several metrics and auto-discovers a Sun JVM server and a single component service. The sample provides the structure of the plugin, and you should start with it when writing your own plugin. You will need to change certain values — which we'll point out — within the descriptor. That's it. All you need for a JMX measurement plugin is an XML descriptor.

JMX Measurement Plugin
<?xml version="1.0"?>

<!DOCTYPE plugin [<!ENTITY process-metrics SYSTEM "/pdk/plugins/process-metrics.xml">]>

<plugin package="org.hyperic.hq.plugin.java">

<classpath>
<include name="pdk/lib/mx4j"/>
</classpath>

<filter name="template" value="${OBJECT_NAME}:${alias}"/>

<metrics name="Class Loading Metrics">
<metric name="Loaded Class Count" indicator="false" category="THROUGHPUT"/>
<metric name="Total Loaded Class Count" indicator="false" category="THROUGHPUT"/>
<metric name="Unloaded Class Count" indicator="false" category="THROUGHPUT"/>
</metrics>

<metrics name="Compilation">
<metric name="Total Compilation Time" indicator="false" category="THROUGHPUT" collectionType="trendsup" units="ms"/>
</metrics>

<metrics name="Garbage Collector">
<metric name="Collection Count" indicator="false" category="THROUGHPUT" collectionType="trendsup"/>
<metric name="Collection Time" indicator="false" category="THROUGHPUT" collectionType="trendsup"/>
</metrics>

<metrics name="Memory">
<metric name="Object Pending Finalization Count" category="THROUGHPUT" indicator="false"/>
</metrics>

<metrics name="Threading">
<metric name="Thread Count" category="UTILIZATION" indicator="false"/>
<metric name="Daemon Thread Count" category="UTILIZATION" indicator="false"/>
</metrics>

<server name="Java" version="1.5.x">
<property name="HAS_BUILTIN_SERVICES" value="true"/>
<property name="VERSION_FILE" value="jre/lib/fontconfig.Sun.2003.bfc"/>
<property name="DEFAULT_PROGRAM" value="bin/java"/>
<property name="domain" value="Java"/>

<config>
<option name="jmx.url" description="JMX URL to MBeanServer"  default="service:jmx:rmi:///jndi/rmi://localhost:6969/jmxrmi"/>
<option name="jmx.username" description="JMX username" optional="true" default=""/>
<option name="jmx.password" description="JMX password" optional="true" default="" type="secret"/>
<option name="process.query" description="PTQL for Java Process" default="State.Name.eq=java,Args.*.ct=proc.java.home"/>
</config>

<metric name="Availability" template="sigar:Type=ProcState,Arg=%process.query%:State" indicator="true"/>
&process-metrics;

<property name="OBJECT_NAME" value="java.lang:type=ClassLoading"/>

<metrics include="Class Loading Metrics"/>
<property name="OBJECT_NAME" value="java.lang:type=Compilation"/>

<metrics include="Compilation"/>
<property name="OBJECT_NAME" value="java.lang:type=Memory"/>

<plugin type="log_track" class="org.hyperic.hq.product.jmx.MxNotificationPlugin"/>

<property name="OBJECT_NAME" value="java.lang:type=Threading"/>
<metrics include="Threading"/>

<!-- derive installpath from JAVA_HOME env prop... -->
<property name="PROC_HOME_ENV" value="JAVA_HOME"/>

<!-- derive installpath from -Dproc.java.home=... -->
<property name="PROC_HOME_PROPERTY" value="proc.java.home"/>
<plugin type="autoinventory" class="org.hyperic.hq.product.jmx.MxServerDetector"/>
<plugin type="measurement" class="org.hyperic.hq.product.jmx.MxMeasurementPlugin"/>

<service name="Java GC">
<plugin type="autoinventory"/>
<property name="OBJECT_NAME" value="java.lang:type=GarbageCollector,name=*"/>
<metrics include="Garbage Collector"/>
</service>
</server>

<server name="Java" version="1.6.x" include="1.5.x">
<property name="VERSION_FILE" value="jre/lib/management-agent.jar"/>
</server>

<!--
 ==================== Plugin Help ===========================
-->
<help name="Java">
<![CDATA[
  <p>
  <h3>Configure HQ for monitoring Java</h3>
  </p>
  <p>
  1) Add this line to the java options when executing the binary.
  <br>
  "-Dcom.sun.management.jmxremote \
  <br>
  -Dcom.sun.management.jmxremote.port=6969 \
  <br>
  -Dcom.sun.management.jmxremote.ssl=false \
  <br>
  -Dcom.sun.management.jmxremote.authenticate=false"
  <br>
  </p>
]]>
</help>
<help name="Java 1.5.x" include="Java"/>
<help name="Java 1.6.x" include="Java"/>
</plugin>

Step 4. What This Plugin Will Show in the HQ UI

After this plugin is successfully run by an Agent, the HQ UI will show:

  • The existence of the JMX-enabled application (Sun JVM server) and its one hosted service: Java GC (Garbage Collector)
  • For that server, these metrics:
    • Availability of the server
    • Loaded Class Count
    • Total Loaded Class Count
    • Unloaded Class Count
    • Total Compilation Time
    • Object Pending Finalization Count
    • Thread Count
    • Daemon Thread Count
  • For that server, log-tracking data for the Threading MBean (displayed on the "Current Health" screen)
  • For the service, these metrics:
    • Collection Count
    • Collection Time
  • Configuration instructions for the JMX-enabled server, on the server's "Resource Configuration" screen

Learn more about viewing resources and metrics in HQ.

back to top

Step 5. Understand and Modify Each Piece of the Sample Plugin XML Descriptor

The sample XML descriptor above is divided into parts, each of which is repeated and explained for your particular use below. Some of the more important parts of the XML descriptor are called out.

Learn more about the plugin XML descriptor.

Order Matters
If a part of the XML descriptor references or includes another part of the XML Descriptor, the referenced part must come before the part doing the referencing. This can be seen in this tutorial with the inclusion of metrics parameters, for example.

  1. This code, in conjunction with one line later, retrieves the standard process metrics for the process obtained by a later process query.
    <!DOCTYPE plugin [<!ENTITY process-metrics SYSTEM "/pdk/plugins/process-metrics.xml">]>
    

    It is a very simple way to retrieve such useful metrics as StartTime, Memory Utilization, and CPU System Time. Keep it as-is.
    This code works when a single process is retrieved by the query; if the query retrieves multiple processes, then simply add multi- just in front of the two occurrences of process-metrics here, and there will be an equivalent change in the later line:

    <!DOCTYPE plugin [<!ENTITY multi-process-metrics SYSTEM "/pdk/plugins/multi-process-metrics.xml">]>
    # This code provides the path for the Java package.
    {code:xml}
    <plugin package="org.hyperic.hq.plugin.java">
    

    Replace it with the path in your environment.

  2. This code enables JMX classes for which HQ has already set up libraries.
    <classpath>
    <include name="pdk/lib/mx4j"/>
    </classpath>
    

    Keep it as-is.

    Define Metrics

  3. This code assigns a template value to each of the metrics defined just after it.
    <filter name="template" value="${OBJECT_NAME}:${alias}"/>
    
    How Do Filters and Templates Work?

    Topics marked with * relate to HQ Enterprise-only features. This page contains information that has not been reviewed. Click Add Comment at the bottom of the page to enter suggestions or corrections.

    Element Overview

    The <filter> element declares a variable that can be referenced by descendent elements in the descriptor to obtain resource-type specific values for other expressions. The most common use for the <filter> element is to define a string that forms all or a portion of the template attribute for <metric> elements, instead of explicitly defining the template for each metric.

    A <filter> element is available to all descendants of its parent. For example, a <filter> definition in the plugin root applies to all <platform>, <server> and <service> elements that follow. You override the filter value a child inherits from a parent by defining a filter of the same name in the child element.

    Parent Elements

    • <plugin> (root) - A <filter> element here is available to all resource elements in the descriptor
    • <platform> - A <filter> element here is available within the element and its descendants.
    • <server> - A <filter> element here is available within the element and its descendants.
    • <service> - A <filter> element here is available only within the element.

    Child Elements and Attributes

    • name - (Required) Name by which the variable is referenced. The name can be an arbitrary value, or exactly match the name of an attribute the filter defines. Typically the name attribute defines a filter named "template" which defines the template attribute forelements using other variables whose values are assigned at the resource and metric level.
    • value - (Required) Value of the variable, expressed explicitly or using other variables.

    Examples

    <filter> defines metric template components using configuration and metric alias

    This excerpt from the HQ Zimbra plugin, is part of a <server> element that defines:

    • a <filter named "template" that specifies a building block in terms of the installpath configuration option and the metric element's alias attribute.
    • an <option> element that defines the installpath configuration option.
    <server name="Zimbra"
         version="4.5.x">
            
            <plugin type="autoinventory"
             class="ZimbraServerDetector"/>
            <plugin type="measurement"
             class="org.hyperic.hq.product.MeasurementPlugin"/>
            <plugin type="collector"
             class="org.hyperic.hq.plugin.zimbra.ZimbraCollector"/>
            
            <filter name="template"
             value="zimbra-stats:installpath=%installpath%:${alias}"/>
            
            <properties>
                <property name="version"
                 description="Zimbra Version"/>
            </properties>
            
            <config>
                <option name="installpath"
                 default="/opt/zimbra"
                 description="Zimbra Install Path"/>
                <option name="zimbra-ptql"
                 default="Pid.PidFile.eq=%installpath%/log/zmtomcatmgr.pid"
                 description="Sigar PTQL Process Query"/>
            </config>
    

    <filter> defines metric template using a values supplied by a <property> and a <metric> alias attribute

    This element from the HQ Resin plugin defines a filter named template that references the values of a resource named OBJECT_NAME and a element's alias attribute. This reference provides two components of the metric template:

    <filter name="template"
    value="${OBJECT_NAME}:${alias}"
    />
    

    Because the filter is defined in the root <plugin> element, it is available to all resource elements in the descriptor.

    The value of the OBJECT_NAME property is defined in each resource element in the descriptor, a <server> and two{{ <service>}} elements. For example:

    <service name="Port">
    <property name="OBJECT_NAME"
    value="resin:type=Port,name=*"/>
    

    The template filter is expanded for each server and service metric, using the value of the owning resource's OBJECT_NAME property and the metric's alias attribute.

    <filter> references globally available configuration schema

    This excerpt shows the use of a globally available configuration schema in a filter:

    <filter name="iplanet.snmp"
    value="iplanet:$\{snmp.config\}"/>
    

    The "snmp" schema is defined in the HQ Netservices plugin descriptor, as shown in this excerpt:

    description="SNMP agent IP address"
    default="127.0.0.1"/>
    description="SNMP agent port"
    type="port"
    default="161"/>
    description="SNMP Version"
    type="enum">
    

    In the filter definition,

    ${snmp.config} is replaced by:

    snmpIP=*,snmpPort=,*snmpVersion=*

    resulting in:

    iplanet:snmpIP=,snmpPort=,snmpVersion=*

    In the same plugin descriptor, the filter is referenced in a template definition:

    template="${iplanet.snmp}:httpStatisticsRequests:${server.config.v4}"

    <filter> uses value of config <option> to provide "domain" portion of metric template

    The HQ mssql-plugin descriptor defines several filters in the root, based on configuration options:

    <plugin name="mssql">
      	......
    	......
      <filter name="db.domain"
              value="Databases(${db.name})"/>
      <filter name="lock.domain"
              value="Locks(${lock.name})"/>
      <filter name="cache.domain"
              value="Cache Manager(${cache.name})"/>
      .....
      .....
    

    Also in the root, <metric> elements, define the template in terms of the filter:

    <metrics name="mssql-avail">
        <metric name="Availability"
                alias="Availability"
                template="${db.domain}:Type=Availability:Active Transactions"
                category="AVAILABILITY"
                group="Reliability"
                indicator="true"
                collectionType="dynamic"
                units="percentage"/>
      </metrics>
    

    Later in the descriptor, each resource element, like this <service> element, defines the <option>:

    <service name="Database">
            ......
            ......
          <config>
            <option name="db.name"
                    description="Database name"
                    default="Northwind"/>
          </config>
        </service>
    

    In this case, the filter applies the template to all the following metrics. Learn more about using filters to apply a template to metrics.

    A "template" is a unique string containing all the information required to collect a particular data point. Basically, it tells the plugin how to collect the metric data. Oftentimes this involves invoking another, HQ-provided plugin that knows exactly how to fetch data or how to execute code. Templates are often indirectly assigned to a metric by way of a filter.

    Learn more about templates.

    In this case, the Loaded Class Count, Total Loaded Class Count, Unloaded Class Count, Total Compilation Time, Collection Count, Collection Time, Object Pending Finalization Count, Thread Count, and Daemon Thread Count metrics all have a template, with the value specified, applied to it, without having to repeat the template parameter for each metric. Keep it as-is.

  1. This code collects in one place, for readability, all the metrics that will be gathered, later, from MBeans.
    <metrics name="Class Loading Metrics">
    <metric name="Loaded Class Count" indicator="false" category="THROUGHPUT"/>
    <metric name="Total Loaded Class Count" indicator="false" category="THROUGHPUT"/>
    <metric name="Unloaded Class Count" indicator="false" category="THROUGHPUT"/>
    </metrics>
    
    <metrics name="Compilation">
    <metric name="Total Compilation Time" indicator="false" category="THROUGHPUT" collectionType="trendsup" units="ms"/>
    </metrics>
    
    <metrics name="Garbage Collector">
    <metric name="Collection Count" indicator="false" category="THROUGHPUT" collectionType="trendsup"/>
    <metric name="Collection Time" indicator="false" category="THROUGHPUT" collectionType="trendsup"/>
    </metrics>
    
    <metrics name="Memory">
    <metric name="Object Pending Finalization Count" category="THROUGHPUT" indicator="false"/>
    </metrics>
    
    <metrics name="Threading">
    <metric name="Thread Count" category="UTILIZATION" indicator="false"/>
    <metric name="Daemon Thread Count" category="UTILIZATION" indicator="false"/>
    </metrics>
    

    The Garbage Collector metrics are handled separately from the other metrics. Replace these metrics with the metrics you want to collect. However you name the group of metrics here (Memory, Compilation, etc.), that's the name you will explicitly "include" later.
    For each metric you collect, you can must specify at least the following attributes:

    Metric Attribute Description Req'd Possible Values
    name Name of the metric to be displayed in the GUI Y  
    indicator Whether or not this metric should be treated as an indicator metric in HQ Y true, false
    template

    A "template" is a unique string containing all the information required to collect a particular data point. Basically, it tells the plugin how to collect the metric data. Oftentimes this involves invoking another, HQ-provided plugin that knows exactly how to fetch data or how to execute code. Templates are often indirectly assigned to a metric by way of a filter.

    Learn more.
    Y See examples

    See all the possible attributes.

  1. This code specifies the name and version of the process against which the plugin will be run.
    <server name="Java" version="1.5.x">
    

    These values will be displayed in the UI for the server, so while you can name it anything you want, we recommend naming it something meaningful.

    Tell the Plugin About Services the Server Hosts

  1. This code tells HQ that the server has component services, which tells the later-invoked auto-discovery function to please auto-discover the services, too.
    <property name="HAS_BUILTIN_SERVICES" value="true"/>
    

    Keep it as-is if your server contains services you want to discover and manage. Otherwise, replace true with false.

  2. This code enables the plugin to identify different versions of Java.
    <property name="VERSION_FILE" value="jre/lib/fontconfig.Sun.2003.bfc"/>
    

    The file jre/lib/fontconfig.Sun.2003.bfc exists only in version 1.5, not in 1.6, and therefore enables the plugin to identify a version as 1.5, which is necessary to determine what parts of the overall plugin to run against the server. If necessary, replace this with a file that uniquely identifies the version of your server.

  3. This code specifies the actual program name being run from the default path.
    <property name="DEFAULT_PROGRAM" value="bin/java"/>
    

    If Java is being run from /usr/jdk/latest/bin/java, then /bin/java is the value you should put here.

  4. This code uniquely identifies the plugin's domain.
    <property name="domain" value="Java"/>
    

    It it typically the name of the server, specified earlier, but can be anything. If desired, replaced "Java" with your unique identifier.

Enable the Plugin to Connect to the MBean Server

  1. This code provides the configuration properties HQ needs to connect to the MBean server.
    <config>
    <option name="jmx.url" description="JMX URL to MBeanServer" default="service:jmx:rmi:///jndi/rmi://localhost:6969/jmxrmi"/>
    <option name="jmx.username" description="JMX username" optional="true" default=""/>
    <option name="jmx.password" description="JMX password" optional="true" default="" type="secret"/>
    

    All the configuration options specified here are the ones that show up in the server's "Resource Configuration" screen. The default values for each of these options can be specified here, but users can change the default values on that screen. You can leave most of the default values in this code as-is but should change the default username and password.
    For a JMX plugin, this list of configuration options suffices, but you can add other options. Learn more about how to write an option. Learn more about login configuration properties or configuration properties in general.

Identify the Exact Processes You Want to Collect Metrics From

  1. This last of configuration options specifically identifies the exact process(es) of interest.
    <option name="process.query" description="PTQL for Java Process" default="State.Name.eq=java,Args.*.ct=proc.java.home"/>
    </config>
    

    ct.=proc.java.home narrows the query to only the salient processes (those with "proc.java.home" in the names). The query is written in PTQL, which isn't necessary to understand for this tutorial, but would be useful to understand for future, custom plugins.
    If you are interested in different processes, replace proc.java.home with another partial name that will narrow the search. The process.query value is used later on when gathering metrics.

    Gather Metrics

  2. This code collects the requisite Availability metric.
    <metric name="Availability" template="sigar:Type=ProcState,Arg=%process.query%:State" indicator="true"/>
    

    The variable %process.query% gets assigned the value from the above process query (which determined whether or not the Java server exists), and so then the plugin can determine whether or not the server is available. Keep it as-is.

    Use of Variables in XML Descriptors
    In plugin XML descriptors, variables are indicated by "%" on either side of the variable name (for example, %process.query%). The variables are assigned the value that was most recently determined. The value of the variable must be determined before the variable is used.
    You Must Always Collect the Availability Metric
    The Availability metric indicates whether a Resource is up or down.

    A metrics-gathering plugin must determine Availability for every server and every service it monitors. A single plugin will likely gather Availability for multiple Resources. If Availability is not gathered for a Resource, HQ will consider the Resource to be unavailable, and will not show any metrics for it in the Portal.

    A plugin sets the value of Availability to 1 if the Resource is up, and 0 if it is down.  These values are displayed in the Portal as "available" or "not available".

    Verifying the existence of a Resource's process is a common technique for determining its Availability. However, the method a plugin uses to determine Availability can vary depending on the Resource Type and the plugin developer's judgment. There might be alternative techniques for determining the Availability of a Resource. For instance, a plugin might determine the Availability of a web server based on whether its process is up, its port is listening, it is responsive to a request, or by some combination of these conditions. 

    Some mBeans do not have an "Availability" attribute. Even if this is the case, you must still specify an "Availability" metric as this sample plugin does.

  3. This line completes the earlier code that retrieves the standard process metrics for the process just obtained by the above process.query.
    &process-metrics;
    

    Keep it as-is.
    This code works when a single process is retrieved by the query; if the query retrieves multiple processes, then simply add multi- just in front of process-metrics here, as there was an equivalent change in the earlier code.

  1. This code gathers the metric values.
    <property name="OBJECT_NAME" value="java.lang:type=ClassLoading"/>
    <metrics include="Class Loading Metrics"/>
    <property name="OBJECT_NAME" value="java.lang:type=Compilation"/>
    <metrics include="Compilation"/>
    <property name="OBJECT_NAME" value="java.lang:type=Memory"/>
    <metrics include="Memory"/>
    ...
    <property name="OBJECT_NAME" value="java.lang:type=Threading"/>
    <metrics include="Threading"/>
    

    It references the previously defined metrics, which are grouped earlier for easier reference. If you want to gather other metrics, you should:

    • Replace the java.lang:type value (for example, ClassLoading) with the associated MBean "objectName" (which you can find, for example, in JConsole).
    • Include a section that you would define earlier. If you include="Foobar Metrics" here, then you would define metrics name="Foobar Metrics" earlier, with all its component metrics.
      Learn more about defining metrics, including the use of OBJECT_NAME, and about defining properties.
  2. This code implements log tracking of the Threading MBeans (the metrics declared just after invoking log tracking).
    <plugin type="log_track" class="org.hyperic.hq.product.jmx.MxNotificationPlugin"/>
    

    Keep it as-is. Learn more about log tracking in JMX plugins.

  1. This code provides two methods — of which you must use one — for defining the install (base) path for the process.
    <!-- derive installpath from JAVA_HOME env prop... -->
    <property name="PROC_HOME_ENV" value="JAVA_HOME"/>
    <!-- derive installpath from -Dproc.java.home=... -->
    <property name="PROC_HOME_PROPERTY" value="proc.java.home"/>
    

    If using the first method, replace JAVA_HOME with the environmental property of the process. If using the second method, replace proc.java.home with the defined name-value pair argument of the process; the MxServer Detector class uses this variable to perform auto-discovery.
    You could instead use a third method:

    <property name="PROC_MAIN_CLASS" value="proc.java.home"/>
    

    As with PROC_HOME_PROPERTY, this variable tells the MxServerDetector class to autodiscover the process with this PTQL: State.Name.eq=java,Args.*.sw=-D<value of proc main class>.
    Any of these methods will set the installpath config variable to be the current working directory of the process in question. And while this is particularly useful for log-tracking and control plugins (which are outside the scope of this tutorial), this value is also used later in this XML descriptor.

    Auto-Discover the Server

  1. This one line of code, in conjunction with the results of the earlier process.query, implements auto-discovery in this plugin.
    <plugin type="autoinventory" class="org.hyperic.hq.product.jmx.MxServerDetector"/>
    

    Keep it as-is. Autoinventory for a server must also include this class. Learn more about auto-discovery in JMX plugins.

  2. This one line of code tells HQ what type of plugin this is — Measurement — and therefore how it should be run.
    <plugin type="measurement" class="org.hyperic.hq.product.jmx.MxMeasurementPlugin"/>
    

    Keep it as-is.

    Identify and Gather Metrics from the Server's Hosted Services

  1. This code defines the Garbage Collector as a service and collects its metrics.
    <service name="Java GC">
    <plugin type="autoinventory"/>
    <property name="OBJECT_NAME" value="java.lang:type=GarbageCollector,name=*"/>
    <metrics include="Garbage Collector"/>
    </service>
    </server>
    

    If you want to collect GarbageCollector metrics, then keep as-is. Autoinventory for a service does not need a class (whereas a server does).
    This code looks slightly different than the earlier metrics-collection code because there are multiple types of Garbage Collection, each of which collects the same metrics. In cases where there are numerous types, calling out each type and its respective metrics (which are identical to the other types'), is onerous and unnecessary. Using

    name=*
    

    makes sure that every type of GarbageCollector gets measured. The <plugin type="autoinventory"/> line tells HQ to resolve the *. If you want to collect metrics of another objectName that similarly has multiple types, replace Java GC with a meaningful name and GarbageCollector with the objectName, and accordingly modify the earlier metrics enumeration.

    Declaring Services as Metrics for Convenient Viewing
    This plugin declares the Garbage Collector as a service of the Java server. It is also possible to treat it simply as a metric of the server. Why would you do that? Then all the metrics of the would be displayed in the UI on one level — the server level — and you wouldn't have to drill down from the server to the service to access the metrics.

  2. This code determines which part of the plugin to use depending on the version of the Java process. Just as we did before, we provide a file — jre/lib/management-agent.jar — that only exists in Java v1.6 so that HQ can distinguish between v1.5 and v1.6. For version 1.6, the plugin includes everything that's been written for v1.5 plus anything additional we write specifically for v1.6 (in this sample, we haven't written anything additional). The install path that we specified above is used here: the file name is resolved within that path (JAVA_HOME/jre/lib/management-agent.jar).
    <server name="Java" version="1.6.x" include="1.5.x">
    <property name="VERSION_FILE" value="jre/lib/management-agent.jar"/>
    </server>
    

    Provide Configuration Instructions

  1. This code includes the configuration instructions that show up at the bottom of the "Resource Configuration" screen.
    <!--
     ==================== Plugin Help ===========================
    -->
    <help name="Java">
    
      <p>
      <h3>Configure HQ for monitoring Java</h3>
      </p>
      <p>
      1) Add this line to the java options when executing the binary.
      <br>
      "-Dcom.sun.management.jmxremote \
      <br>
      -Dcom.sun.management.jmxremote.port=6969 \
      <br>
      -Dcom.sun.management.jmxremote.ssl=false \
      <br>
      -Dcom.sun.management.jmxremote.authenticate=false"
      <br>
      </p>
    
    </help>
    <help name="Java 1.5.x" include="Java"/>
    <help name="Java 1.6.x" include="Java"/>
    </plugin>
    

    This help text — which are instructions for exposing MBeans — should suffice for any plugins gathering JMX metrics. If you are dealing with more than two versions, the <help name="Java 1.5.x" include="Java"/> lines can be augmented to include other versions. Additional lines should have the same content but with the server and version replaced with the format: server version.
    If necessary, replace this help with whatever configuration instructions are necessary for getting the plugin running in your environment (prerequisites, etc.). Learn more about using the help tag.

back to top

Step 6. Test the Plugin.

The PDK allows you to invoke your plugin methods from the command line for quick testing. To perform any of the following tasks (targeted mainly at measurement plugins), run the associated commands from the command line in the HQ Agent directory:

Check the syntax of the plugin: (simply initializes the plugin)

java -jar <Agent Directory>/pdk/lib/hq-product.jar -Dplugins.include=yourPluginName -m lifecycle -Dlog=debug

Make sure the plugin can indeed collect the metrics: (runs the plugin and outputs the metric values)

java -jar <Agent Directory>/pdk/lib/hq-product.jar -Dplugins.include=yourPluginName -m metric

Make sure the plugin can perform auto-discovery: (enables auto-discovery in addition to metric collection)

java -jar <Agent Directory>/pdk/lib/hq-product.jar -Dplugins.include=yourPluginName -m discover -a metric

Enable debug for troubleshooting:

java -jar <Agent Directory>/pdk/lib/hq-product.jar -Dplugins.include=yourPluginName -m discover -a metric -Dlog=debug

Passing in Config Options
When testing your plugin, you need to also pass in values (using the -D argument) for all the config options that are required to make the plugin run, for example, config options that specify credentials. For example, -Djmx.password=<password>. Otherwise you will not be able to run your plugin.
It's a Good Habit to Specify an exec.sleep Value
When running the script plugin from the command line, it is best to assign an explicit value to exec.sleep just in case the script takes longer to run than the default exec.sleep value (30 sec).

java -jar <Agent Directory>/pdk/lib/hq-product.jar -Dexec.sleep=number_of_seconds ...

This doesn't apply to plugins deployed in HQ because there the timeout variable kicks in.

Learn more about invoking plugins outside of the Server and Agent, including more testing commands.

For this JMX plugin, you need to include in these commands your JMX credentials: URL, username, and password, like this:

... -Dplugins.include=yourPluginName -Djmx.url=<URL> -Djmx.username=<username> -Djmx.password=<password> ...

back to top

Step 7. Deploy the Plugin.

You must deploy your custom plugin on the HQ Server and on all the Agents you want to run the plugin.

Deploying the Plugin in .xml or .jar Format

You can name your plugin as you please, but the name must end with either -plugin.xml or -plugin.jar, depending on the plugin format.

Plugin Format Description and Contents
-plugin.jar A standard jar-formatted file, containing etc/hq-plugin.xml — the plugin's XML descriptor — and any java class files, scripts, and MIB files.
-plugin.xml For plugins that consist solely of an XML descriptor. It is combined with HQ's plugin support classes (either in the hq-product.jar or other *-plugin.jar plugins). In the case of a script plugin, the script can also be included in a separate file (as opposed to embedded in the XML descriptor).

Where to Place Custom-Plugin Files

Usually you will place your custom-plugin files in a subdirectory of the Server's and Agent's parent directories. By doing this, your plugin files will persist through upgrades. The subdirectory is called hq-plugins. For example:

Non-Windows Installation

  • If the Server is installed at /usr/local/hyperic/<Server directory>, then add the plugin in /usr/local/hyperic/hq-plugins
  • If the Agent is installed at /usr/local/hyperic/<Agent directory>, then add the plugin in /usr/local/hyperic/hq-plugins

Windows Installation

  • If the Server is installed at C:\Program Files\Hyperic HQ\<Server directory>, then add the plugin in C:\Program Files\Hyperic HQ\hq-plugins
  • If the Agent is installed at C:\Program Files\Hyperic HQ\<Agent directory>, then add the plugin in C:\Program Files\Hyperic HQ\hq-plugins
hq-plugins/ must exist prior to starting the Server
Hot-deployment on the Server side using the custom hq-plugins/ directory requires that the directory exist prior to starting the Server. So, after creating /usr/local/hyperic/hq-plugins/, you must restart the Server.

Alternate File Placement
You can also place the files under the Server and Agent directories:

  • On the Server: <Server directory>/hq-engine/server/default/deploy/hq.ear/hq-plugins/
  • On the Agent: <Agent directory>/bundles/agent-x.y.z/pdk/plugins/

You should do this when, for example, you are installing a patch to a plugin, or if you want to keep all your Agent-deployment files together.

Hot Deployment of Plugins

The Server supports hot-deployment: plugins can be updated or added without restarting the Server.

The Agent does not support hot-deployment: it must be restarted after a plugin is updated or added.

back to top

Done!

Your plugin should now kick into action the next time the Agent runs (assuming it's been rebooted since the plugin was added to it), and you should see all the desired metrics in the HQ UI.

back to top


Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Apr 22, 2008

    Anonymous says:

    why do you make this so freaking hard? its been 4 hours and I still cant go from...

    why do you make this so freaking hard? its been 4 hours and I still cant go from dumping all the mbeans out of a jvm I have, where i see the values, to telling hyperic about them. start your example with something simpler than 25 steps.

    url to connect to a jvm
    long full name of an mbean.
    tell hyperic what it is (throughput, trendsup)
    save the xml file, go to the gui, see it.

  2. Nov 13, 2008

    Anonymous says:

    Same here. I got a JVM running that waits to be monitored (works with jconsole)....

    Same here. I got a JVM running that waits to be monitored (works with jconsole). Now I just want to get started, so I save the plugin as test01-plugin.xml and execute the command java -jar pdk/lib/hq-product.jar -Dplugins.include=test01 -m lifecycle -Dlog=debug as documented. All I get is this:

    [DEBUG] ProductPluginManager - Initializing in client mode (pdk=C:\Programme\hyperic-hq-agent-3.2.4\pdk)
    [DEBUG] MIBTree - No MIBs in directory: C:\Programme\hyperic-hq-agent-3.2.4\pdk\mibs
    [INFO] ProductPluginManager - Loading plugin: system-plugin.jar
    [DEBUG] SystemPlugin - sigar.mirror.procnet=null
    [INFO] ProductPluginManager - Loading plugin: netservices-plugin.jar
    [INFO] MeasurementPlugin - Register TCP Socket proxy for domain: socket
    [INFO] MeasurementPlugin - Register HTTP proxy for domain: http
    [INFO] MeasurementPlugin - Register HTTP proxy for domain: url.availability
    [INFO] MeasurementPlugin - Register FTP proxy for domain: ftp
    [INFO] ProductPluginManager - Loading plugin: sqlquery-plugin.jar
    [DEBUG] ProductPluginManager - adding to sqlquery classpath:
    [DEBUG] ProductPluginManager -    d C:\Programme\hyperic-hq-agent-3.2.4\pdk\lib\jdbc
    [INFO] SQLQueryMeasurementPlugin - Registered proxy for domain: sql
    Exception in thread "main" org.hyperic.hq.product.PluginNotFoundException: product plugin name=test01 not found
            at org.hyperic.hq.product.PluginManager.getPlugin(PluginManager.java:286)
            at org.hyperic.hq.product.util.PluginDumper.init(PluginDumper.java:369)
            at org.hyperic.hq.product.util.PluginMain.main(PluginMain.java:272)

    If you'd provide a simple sample with exact commands to be executed that work straight forward and explain what happened afterwards, people would be much more motivated to stick to the topic.

    Cheers, Bjoern

  3. May 09, 2009

    Bjoern Martin says:

    I finally took the time to work through this tutorial. Here are some hints that ...

    I finally took the time to work through this tutorial. Here are some hints that would've saved me some time.

    Step 3

    • The measurement plugin has a typo: !<ENTITY should be <!ENTITY instead
    • The measurement plugin is malformed, as the <help> tag content lacks the <![CDATA[ ... ]]> encapsulation (see e.g. Tomcat plugin)

    Step 6

    • The hint for the reader about how the plugin file is to be named comes after the first time that information is needed. Maybe the info boxes should be moved above the code boxes.
    • Hint the reader to the fact that the plugin has to reside within the <Agent Directory>/pdk/plugins directory.

    Cheers, Bjoern

  4. Jun 10, 2009

    BJ Chippindale says:

    Noting here that the Availability is obtained through PTQL in SIGAR. The query ...

    Noting here that the Availability is obtained through PTQL in SIGAR. The query will require different arguments for a Windows based server than it does for a server on Linux or Solaris... in particular it is necessary to check the process args before relying on the availability to work. If your custom plugin using java has a problem here try the following:

    1. java -jar sigar.jar
    (you get the <sigar> prompt)

    2. <sigar> ps State.Name.eq=java
    (you get a typical ps output for all the java processes... pick yours and note the PID )

    3. <sigar>pargs PID
    (you get the process arguments for the process - these can be DIFFERENT from the args you saw in the ps result above and are different from the args useful in linux (or linux from windows). Note the actual argument you want)

    4. now <sigar> ps State.Name.eq=java,Args.*.eq=<the name you just found> will work and so will your availability.

  5. Feb 05, 2010

    Dimitar Georgievski says:

    Agree with above comments. This is not a tutorial but a kind of a reference and ...

    Agree with above comments. This is not a tutorial but a kind of a reference and one that needs lots of improvements. It is hard to read it.

    Take this sentence for example: "Typically the name attribute defines a filter named "template" which defines the template attribute forelements using other variables whose values are assigned at the resource and metric level."

    Notice how the words "attribute" and "template" are used in different contexts in the same sentence.

    More, my impression of the section "Child Elements and Attributes" is that was like cut&pasted from some unrelated material. It makes so many references to things that I have to discover yet.

    Hopefully someone at Hyperic is reading these notes and they would improve this documentation soon.

  6. Feb 05, 2010

    Marty Messer says:

    I concur. This is very hard to follow and I work here I will be discussing this...

    I concur. This is very hard to follow and I work here I will be discussing this with Docs. I think we can do better by making this a lot simpler.

  7. Feb 08, 2010

    Dimitar Georgievski says:

    Marty, I am glad you monitor these pages. Any chance the people who maintain th...

    Marty,

    I am glad you monitor these pages. Any chance the people who maintain these pages could develop a "Hello World" type of example that could be used as a starting point for diving deeper into the plug-in development?

    Since I am concerned mostly with JBoss monitoring, I suggest also adding on a prominent spot the information that JBoss will start supporting jsr 160 starting with JBoss 5, and that is the reason one would need to enable remote JMX in Java 1.5+ to be able to read metrics via JMX from a JBoss server.

    Thanks,

    Dimitar

  8. Feb 09, 2010

    Marty Messer says:

    Dimitar, I'm working with our Docs folks on precisely the kind of "Hello World"...

    Dimitar,

    I'm working with our Docs folks on precisely the kind of "Hello World" doc you're looking for. Stay tuned.

    Marty

  9. Feb 09, 2010

    Marty Messer says:

    One more thing: have you seen http://support.hyperic.com/display/DOC/JMX+Plugin ...

    One more thing: have you seen http://support.hyperic.com/display/DOC/JMX+Plugin ? This doc is actually a lot easier to follow. Stop reading when you get to "Implementing Control Actions". Everything from that point on is advanced and not needed for a basic JMX plugin.

  10. Aug 16

    Sylvain Combe says:

    Issue found with HQ 4.3 for the update of Java plugins. Work Around is to remove...

    Issue found with HQ 4.3 for the update of Java plugins.
    Work Around is to remove sybase plugin from HQ server.
    This issue is fixed with HQ 4.4