MicroProfile Metrics for monitoring your application

Last Updated:  October 11, 2020 | Published: August 18, 2019

Ensuring a stable operation of your application in production requires monitoring. Without monitoring, you have no insights about the internal state and health of your system and have to work with a black-box. MicroProfile Metrics gives you the ability to not only monitor pre-defined metrics like JVM statistics but also create custom metrics to monitor e.g. key figures of your business. These metrics are then exposed via HTTP and ready to visualize on a dashboard and create appropriate alarms.

Learn more about the  MicroProfile Metrics specification and how to use it in this blog post.

Specification profile: MicroProfile Metrics

  • Current version: 2.3
  • GitHub repository
  • Latest specification document
  • Basic use case: Add custom metrics (e.g. timer or counter) to your application and expose them via HTTP

Default MicroProfile metrics defined in the specification

The specification defines one endpoint with three subresources to collect metrics from a MicroProfile application:

  • The endpoint to collect all available metrics: /metrics
  • Base (pre-defined by the specification) metrics: /metrics/base
  • Application metrics: /metrics/application (optional)
  • Vendor-specific metrics: /metrics/vendor (optional)

So you can either use the main /metrics endpoint and get all available metrics for your application or one of the subresources.

The default media type for these endpoints is text/plain using the OpenMetrics format. You are also able to get them as JSON if you specify the Accept header in your request as application/json.

In the specification, you find a list of base metrics every MicroProfile Metrics compliant application server has to offer. These are mainly JVM, GC, memory, and CPU related metrics to monitor the infrastructure. The following output is the required amount of base metrics:

In addition, you are able to add metadata and tags to your metrics like in the output above for gc.time where name=global is a tag. You can use these tags to further separate a metric for multiple use cases.

Since MicroProfile 3.3 there is now also a new (optional) base metric REST.request. This tracks the total count of requests and the total elapsed time spent at your JAX-RS endpoints. As this is an optional metric, it might not be available in every implementation.

Create a custom metric with MicroProfile Metrics

There are two ways for defining a custom metric with MicroProfile Metrics: using annotations or programmatically. The specification offers five different metric types:

  • Timer: sampling the time for e.g. a method call
  • Counter: monotonically counting e.g. invocations of a method
  • Gauges: sample the value of an object e.g. current size of JMS queue
  • Meters: tracking the throughput of e.g. a JAX-RS endpoint
  • Histogram: calculate the distribution of values e.g. the variance of incoming user agents

For simple use cases, you can make use of annotations and just add them to a method you want to monitor. Each annotation offers attributes to configure tags and metadata for the metric:

If your monitoring use case requires a more dynamic configuration, you can programmatically create/update your metrics. For this, you just need to inject the MetricRegistry to your class:

Create a timer metric

If you want to track and sample the duration for a method call, you can make use of timers. You can add them with the @Timer annotation or using the MetricRegistry. A good use case might be tracking the time for a call to an external service:

While using the timer metric type you'll also get a count of method invocations and mean/max/min/percentile calculations out-of-the-box:

Getting started with Eclipse MicroProfile Course Bundle

NEWS: Up-to-date with MicroProfile 3.3

All you need to know about MicroProfile

Looking for a resource to learn more about MicroProfile and all its specifications in-depth? Signup for the MicroProfile Course Bundle (E-Book & Video Course)

Be aware that you get the result as nanoseconds if you request the JSON result and for the OpenMetrics format, you get seconds:

Create a simple timer

As you saw it in the chapter above, the @Timed annotation already calculates throughput and percentile statistics. If you don't need this amount of data to e.g. reduce the bandwidth, you can fall back on @SimplyTimed.

This annotation is similar to the already mentioned timer, but solely tracks how long an invocation took to complete and does not prepare any statistics for you:

Create a counter metric
The next metric type is the simplest one: a counter. With the counter, you can track e.g. the number of invocations of a method:

In one of the previous MicroProfile Metrics versions, you were able to decrease the counter and have a not monotonic counter. As this caused confusion with the gauge metric type, the current specification version defines this metric type as a monotonic counter which can only increase.

If you use the programmatic approach, you are also able to define the amount of increase for the counter on each invocation:

Create a metered metric

The meter type is perfect if you want to measure the throughput of something and get the one-, five- and fifteen-minute rates. As an example I'll monitor the throughput of a JAX-RS endpoint:

After several invocations, the result looks like the following:

Depending on your implementation provider of MicroProfile Metrics, tracking time and invocations for JAX-RS endpoints might be redundant, as there is now the optional base metric REST.request.

Create a gauge metric

To monitor a value that can increase and decrease over time, you should use the gauge metric type. Imagine you want to visualize the current disk size or the remaining messages to process in a queue:

The unit attribute of the annotation is required and has to be explicitly configured. There is a MetricUnits class that you can use for common units like seconds or megabytes.

In contrast to all other metrics, the @Gauge annotation can only be used in combination with a single instance (e.g. @ApplicationScoped) as otherwise, it would be not clear which instance represents the actual value. There is a @ConcurrentGauge if you need to count parallel invocations.

The outcome is the current value of the gauge, which might increase or decrease over time:

YouTube video for using MicroProfile Metrics

Watch the following YouTube video of my Getting started with MicroProfile series to see MicroProfile Metrics in action:

You can find the source code for this blog post on GitHub.

Have fun using MicroProfile Metrics,


  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

    Sign up for Our Mailing List And Get

    the Testing Java Applications ($9) Cheat Sheet for Free

    Testing Java Applications Cheat Sheet Cover