Go / 开源社区 / 源码 · 2020/04/25 0

prometheus中honor_labels配置项的源码分析

标签解释

https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config


# honor_labels controls how Prometheus handles conflicts between labels that are
# already present in scraped data and labels that Prometheus would attach
# server-side ("job" and "instance" labels, manually configured target
# labels, and labels generated by service discovery implementations).
#
# If honor_labels is set to "true", label conflicts are resolved by keeping label
# values from the scraped data and ignoring the conflicting server-side labels.
#
# If honor_labels is set to "false", label conflicts are resolved by renaming
# conflicting labels in the scraped data to "exported_<original-label>" (for
# example "exported_instance", "exported_job") and then attaching server-side
# labels.
#
# Setting honor_labels to "true" is useful for use cases such as federation and
# scraping the Pushgateway, where all labels specified in the target should be
# preserved.
#
# Note that any globally configured "external_labels" are unaffected by this
# setting. In communication with external systems, they are always applied only
# when a time series does not have a given label yet and are ignored otherwise.
[ honor_labels: boolean | default = false ]

根据官方解释honor_labels配置项的作用主要用于解决被采集的目标标签和服务端本地标签(包含静态标签和服务发现的标签)发生同名时的覆盖规则

  • 当honor_labels为true

同名的标签以被采集的标签为准忽略服务端本地标签

  • 当honor_labels为false(默认为false)

同名的被采集的标签将不会覆盖服务端本地标签,而是标签名前增加exported_而服务端本地标签保留(例如两端同时拥有job标签,被采集端标签将会替换exported_job服务端本地标签继续使用job标签

以上官方解释了发生标签同名的情况下的覆盖规则,但是在业务实际使用中我们还需要考虑被采集端偶尔缺失该同名标签或者标签值为空的情况。我们需要了解该场景下本地标签是否会被删除还是会继续保留。

源码分析

https://github.com/prometheus/prometheus/blob/4b5e7d4984a135abd3729b9a2a5904336d35bc21/scrape/scrape.go#L455

func mutateSampleLabels(lset labels.Labels, target *Target, honor bool, rc []*relabel.Config) labels.Labels {
	lb := labels.NewBuilder(lset)
	if honor {
		for _, l := range target.Labels() {
			if !lset.Has(l.Name) {
				lb.Set(l.Name, l.Value)
			}
		}
	} 
       ...忽略
}

当honor_labels为true时候,遍历本地标签target.Labels(),

  • 如果被采集端不存在该标签 !lset.Has(l.Name),则使用本地标签,如果存在则使用被采集端同名标签。
  • 如果被采集端存在该标签但是值为空时需要跟下lb.Set(l.Name, l.Value)的代码

https://github.com/prometheus/prometheus/blob/4b5e7d4984a135abd3729b9a2a5904336d35bc21/pkg/labels/labels.go#L361

// Set the name/value pair as a label.
func (b *Builder) Set(n, v string) *Builder {
	if v == "" {
		// Empty labels are the same as missing labels.
		return b.Del(n)
	}
	for i, a := range b.add {
		if a.Name == n {
			b.add[i].Value = v
			return b
		}
	}
	b.add = append(b.add, Label{Name: n, Value: v})

	return b
}

当值为空时候return b.Del(n)  该标签会被标记为删除后续操作会执行删除操作。

适用场景

综上honor_labels=true时

  1. 两端同时存在该标签且不为空时使用被采集端标签
  2. 两端同时存在该标签且被采集端为空时使用本地标签
  3. 被采集端不存在该标签时候使用本地标签