Microprofile Metrics using WildFly application Server

In the second tutorial about monitoring WildFly we will learn how to collect application metrics by applying MicroProfile Metrics API  that will show up in WildFly 15 and above.

So in the first article Monitoring WildFly with Prometheus we have learned how to install and configure Prometheus so that WildFly metrics can be captured. In order to capture application metrics we can apply the annotations contained in the org.eclipse.microprofile.metrics.annotation package. These annotations cover several crucial aspects such as how many time a method has been executed, the rate at which an application event occurred, or the time it took to complete one business method.

Let’s start from the @Counted annotation which counts how many time a request has been made.

The @Counted metric

package demomp;

import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;

import org.eclipse.microprofile.metrics.MetricUnits;
import org.eclipse.microprofile.opentracing.Traced;

public class RESTEndpoints {

    @Counted(description = "How many greetings", absolute = true, monotonic = true)
    public String hello(@DefaultValue("my friend!") @QueryParam("name") String name) {
        return "Hello "+name;



Within the @Counted annotation, besides the description we have also the absolute flag, as true, that means the name of the package and class will not be prepended to the metric name. The monotonic flag, as true, means it will count total invocations of the annotated method. If the flag is false (default) it will count concurrent invocations.

When invoked the above REST Service, the following metric will show up on WildFly at http://localhost:9990/metrics:

# HELP application:hello How many greetings
# TYPE application:hello counter
application:hello 1.0

One further customization can be done through the org.eclipse.microprofile.config.inject.ConfigProperty annotation that is able to inject key/values into your Service. For example:

@ConfigProperty(name = "greeting", defaultValue = "my dear friend")
private String greeting;

In this case, the method will be transformed into:

@Counted(description = "How many greetings", absolute = true, monotonic = true)
public String hello(@DefaultValue("my friend!") @QueryParam("name") String name) {
    return "Hello " + greeting;

Let’s move to some other annotations.

The @Gauge metric

The @Gauge is the most basic metric type that you can use as it just returns a value.

@Gauge(unit = "time", name = "currentime", absolute = true)
public Long getTime() {
    return  System.currentTimeMillis();

It will display the result in the metrics as follows:

# TYPE application:currentime_time gauge
application:currentime_time 1.550847591437E12

The @Metered annotation

The @Metered annotation measures the rate at which a set of events occur.

@Metered(name = "sell-share", unit = MetricUnits.MINUTES, description = "Metrics to monitor frequency of share sale.", absolute = true)
public String sellStock() {

    // do business
    return "sold!";

The @Timed annotation

Finally, the @Timed annotatoin can keep track of the duration of an event, such as a business transaction:

@Timed(name = "tx-time",
        description = "Metrics to monitor time to complete ticket purchase.",
        unit = MetricUnits.MINUTES,
        absolute = true)
public String buyTicket() {

    try {
        Thread.sleep((long) (Math.random() * 1000));
    } catch (InterruptedException e) {
    return "transaction completed!";

Once applied, a comprehensive list of statistics will be provided for all @Timed events:

# TYPE application:tx_time_rate_per_second gauge
application:tx_time_rate_per_second 0.4317018836985329
# TYPE application:tx_time_one_min_rate_per_second gauge
application:tx_time_one_min_rate_per_second 1.374706127912254
# TYPE application:tx_time_five_min_rate_per_second gauge
application:tx_time_five_min_rate_per_second 7.780132092018116
# TYPE application:tx_time_fifteen_min_rate_per_second gauge
application:tx_time_fifteen_min_rate_per_second 10.386035934806122
# TYPE application:tx_time_min_seconds gauge
application:tx_time_min_seconds 1.290288978E11
# TYPE application:tx_time_max_seconds gauge
application:tx_time_max_seconds 1.290288978E11
# TYPE application:tx_time_mean_seconds gauge
application:tx_time_mean_seconds 1.290288978E11
# TYPE application:tx_time_stddev_seconds gauge
application:tx_time_stddev_seconds 0.0
# HELP application:tx_time_seconds Metrics to monitor time to complete ticket purchase.
# TYPE application:tx_time_seconds summary
application:tx_time_seconds_count 1.0
application:tx_time_seconds{quantile="0.5"} 1.290288978E11
application:tx_time_seconds{quantile="0.75"} 1.290288978E11
application:tx_time_seconds{quantile="0.95"} 1.290288978E11
application:tx_time_seconds{quantile="0.98"} 1.290288978E11
application:tx_time_seconds{quantile="0.99"} 1.290288978E11
application:tx_time_seconds{quantile="0.999"} 1.290288978E11
# HELP base:classloader_total_loaded_class_count Displays the t

Building the project

In order to build a project using Microprofile metrics, we need to add the following set of dependencies, which cover OpenTracing JAX-RS tracing, Microprofile configurations and MicroProfile metrics API: