mirror of
https://github.com/grafana/grafana.git
synced 2024-11-28 19:54:10 -06:00
87 lines
2.2 KiB
Go
87 lines
2.2 KiB
Go
package metricutil
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
)
|
|
|
|
// SanitizeLabelName removes all invalid chars from the label name.
|
|
// If the label name is empty or contains only invalid chars, it
|
|
// will return an error.
|
|
func SanitizeLabelName(name string) (string, error) {
|
|
if len(name) == 0 {
|
|
return "", errors.New("label name cannot be empty")
|
|
}
|
|
|
|
out := strings.Builder{}
|
|
for i, b := range name {
|
|
if (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0) {
|
|
out.WriteRune(b)
|
|
} else if b == ' ' {
|
|
out.WriteRune('_')
|
|
}
|
|
}
|
|
|
|
if out.Len() == 0 {
|
|
return "", fmt.Errorf("label name only contains invalid chars: %q", name)
|
|
}
|
|
|
|
return out.String(), nil
|
|
}
|
|
|
|
// NewCounterStartingAtZero initializes a new Prometheus counter with an initial
|
|
// observation of zero. Used for to guarantee the existence of the specific metric.
|
|
func NewCounterStartingAtZero(opts prometheus.CounterOpts) prometheus.Counter {
|
|
counter := prometheus.NewCounter(opts)
|
|
counter.Add(0)
|
|
return counter
|
|
}
|
|
|
|
// NewCounterVecStartingAtZero initializes a new Prometheus counter with an initial
|
|
// observation of zero for every possible value of each label. Used for the sake of
|
|
// consistency among all the possible labels and values.
|
|
func NewCounterVecStartingAtZero(opts prometheus.CounterOpts, labels []string, labelValues map[string][]string) *prometheus.CounterVec {
|
|
counter := prometheus.NewCounterVec(opts, labels)
|
|
|
|
for _, ls := range buildLabelSets(labels, labelValues) {
|
|
counter.With(ls).Add(0)
|
|
}
|
|
|
|
return counter
|
|
}
|
|
|
|
func buildLabelSets(labels []string, labelValues map[string][]string) []prometheus.Labels {
|
|
var labelSets []prometheus.Labels
|
|
|
|
var n func(i int, ls prometheus.Labels)
|
|
n = func(i int, ls prometheus.Labels) {
|
|
if i == len(labels) {
|
|
labelSets = append(labelSets, ls)
|
|
return
|
|
}
|
|
|
|
label := labels[i]
|
|
values := labelValues[label]
|
|
|
|
for _, v := range values {
|
|
lsCopy := copyLabelSet(ls)
|
|
lsCopy[label] = v
|
|
n(i+1, lsCopy)
|
|
}
|
|
}
|
|
|
|
n(0, prometheus.Labels{})
|
|
return labelSets
|
|
}
|
|
|
|
func copyLabelSet(ls prometheus.Labels) prometheus.Labels {
|
|
newLs := make(prometheus.Labels, len(ls))
|
|
for l, v := range ls {
|
|
newLs[l] = v
|
|
}
|
|
return newLs
|
|
}
|