普罗米修斯 CollectAndCount 总是返回 1

Posted

技术标签:

【中文标题】普罗米修斯 CollectAndCount 总是返回 1【英文标题】:prometheus CollectAndCount always returns 1 【发布时间】:2021-03-28 05:09:19 【问题描述】:

我想检测一个程序并通过测试检查检测是否正确完成。我发现了 testutil,它有一个名为 CollectAndCount 的函数。我希望该函数返回与我在 HTTP 指标端点上看到的相同的计数。当我将下面示例中的计数器增加 2 倍时,CollectAndCount 返回 1 而不是预期的 2。在这种情况下使用 ToFloat64 函数是可行的。因为我也想获得直方图的计数,所以 ToFloat64 不可用。

package main

import (
    "testing"

    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/testutil"
)

func TestMetricT(t *testing.T) 
    var Duration = prometheus.NewHistogram(prometheus.HistogramOpts
        Name:    "duration",
        Help:    "Help",
        Buckets: prometheus.DefBuckets,
    )

    var Errors = prometheus.NewCounter(prometheus.CounterOpts
        Name: "errors",
        Help: "Help",
    )

    prometheus.MustRegister(Duration, Errors)

    timer := prometheus.NewTimer(Duration)
    timer.ObserveDuration()
    Errors.Inc()

    timer = prometheus.NewTimer(Duration)
    timer.ObserveDuration()

    Errors.Inc()

    errors := testutil.CollectAndCount(Errors)
    if errors != 2 
        t.Error("no 2 increments but", errors, "ToFloat64 counts", testutil.ToFloat64(Errors))
    

    observations := testutil.CollectAndCount(Duration)
    if observations != 2 
        t.Error("not 2 observations but", observations)
    


输出是:

--- FAIL: TestMetricT (0.00s)
    so_test.go:35: no 2 increments but 1 ToFloat64 counts 2
    so_test.go:40: not 2 observations but 1
FAIL
FAIL

【问题讨论】:

你找到解决这个问题的方法了吗? 不,我没有找到解决方案。此外,我没有花时间在他们的问题跟踪器上打开问题或检查它是否在较新版本中得到解决。如果您有更多信息,请告诉我。 【参考方案1】:

我使用了与您的示例略有不同的指标来说明正在发生的事情,并且我还决定使用 testify 来获得一个更紧凑的示例。如有任何问题,请随时询问。


TL;DR:CollectAndCount 返回收集的指标数量,ToFloat64 返回单个指标的实际值。

package main

import (
    "testing"

    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/testutil"
    "github.com/stretchr/testify/assert"
)

func TestMetricT(t *testing.T) 
    assert := assert.New(t)

    var A = prometheus.NewCounter(prometheus.CounterOpts
        Name: "A",
        Help: "Help",
    )

    var B = prometheus.NewCounter(prometheus.CounterOpts
        Name: "B",
        Help: "Help",
    )

    // CounterVec is a Collector that bundles a set of Counters
    var C = prometheus.NewCounterVec(prometheus.CounterOpts
        Name: "C",
        Help: "Help",
    , []string"subname",
    )

    prometheus.MustRegister(A, B, C)

    // After the registration, simple metrics like A and B can
    // be collected with the CollectAndCount function.
    // The CollectAndCount function seems to count the number of
    // metrics which were collected, not their value.
    assert.Equal(1, testutil.CollectAndCount(A))
    assert.Equal(1, testutil.CollectAndCount(B))
    // Different to the "simple" metrics like the counters A and B,
    // C is a CounterVec, a collection of counters that share
    // the same description.
    // After its registration, this collection contains 0 metrics,
    // until one is added to the collection.
    assert.Equal(0, testutil.CollectAndCount(C))

    // ToFloat64 returns the actual value of the metric. After the
    // registration, the value of the counters A and B is 0.
    assert.Equal(float64(0), testutil.ToFloat64(A))
    assert.Equal(float64(0), testutil.ToFloat64(B))

    A.Inc()
    B.Inc()

    // After we incremented A and B, CollectAndCount still
    // collects exactly one metric series for A, and one for B.
    assert.Equal(1, testutil.CollectAndCount(A))
    assert.Equal(1, testutil.CollectAndCount(B))
    // But the actual values of the counters were incremented by 1.
    assert.Equal(float64(1), testutil.ToFloat64(A))
    assert.Equal(float64(1), testutil.ToFloat64(B))

    A.Inc()
    B.Inc()

    assert.Equal(1, testutil.CollectAndCount(A))
    assert.Equal(1, testutil.CollectAndCount(B))
    // Now we incremented the counters again, and ToFloat64
    // returns 2, since we've incremented each counter 2 times.
    assert.Equal(float64(2), testutil.ToFloat64(A))
    assert.Equal(float64(2), testutil.ToFloat64(B))

    A.Inc()

    assert.Equal(1, testutil.CollectAndCount(A))
    assert.Equal(1, testutil.CollectAndCount(B))
    // Only incremented A
    assert.Equal(float64(3), testutil.ToFloat64(A))
    assert.Equal(float64(2), testutil.ToFloat64(B))

    // To increment C, we have to use a label. This
    // adds a metric with the label "firstLabel" to the
    // collection C.
    C.WithLabelValues("firstLabel").Inc()
    // Now, CollectAndCount will collect the one metric which
    // is contained in the collection C.
    assert.Equal(1, testutil.CollectAndCount(C))
    // The ToFloat64 value of the metrics is as expected.
    // We have to again use a label here, since we cannot get a
    // single float value from a collection.
    assert.Equal(float64(1), testutil.ToFloat64(C.WithLabelValues("firstLabel")))

    // Let's increase the "firstLabel" metric again and add another one.
    C.WithLabelValues("firstLabel").Inc()
    C.WithLabelValues("secondLabel").Inc()

    // CollectAndCount now collects 2 metrics from the collection C.
    assert.Equal(2, testutil.CollectAndCount(C))
    assert.Equal(float64(2), testutil.ToFloat64(C.WithLabelValues("firstLabel")))
    assert.Equal(float64(1), testutil.ToFloat64(C.WithLabelValues("secondLabel")))

    C.WithLabelValues("firstLabel").Inc()
    C.WithLabelValues("secondLabel").Inc()
    C.WithLabelValues("thirdLabel").Inc()

    assert.Equal(3, testutil.CollectAndCount(C))
    assert.Equal(float64(3), testutil.ToFloat64(C.WithLabelValues("firstLabel")))
    assert.Equal(float64(2), testutil.ToFloat64(C.WithLabelValues("secondLabel")))
    assert.Equal(float64(1), testutil.ToFloat64(C.WithLabelValues("thirdLabel")))


【讨论】:

顺便说一句,您不必在使用ToFloat64 之前使用CollectAndCount,因为ToFloat64 也会从提供的收集器中收集所需的指标。

以上是关于普罗米修斯 CollectAndCount 总是返回 1的主要内容,如果未能解决你的问题,请参考以下文章

有手动挡的车了为什么还要买自动挡

为啥函数返回的值总是 null 或 undefined?

普罗米修斯的故事

普罗米修斯的故事,最后的结局

普罗米修斯的架构

Docker 搭建普罗米修斯