跳至内容

Prometheus-Go 动态 labels 的实现

2025-11-09 19:25:31

prometheus-go 的标签是静态的,没法在创建后动态更新,而本文就是为了解决该问题,且是以极低的成本实现。

我的实现是,根据传入的 labels map 的 key 创建不同的 Counter 或 Gauge,但在注册时,会遇到名字重复的问题,最后发现该问题可通过重写 Describe 来绕过去,举个例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
type MyCounter struct {
	*prometheus.CounterVec
	desc *prometheus.Desc
}

type MyGauge struct {
	*prometheus.GaugeVec
	desc *prometheus.Desc
}

func (counter *MyCounter) Describe(ch chan<- *prometheus.Desc) {
	ch <- counter.desc
}

func NewMyCounter(metricName, unionName string, labelKeys []string) *MyCounter {
	return &MyCounter{
		CounterVec: prometheus.NewCounterVec(prometheus.CounterOpts{Name: metricName, Help: ""}, labelKeys),
		desc:       prometheus.NewDesc(unionName, "", labelKeys, nil),
	}
}

func (gauge *MyGauge) Describe(ch chan<- *prometheus.Desc) {
	ch <- gauge.desc
}

func NewMyGauge(metricName, unionName string, labelKeys []string) *MyGauge {
	return &MyGauge{
		GaugeVec: prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: metricName, Help: ""}, labelKeys),
		desc:     prometheus.NewDesc(unionName, "", labelKeys, nil),
	}
}

其中,metricName 可以相同,但 unionName 必须唯一,可以考虑用 map 存储 unionName 和 Counter 或 Gauge 的关系,map 的 key 可以为 metricName + unionName,unionName 可由 labelKeys 组成。

我们可以这么理解,Describe 是指标的描述信息,这个不能重复或冲突,但 Name 不是,Name 用于导出时生成指标名,需要注意的是,同一个 metricName 下,labelKeys 必须是唯一的,不唯一时,同样有问题。

最后更新于