Runtime performance monitoring made easy

JETM Etm Manager Configuration

This page explains how to configure an EtmManager using Java or XML-based configuration. Both configuration strategies imply that you are using programmatic performance measurement. Alternatively you may use declarative performance measurement.

Common concepts

The class EtmManager may be used to retrieve a previously configured EtmMonitor. As seen in basic concepts this behavior is pretty similar to the static Logger access provided by Log4J or similar tools. However an EtmManager will always return an instance of NullMonitor unless it's configured to provide a different implementation. JETM ships with two different configurator implementations called BasicEtmConfigurator and XmlEtmConfigurator to do so.

Since the created EtmMonitor setup may bind resources such as threads both configurators will create a valid configuration, but will not start the monitor itself. Before using it you need to start it. It is also recommended to stop the monitor before shutting down the application. See following examples for further details.

Be aware that you need to execute the configuration process before calling EtmManager.getEtmMonitor() for the first time. Otherwise performance measurements may create unexpected results.

Java runtime configuration

Within Java you may configure the EtmManager using the class BasicEtmConfigurator. It provides methods to specify the used EtmMonitor, ExecutionTimer and Aggregator chain. The following configuration examples use the class BusinessService.java introduced in one minute tutorial.

Default Setup
  // initialize measurement subsystem
  BasicEtmConfigurator.configure();

  // startup measurement subsystem
  EtmMonitor etmMonitor = EtmManager.getEtmMonitor();
  etmMonitor.start();

  // instantiate business service
  BusinessService service = new BusinessService();

  // execute business logic
  service.someMethod();
  service.someMethod();
  service.someMethod();
  service.nestedMethod();

  // visualize results
  etmMonitor.render(new SimpleTextRenderer());

  // shutdown measurement framework
  etmMonitor.stop();
Using nested monitor instance
  // initialize measurement subsystem
  BasicEtmConfigurator.configure(true);

  // startup measurement subsystem
  EtmMonitor etmMonitor = EtmManager.getEtmMonitor();
  etmMonitor.start();

  // instantiate business service
  BusinessService service = new BusinessService();

  // execute business logic
  service.someMethod();
  service.someMethod();
  service.someMethod();
  service.nestedMethod();

  // visualize results
  etmMonitor.render(new SimpleTextRenderer());

  // shutdown measurement framework
  etmMonitor.stop();
Using specific timer
  // initialize measurement subsystem
  BasicEtmConfigurator.configure(true, new SunHighResTimer());

  // startup measurement subsystem
  EtmMonitor etmMonitor = EtmManager.getEtmMonitor();
  etmMonitor.start();

  // instantiate business service
  BusinessService service = new BusinessService();

  // execute business logic
  service.someMethod();
  service.someMethod();
  service.someMethod();
  service.nestedMethod();

  // visualize results
  etmMonitor.render(new SimpleTextRenderer());

  // shutdown measurement framework
  etmMonitor.stop();
Using specific aggregator
  // initialize measurement subsystem
  Aggregator aggregatorChain = new BufferedTimedAggregator(new RootAggregator());
    BasicEtmConfigurator.configure(true, aggregatorChain);

  // startup measurement subsystem
  EtmMonitor etmMonitor = EtmManager.getEtmMonitor();
  etmMonitor.start();

  // instantiate business service
  BusinessService service = new BusinessService();

  // execute business logic
  service.someMethod();
  service.someMethod();
  service.someMethod();
  service.nestedMethod();

  // visualize results
  etmMonitor.render(new SimpleTextRenderer());

  // shutdown measurement framework
  etmMonitor.stop();

For further configuration options see BasicEtmConfigurator JavaDoc.

Xml configuration

With the help of XmlEtmConfigurator the EtmManager can be configured using an xml file that complies to a JETM configuration DTD. The configuration file allows you to specify the EtmMonitor and ExecutionTimer by full qualified classname or type and the used aggregator chain that processes measurement results.

The usage of XmlEtmConfigurator is similar to BasicEtmConfigurator; instead of java objects this configurator requires an xml configuration that may be provided as String, File, URL or InputStream.

  // initialize measurement subsystem
  XmlEtmConfigurator.configure(new File("jetm-config.xml"));

  // startup measurement subsystem
  EtmMonitor etmMonitor = EtmManager.getEtmMonitor();
  etmMonitor.start();

  // instantiate business service
  BusinessService service = new BusinessService();

  // execute business logic
  service.someMethod();
  service.someMethod();
  service.someMethod();
  service.nestedMethod();

  // visualize results
  etmMonitor.render(new SimpleTextRenderer());

  // shutdown measurement framework
  etmMonitor.stop();

XmlEtmConfigurator uses the given xml configuration to override internal defaults. The defaults are: A NestedMonitor that uses the best available timer implementation and buffers collected details until a threshold of 1000 performance results is reached.

EtmMonitor type configuration

It is possible to select a certain EtmMonitor implementation by specifying a full qualified classname or a type property. Currently supported types are nested (NestedMonitor), flat (FlatMonitor) and null (NullMonitor). See JavaDoc for further details.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jetm-config PUBLIC "-// void.fm //DTD JETM Config 1.2//EN"
                             "http://jetm.void.fm/dtd/jetm_config_1_2.dtd">

<jetm-config type="nested"/>
Custom timer configuration

You can select an ExecutionTimer implementation by specifying a full qualified classname or a type property. Currently supported types are default (DefaultTimer), sun (SunHighResTimer) and jdk50 (Java15NanoTimer). See JavaDoc for further details.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jetm-config PUBLIC "-// void.fm //DTD JETM Config 1.2//EN"
                             "http://jetm.void.fm/dtd/jetm_config_1_2.dtd">
  
<jetm-config timer="etm.core.timer.DefaultTimer"/>
Further JETM configuration options

As stated above the default aggregation chain uses a threshold based buffer. If you want to alter this behavior you may chose between activating a distinct feature from a predefined set or specifying the complete aggregator chain manually.

The nested element features supports access to predefined JETM aggregation features. Currently it is possible to alter the buffering capabilities, enable aggregation persistence and raw data logging. For further details see nested elements interval-buffer, threshold-buffer,persistence and raw-data-log in JETM configuration DTD.

The following example buffers collected details for 5000 miliseconds before aggregation. Furthermore aggregated performance results are persistent and will survive VM restarts, see Aggregation Persistence for details.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jetm-config PUBLIC "-// void.fm //DTD JETM Config 1.2//EN"
                             "http://jetm.void.fm/dtd/jetm_config_1_2.dtd">

<jetm-config>
  <features>
    <interval-buffer interval="5000"/>
      <persistence>
      <file-backend path="${java.io.tmpdir}">
      </persistence>
  </features>
</jetm-config>

Alternatively the aggregator chain can be configured using the aggregator-chain element. This element takes an unlimited number of chain-elements and one (optional) chain-root element. Every EtmPoint will be processed by the list of chain-elements in descending order and finally by the given chain-root aggregator. If there is no chain-root element it will default to RootAggregator automatically.

Both chain-element and chain-root may depend on runtime properties. These runtime properties can be configured using the nested property elements. For each property the aggregator class has to offer a setName method that takes either a boolean, int, long, String or Class argument. XmlEtmConfigurator will automatically convert the given string values to the appropriate type of the setter method.

The following example shows an aggregator chain that buffers raw measurements for one second before asynchronously logging and aggregating them.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jetm-config PUBLIC "-// void.fm //DTD JETM Config 1.2//EN"
                             "http://jetm.void.fm/dtd/jetm_config_1_2.dtd">
<jetm-config>
  <aggregator-chain>

    <chain-element class="etm.core.aggregation.BufferedTimedAggregator>
      <!-- Set aggregation interval to 1 second -->
      <property name="aggregationInterval">1000</property>
    </chain-element>

    <chain-element class="etm.contrib.aggregation.log.CommonsLoggingAggregator">
      <!-- Set commons-logging log category -->
      <property name="logName">etm-result</property>
    </chain-element>

  </aggregator-chain>
</jetm-config>

Similar to features ant-style property values will be expanded by looking for System.getProperty() values with the given name.

Using EtmMonitor plugins

Sometimes it is necessary to manage additional resources as part of the EtmMonitor lifecycle. Therefore JETM provides a simple but powerful plugin mechanism that allows to register classes to an EtmMonitor instance. See HTTP Console for plugin example.

Enable autostart

While it is recommend to start and stop an EtmMonitor manually it can be automatically started. Simply set autostart to true and xml-based JETM configurations will startup an EtmMonitor automatically. Additionally a Shutdown Hook will be registered to stop and free resources during VM shutdown.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jetm-config PUBLIC "-// void.fm //DTD JETM Config 1.2//EN"
                             "http://jetm.void.fm/dtd/jetm_config_1_2.dtd">
<jetm-config autostart="true">

 ...

</jetm-config>

Warning: Do not use this mechanism within Java™ EE applications if you plan to use hot redeploy. In this environment the ShutDown Hook will never be called and therefore allocated resources will never be freed.