10

我正在尝试使用 Micrometer.io 和 Spring Boot 2.0.0.RELEASE 生成 Prometheus 指标。

当我试图将 List 的大小公开为 Gauge 时,它​​一直显示 NaN。在文档中它说;

您有责任对您正在使用 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
    }
}

有没有人可以帮助解决这个问题?任何帮助,将不胜感激。

4

4 回答 4

7

在所有情况下,您都必须持有对观察到的实例的强引用。当您的createGauge()方法退出时,所有函数堆栈分配的引用都有资格进行垃圾收集。

对于#1,像这样传递您的atomicInteger字段:registry.gauge("my_ai", atomicInteger);。然后根据需要增加/减少。每当千分尺需要查询时,只要找到参考,它就会查询。

对于#2,传递您的productService字段和一个 lambda。基本上,每当查询仪表时,它都会使用提供的对象调用该 lambda:registry.gauge("product_gauge", productService, productService -> productService.getProducts().size());

(不保证语法错误。)

于 2018-06-26T20:44:18.947 回答
4

我无法使用@panser 解决方案,因为我使用的是带有标签的仪表。我的解决方案涉及使用的键和值作为映射键创建com.google.common.util.concurrent.AtomicDouble缓存,如下:io.micrometer.core.instrument.Tag

    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(""));
    }

这对我的需求非常有效,希望能帮助其他人。

于 2019-01-22T01:24:47.997 回答
3

当我使用你的方法 #1 时,我对 Micrometer.io 仪表有同样的问题meterRegistry.gauge("myGauge", new AtomicDouble())。顺便说一句,我正在使用 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)找到了这个例子。

于 2019-06-28T16:10:52.857 回答
0

我的仪表使用示例

private final AtomicLong countTryUsers = new AtomicLong(0);
Metrics.gauge("app.countTry", countTryUsers);

public void updateCountTryUsers(Long countTryUsersDb){
   countTryUsers.set(countTryUsersDb);
}

所以我只注册一次app.countTry,然后通过自定义方法 updateCountTryUsers()更新 AtomicLong countTryUsers

于 2019-01-02T23:25:31.297 回答