Micrometer - Prometheus Gauge 显示 NaN
Micrometer - Prometheus Gauge displays NaN
我正在尝试使用 Micrometer.io 和 Spring Boot 2.0.0.RELEASE.
生成 Prometheus 指标
当我尝试将 List 的大小公开为 Gauge 时,它一直显示 NaN。在文档中它说;
It is your responsibility to hold a strong reference to the state object that you are measuring with a Gauge.
我尝试了一些不同的方法,但我无法解决问题。这是我的一些试验代码。
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
}
}
有没有人可以帮助解决这个问题?任何帮助将不胜感激。
在所有情况下,您都必须持有对观察到的实例的强引用。当您的 createGauge()
方法退出时,所有函数堆栈分配的引用都符合垃圾回收条件。
对于 #1
,像这样传递您的 atomicInteger
字段:registry.gauge("my_ai", atomicInteger);
。然后 increment/decrement 如你所愿。 micrometer 需要查询的时候,只要找到引用就会查询。
对于 #2
,传递您的 productService
字段和一个 lambda。基本上每当查询仪表时,它都会使用提供的对象调用该 lambda:registry.gauge("product_gauge", productService, productService -> productService.getProducts().size());
(不保证语法错误。)
我使用的仪表示例
private final AtomicLong countTryUsers = new AtomicLong(0);
Metrics.gauge("app.countTry", countTryUsers);
public void updateCountTryUsers(Long countTryUsersDb){
countTryUsers.set(countTryUsersDb);
}
所以我只注册了一次app.countTry,然后通过自定义方法更新 AtomicLong countTryUsers updateCountTryUsers()
我无法使用@panser 解决方案,因为我使用的是带标签的仪表。我的解决方案涉及使用 io.micrometer.core.instrument.Tag
的键和值作为映射键创建 com.google.common.util.concurrent.AtomicDouble
缓存,如下所示:
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(""));
}
这很好地满足了我的需求,希望对其他人有所帮助。
当我使用您的方法 #1 meterRegistry.gauge("myGauge", new AtomicDouble())
时,Micrometer.io 仪表也遇到了同样的问题。顺便说一下,我正在使用 Scala。我注意到在我创建了大约 50 个仪表之后,之后的新仪表显示 NaN
。
相反,我使用了:
val atomicDouble = new AtomicDouble()
Gauge
.builder("myGauge", atomicDouble, new AtomicDoubleToDoubleFunction)
.strongReference(true)
.register(meterRegistry)
和
class AtomicDoubleToDoubleFunction extends ToDoubleFunction[AtomicDouble] {
override def applyAsDouble(value: AtomicDouble): Double = value.doubleValue()
}
这解决了 NaN
问题,我的所有仪表都正确显示。我从 https://www.codota.com/code/java/classes/io.micrometer.core.instrument.Gauge 中找到了 .strongReference(true)
示例。
我遇到了同样的问题,在 spring 使用执行器和普罗米修斯启动时,我试图为地图大小创建一个指标。当我用 guageMapSize 注册地图时,有一段时间它显示了正确的值,之后它就停止更新,并不断显示 NAN,因为已经存在键的地图的度量,它没有更新。
要解决此问题,我们可以删除现有指标并使用更新后的值注册新指标。这对我有用。希望对你有用。
创建一个方法,removeMicroMeterGuage();用它来删除一个仪表,然后添加具有更新值的新仪表。
removeMicroMeterGuage(<keyName>);
registry.gaugeMapSize(<KeyName>, null, map);
public void removeMicroMeterGuage(String guageName) {
List<Meter> meterList = registry.getMeters();
for(Meter meter : meterList){
meter.getId().getName();
if(meter.getId().getName().equalsIgnoreCase(guageName)){
System.out.println(guageName+" guage removed");
registry.remove(meter);
}
}
}
我正在尝试使用 Micrometer.io 和 Spring Boot 2.0.0.RELEASE.
生成 Prometheus 指标当我尝试将 List 的大小公开为 Gauge 时,它一直显示 NaN。在文档中它说;
It is your responsibility to hold a strong reference to the state object that you are measuring with a Gauge.
我尝试了一些不同的方法,但我无法解决问题。这是我的一些试验代码。
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
}
}
有没有人可以帮助解决这个问题?任何帮助将不胜感激。
在所有情况下,您都必须持有对观察到的实例的强引用。当您的 createGauge()
方法退出时,所有函数堆栈分配的引用都符合垃圾回收条件。
对于 #1
,像这样传递您的 atomicInteger
字段:registry.gauge("my_ai", atomicInteger);
。然后 increment/decrement 如你所愿。 micrometer 需要查询的时候,只要找到引用就会查询。
对于 #2
,传递您的 productService
字段和一个 lambda。基本上每当查询仪表时,它都会使用提供的对象调用该 lambda:registry.gauge("product_gauge", productService, productService -> productService.getProducts().size());
(不保证语法错误。)
我使用的仪表示例
private final AtomicLong countTryUsers = new AtomicLong(0);
Metrics.gauge("app.countTry", countTryUsers);
public void updateCountTryUsers(Long countTryUsersDb){
countTryUsers.set(countTryUsersDb);
}
所以我只注册了一次app.countTry,然后通过自定义方法更新 AtomicLong countTryUsers updateCountTryUsers()
我无法使用@panser 解决方案,因为我使用的是带标签的仪表。我的解决方案涉及使用 io.micrometer.core.instrument.Tag
的键和值作为映射键创建 com.google.common.util.concurrent.AtomicDouble
缓存,如下所示:
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(""));
}
这很好地满足了我的需求,希望对其他人有所帮助。
当我使用您的方法 #1 meterRegistry.gauge("myGauge", new AtomicDouble())
时,Micrometer.io 仪表也遇到了同样的问题。顺便说一下,我正在使用 Scala。我注意到在我创建了大约 50 个仪表之后,之后的新仪表显示 NaN
。
相反,我使用了:
val atomicDouble = new AtomicDouble()
Gauge
.builder("myGauge", atomicDouble, new AtomicDoubleToDoubleFunction)
.strongReference(true)
.register(meterRegistry)
和
class AtomicDoubleToDoubleFunction extends ToDoubleFunction[AtomicDouble] {
override def applyAsDouble(value: AtomicDouble): Double = value.doubleValue()
}
这解决了 NaN
问题,我的所有仪表都正确显示。我从 https://www.codota.com/code/java/classes/io.micrometer.core.instrument.Gauge 中找到了 .strongReference(true)
示例。
我遇到了同样的问题,在 spring 使用执行器和普罗米修斯启动时,我试图为地图大小创建一个指标。当我用 guageMapSize 注册地图时,有一段时间它显示了正确的值,之后它就停止更新,并不断显示 NAN,因为已经存在键的地图的度量,它没有更新。
要解决此问题,我们可以删除现有指标并使用更新后的值注册新指标。这对我有用。希望对你有用。
创建一个方法,removeMicroMeterGuage();用它来删除一个仪表,然后添加具有更新值的新仪表。
removeMicroMeterGuage(<keyName>);
registry.gaugeMapSize(<KeyName>, null, map);
public void removeMicroMeterGuage(String guageName) {
List<Meter> meterList = registry.getMeters();
for(Meter meter : meterList){
meter.getId().getName();
if(meter.getId().getName().equalsIgnoreCase(guageName)){
System.out.println(guageName+" guage removed");
registry.remove(meter);
}
}
}