We addressed some significant questions while creating MicroProfile Metrics v5.0.
API or no API
In light of the increasing prevalence of developer use of APIs from Micrometer and OpenTelemetry, we considered whether we should continue to have a distinct API for MicroProfile Metrics. We decided to continue our path of providing an API for the following reasons:
-
provides an easy-to-use metrics API for application developers
-
provides continuity for the existing MicroProfile Metrics user community
-
provides a MicroProfile-style API (for example, CDI-based annotations), and configurability (MicroProfile Config), for ease of adoption by MicroProfile users
-
ensures compatibility across APIs within the same MicroProfile release
We also considered feedback from an informal poll in which a majority of respondents said they would use a MicroProfile Metrics API, given the other options.
Fixed implementation or vendor-chosen implementation
We considered whether MicroProfile Metrics should require vendors to use a particular metrics library in their implementations. The benefit of requiring a particular metrics library would be the potential for improved consistency across vendors. The benefits of not requiring a particular metrics library would be avoiding MicroProfile potentially overreaching by telling vendors which libraries to use, and leaving flexibility for vendors to change their implementation in the future if needed. Ultimately, we decided to not require a specific metrics library to be used in the implementation. Vendors may choose to implement using Micrometer libraries, OpenTelemetry libraries, Dropwizard libraries, custom code, or anything else they choose.
The following is an example configuration in YAML format.
base:
- name: "thread-count"
mbean: "java.lang:type=Threading/ThreadCount"
description: "Number of currently deployed threads"
unit: "none"
type: "gauge"
displayName: "Current Thread count"
- name: "peak-thread-count"
mbean: "java.lang:type=Threading/PeakThreadCount"
description: "Max number of threads"
unit: "none"
type: "gauge"
- name: "total-started-thread-count"
mbean: "java.lang:type=Threading/TotalStartedThreadCount"
description: "Number of threads started for this server"
unit: "none"
type: "counter"
- name: "max-heap"
mbean: "java.lang:type=Memory/HeapMemoryUsage#max"
description: "Number of threads started for this server"
unit: "bytes"
type: "counter"
tags: "kind=memory"
vendor:
- name: "msc-loaded-modules"
mbean: "jboss.modules:type=ModuleLoader,name=BootModuleLoader-2/LoadedModuleCount"
description: "Number of loaded modules"
unit: "none"
type: "gauge"
This configuration can be backed into the runtime or be provided via an external configuration file.
@ApplicationScoped
public class MetricRegistryFactory {
@Produces
public static MetricRegistry getDefaultRegistry() {
return getApplicationRegistry();
}
@Produces
@RegistryType(type = Type.APPLICATION)
public static MetricRegistry getApplicationRegistry() {
// Returns the static instance of the Application MetricRegistry
[...]
}
@Produces
@RegistryType(type = Type.BASE)
public static MetricRegistry getBaseRegistry() {
// Returns the static instance of the Base MetricRegistry
[...]
}
@Produces
@RegistryType(type = Type.VENDOR)
public static MetricRegistry getVendorRegistry() {
// Returns the static instance of the Vendor MetricRegistry
[...]
}
}
The @Counted
annotation has changed. Users of the previous @Counted
annotation were surprised to learn that by default counters were not monotonic. Also, the OpenMetrics format expects all counters to be monotonic.
To migrate:
-
Replace
@Counted()
or@Counted(monotonic=false)
with@ConcurrentGauge
. A set of gauges will be created in the OpenMetrics output for each@ConcurrentGauge
. -
Replace
@Counted(monotonic=true)
with@Counted
(monotonic flag is gone)
This change has also had an impact on the Counter
interface to basically follow the above change:
-
Modify code which uses
Counter.dec()
to use aGauge
orConcurrentGauge
.
Some base metrics' types have changed from Counter
to Gauge
since counters must now count monotonically. Update code or dashboards that use the following metrics:
-
thread.count
-
thread.daemon.count
-
classloader.currentLoadedClass.count
-
thread.max.count
Some base metrics' names have changed to follow the convention of ending the name of accumulating counters with total
. Update code or dashboards that use the following metrics:
-
gc.count → gc.total
-
classloader.currentLoadedClass.count → classloader.loadedClasses.count (changed to stay consistent with other classloader metric names)
-
classloader.totalLoadedClass.count → classloader.loadedClasses.total
-
classloader.totalUnloadedClass.count → classloader.unloadedClasses.total