I am trying to generate Prometheus metrics with using Micrometer.io with Spring Boot 2.0.0.RELEASE.
When I am trying to expose the size of a List as Gauge, it ke
my example for gauge using
private final AtomicLong countTryUsers = new AtomicLong(0);
Metrics.gauge("app.countTry", countTryUsers);
public void updateCountTryUsers(Long countTryUsersDb){
countTryUsers.set(countTryUsersDb);
}
so I register app.countTry just once, and then just update AtomicLong countTryUsers over custom method updateCountTryUsers()
I wasn't able to use @panser solution 'cause I'm using gauges with labels. My solution involved the creation of com.google.common.util.concurrent.AtomicDouble
cache with io.micrometer.core.instrument.Tag
's key and values as map key, heres goes:
private static final Map<String, AtomicDouble> GAUGE_CACHE = new HashMap<>();
public void handleGauge(String name, List<Tag> tags, double value) {
String gaugeKey = this.gaugeKey(name, tags);
if (!GAUGE_CACHE.containsKey(gaugeKey)) {
GAUGE_CACHE.put(gaugeKey, new AtomicDouble());
}
Objects.requireNonNull(this.registry.gauge(name, tags, GAUGE_CACHE.get(gaugeKey))).set(value);
}
private String gaugeKey(String name, List<Tag> tags) {
return name + ":" + tags.stream().map(tag -> tag.getKey() + tag.getValue()).collect(Collectors.joining(""));
}
That worked pretty well for my needs, hopefully help other people.
In all cases, you must hold a strong reference to the observed instance. When your createGauge()
method is exited, all function stack allocated references are eligible for garbage collection.
For #1
, pass your atomicInteger
field like this: registry.gauge("my_ai", atomicInteger);
. Then increment/decrement as you wish. Whenever micrometer needs to query it, it will as long as it finds the reference.
For #2
, pass your productService
field and a lambda. Basically whenever the gauge is queried, it will call that lambda with the provided object: registry.gauge("product_gauge", productService, productService -> productService.getProducts().size());
(No guarantee regarding syntax errors.)
I had the same issue with Micrometer.io gauges when I used your method #1 meterRegistry.gauge("myGauge", new AtomicDouble())
. I am using Scala by the way. I noticed that after I created about 50 gauges, the new gauges after that displayed NaN
.
Instead I used:
val atomicDouble = new AtomicDouble()
Gauge
.builder("myGauge", atomicDouble, new AtomicDoubleToDoubleFunction)
.strongReference(true)
.register(meterRegistry)
with
class AtomicDoubleToDoubleFunction extends ToDoubleFunction[AtomicDouble] {
override def applyAsDouble(value: AtomicDouble): Double = value.doubleValue()
}
This fixed the NaN
issue, and all of my gauges appear correctly. I found the .strongReference(true)
example from https://www.codota.com/code/java/classes/io.micrometer.core.instrument.Gauge .