更新:当前来源可用here.
我目前正在为一家定制Prometheus出口商工作,价格为changedetection.io英镑,以公布所有注册手表的刮擦和价格指标.
在完成了有效的概念验证后,我正在try 维护该项目并准备好发布到开源社区(例如添加测试文档并使其功能尽可能完整).
在编写这些测试时,我在try 测试在监控的changedetection.io实例中创建新手表时的动态注册时发现了一个问题.为了让出口商无需重新启动即可拾取它们,我在每次收集运行时判断API以获取新添加的手表.
以下是priceCollector
的Collect
功能:
func (c *priceCollector) Collect(ch chan<- prometheus.Metric) {
// check for new watches before collecting metrics
watches, err := c.ApiClient.getWatches()
if err != nil {
log.Errorf("error while fetching watches: %v", err)
} else {
for id, watch := range watches {
if _, ok := c.priceMetrics[id]; !ok {
// create new metric and register it on the DefaultRegisterer
c.priceMetrics[id] = newPriceMetric(prometheus.Labels{"title": watch.Title}, c.ApiClient, id)
prometheus.MustRegister(c.priceMetrics[id])
log.Infof("Picked up new watch %s, registered as metric %s", watch.Title, id)
}
}
}
// collect all registered metrics
for _, metric := range c.priceMetrics {
metric.Collect(ch)
}
}
newPriceMetric
函数只是创建一个新的priceMetric
对象,该对象由prometheus.Desc
、ApiClient
(提供访问www.example.com API的类)和UUID
组成changedetection.io
func newPriceMetric(labels prometheus.Labels, apiClient *ApiClient, uuid string) priceMetric {
return priceMetric{
desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "watch", "price"),
"Current price of an offer type watch",
nil, labels,
),
apiClient: apiClient,
UUID: uuid,
}
}
测试默认行为运行得非常好,并且通过了所有测试,但当我try 测试添加新手表的行为时(当出口器在不重新启动的情况下运行时),测试失败.
注:
expectMetrics
和expectMetricCount
都是普罗米修斯自己的testutil.CollectAndCompare
和testutil.CollectAndCount
的包装函数.助手CreateTestApiServer
创建包装的httptest
服务器,该服务器基于传递的map[string]*data.WatchItem
struct 返回SON有效负载.
func TestAutoregisterPriceCollector(t *testing.T) {
watchDb := createCollectorTestDb()
server := testutil.CreateTestApiServer(t, watchDb)
defer server.Close()
c, err := NewPriceCollector(server.URL(), "foo-bar-key")
if err != nil {
t.Fatal(err)
}
expectMetricCount(t, c, 2, "changedetectionio_watch_price")
// now add a new watch and expect the collector to pick it up
uuid, newItem := testutil.NewTestItem("Item 3", 300, "USD")
watchDb[uuid] = newItem
expectMetrics(t, c, "price_metrics_autoregister.prom", "changedetectionio_watch_price")
expectMetricCount(t, c, 3, "changedetectionio_watch_price")
}
运行该测试时,运行失败并出现以下错误:
collector_test.go:23:返回了意外的指标:收集指标失败:收集的指标changedetectionio_watch_price标签:{名称:"title"值:"Project 3"}仪表:{值:300},带有未注册的描述符Desc{fqName:"changedetectionio_watch_price",帮助:"报价类型手表的当前价格",constLabels:{title="Project 3"},VariableLabels:{}
我目前认为这个错误与testutil.CollectAnd*
的内部工作方式有关.根据函数注释,他们在newly created pedantic Registry上注册收集器,这可能会导致它无法拾取懒惰注册的描述符.
有什么 idea 吗?