github.com/prometheus/prometheus/pkg/labels
时间序列由一组 Label 唯一标识。labels包中是对 Label 和 Labels 对象的定义和方法。还有一个构建 Labels 的 Builder 对象。
一个标签(Label)就是一个字符串键值对
// Label is a key/value pair of strings.
type Label struct {
Name, Value string
Labels 是 Label 的有序列表,实现了 sort 接口。
func (ls Labels) Len() int { return len(ls) }
func (ls Labels) Swap(i, j int) { ls[i], ls[j] = ls[j], ls[i] }
func (ls Labels) Less(i, j int) bool { return ls[i].Name < ls[j].Name }
标签名是键为"name"的值
// Well-known label names used by Prometheus components.
const (
MetricName = "__name__"
AlertName = "alertname"
BucketLabel = "le"
InstanceName = "instance"
labelSep = '\xfe'
)
习得
- 高效哈希算法: github.com/cespare/xxhash/v2
- a、b 两个有序列表,处理 a 中不存在于 b 的元素
/ HashWithoutLabels returns a hash value for all labels except those matching
// the provided names.
// 'names' have to be sorted in ascending order.
func (ls Labels) HashWithoutLabels(b []byte, names ...string) (uint64, []byte) {
b = b[:0]
j := 0
for i := range ls {
for j < len(names) && names[j] < ls[i].Name {
j++
}
if ls[i].Name == MetricName || (j < len(names) && ls[i].Name == names[j]) {
continue
}
b = append(b, ls[i].Name...)
b = append(b, seps[0])
b = append(b, ls[i].Value...)
b = append(b, seps[0])
}
return xxhash.Sum64(b), b
}
- 在必要的时候才做额外的工作,对于需要做额外工作概率较小的情况可以提高性能,这个算法有个小问题,els 的 cap 是 ls-1 实际 len 可能小于这个值,cap 可以做收缩。Prometheus 鉴于标签基数不宜太大,收缩只会小幅度节省空间但要多耗一点时间,所以没有必要收缩吧。
// WithoutEmpty returns the labelset without empty labels.
// May return the same labelset.
func (ls Labels) WithoutEmpty() Labels {
for _, v := range ls {
if v.Value != "" {
continue
}
// Do not copy the slice until it's necessary.
els := make(Labels, 0, len(ls)-1)
for _, v := range ls {
if v.Value != "" {
els = append(els, v)
}
}
return els
}
return ls
}