The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/infra/metrics/metricutil/utils.go

86 lines
2.2 KiB

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
}