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 keeps displaying NaN. In the documentation it says that;
It is your responsibility to hold a strong reference to the state object that you are measuring with a Gauge.
I have tried some different ways but I could not solve the problem. Here is my code with some trials.
import io.micrometer.core.instrument.*;
import io.swagger.backend.model.Product;
import io.swagger.backend.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@RestController
@RequestMapping("metrics")
public class ExampleController {
private AtomicInteger atomicInteger = new AtomicInteger();
private ProductService productService;
private final Gauge productGauge;
@Autowired
public HelloController(ProductService productService,
MeterRegistry registry) {
this.productService = productService;
createGauge("product_gauge", productService.getProducts(), registry);
}
private void createGauge(String metricName, List<Product> products,
MeterRegistry registry) {
List<Product> products = productService.getProducts();
// #1
// this displays product_gauge as NaN
AtomicInteger n = registry.gauge("product_gauge", new AtomicInteger(0));
n.set(1);
n.set(2);
// #2
// this also displays product_gauge as NaN
Gauge
.builder("product_gauge", products, List::size)
.register(registry);
// #3
// this displays also NaN
testListReference = Arrays.asList(1, 2);
Gauge
.builder("random_gauge", testListReference, List::size)
.register(registry);
// #4
// this also displays NaN
AtomicInteger currentHttpRequests = registry.gauge("current.http.requests", new AtomicInteger(0));
}
@GetMapping(path = "/product/decrement")
public Counter decrementAndGetProductCounter() {
// decrement the gague by one
}
}
Is there anyone who can help with this issue? Any help would be appreciated.
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 displayedNaN
.Instead I used:
with
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 .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 youratomicInteger
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 yourproductService
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 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 withio.micrometer.core.instrument.Tag
's key and values as map key, heres goes:That worked pretty well for my needs, hopefully help other people.
my example for gauge using
so I register app.countTry just once, and then just update AtomicLong countTryUsers over custom method updateCountTryUsers()