Quarkus Metrics - 拦截指标端点

问题描述

有没有办法在使用 https://quarkus.io/guides/micrometer 时监听 /metrics 端点?

我想收集一些需要调用不同 API 的指标...而不是设置时间表 (https://quarkus.io/guides/scheduler-reference)...

示例:

  • 我在 Kubernetes API 中查询了一些自定义资源
  • 然后我想用不同的标签更新一些仪表

一个 /metrics 给我们:

# HELP test_metric_a  
# TYPE test_metric_a gauge
test_metric_a{namespace="test123",user="admin",} 1.0
test_metric_a{namespace="testabc",} 1.0

# HELP test_metric_b  
# TYPE test_metric_b gauge
test_metric_b 0.0

第二个 /metrics 可能会给出:

# HELP test_metric_a  
# TYPE test_metric_a gauge
test_metric_a 0.0

# HELP test_metric_b  
# TYPE test_metric_b gauge
test_metric_b{namespace="testabc",} 2.0

我如何使用 https://quarkus.io/guides/micrometer 调用 Kubernetes API,因为应用程序内可能没有任何更改以导致仪表/注册表更新,但外部事件或时间流逝会导致状态(所需的指标输出)更改...

请注意,自定义指标(请参阅下面的评论)仅被调用一次(我猜它是单例?)。理想情况下,我希望每次回答 /metrics 时都调用它...

进一步编辑以显示仪表是如何创建/更新的:

@ApplicationScoped
public class MyMetrics {

    private final MeterRegistry registry;

    MyMetrics(MeterRegistry registry) {
        this.registry = registry;
    }

    //...

    // somehow call this whenever /metrics is hit?
    protected void updateGauges() {
        // use KubernetesClient to query K8s API to gather some customer resources,then process that list... etc...
        // there is a loop over the below for user/namespace pairs in the tags
        //final Tags tags = getTags();
        //int count = getCount();
        //registry.gauge("test_metric_a",tags,count);

        // so this Could roll out to something like:
        registry.gauge("test_metric_a",Tags.of("user","user1","namespace","ns1"),1);
        registry.gauge("test_metric_a","user2",2);
        registry.gauge("test_metric_a","ns2"),1);

        registry.gauge("test_metric_b",1);
        registry.gauge("test_metric_b",1);
    }
}

...也许这些gauges可能是counters...但问题仍然存在...

解决方法

好的。正如我在评论中所述,当收集指标时(例如,在 Prometheus 的情况下,当端点被抓取时)会观察到仪表的值。

如果您正在谈论添加包含名称空间之类的标签,那么常用标签示例可能对您有所帮助,您可以在其中预先计算标签:

registry.config().commonTags("stack","prod","region","us-east-1");

这会将这些标签添加到所有指标,但您可以使用 MeterFilter 来提高选择性(例如,仅将标签添加到符合某些条件的指标)。

new MeterFilter() {
    @Override
    public Meter.Id map(Meter.Id id) {
       if(id.getName().startsWith("test")) {
          return id.withName("extra." + id.getName()).withTag("extra.tag","value");
       }
       return id;
    }
}

https://micrometer.io/docs/concepts#_common_tags

如果您尝试根据从 Kubernetes API 检索到的数据更新标签/标签值,您可能需要运行一个周期性任务(例如计划任务),该任务将使用新标签重新注册仪表。

请注意,对于已被垃圾收集的仪表,千分尺将省略或返回 NaN(取决于您使用的注册表),因此如果您希望使用先前标记值注册的仪表保持不变,则需要使它们强大参考资料。