Align metric names with Prometheus naming conventions
Use base units, export cumulative values as _total counters, update docs, dashboards and rules.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/testutil/promlint"
|
||||
)
|
||||
|
||||
// Verifies that all exported PVE metrics follow the Prometheus naming conventions
|
||||
// (base units, '_total' suffix on counters, '_info' suffix on info metrics, ...)
|
||||
// so that tools such as promtool or Grafana do not report naming problems.
|
||||
func TestPveMetricNamesFollowPrometheusConventions(t *testing.T) {
|
||||
registry := prometheus.NewRegistry()
|
||||
|
||||
// Collectors register their metrics on the default registerer, so it is
|
||||
// temporarily replaced by a dedicated registry.
|
||||
defaultRegisterer := prometheus.DefaultRegisterer
|
||||
prometheus.DefaultRegisterer = registry
|
||||
defer func() { prometheus.DefaultRegisterer = defaultRegisterer }()
|
||||
|
||||
// Collector constructors only create metrics, the API client is used during
|
||||
// collection only, so a nil client is enough here.
|
||||
ttlRegistry := NewTTLRegistry()
|
||||
NewPveClusterStateCollector(nil, ttlRegistry)
|
||||
NewPveNodeStatusCollector(nil, ttlRegistry)
|
||||
NewPveSubscriptionCollector(nil, ttlRegistry)
|
||||
NewPveNodeDiskCollector(nil, ttlRegistry)
|
||||
NewPveNodeZfsCollector(nil, ttlRegistry)
|
||||
NewPveSdnCollector(nil, ttlRegistry)
|
||||
NewPveStorageCollector(nil, ttlRegistry)
|
||||
NewPveContainerCollector(nil, ttlRegistry)
|
||||
NewPveVirtualMachineCollector(nil, ttlRegistry)
|
||||
|
||||
// Metric vectors are exported only once they hold a label set.
|
||||
for _, metric := range ttlRegistry.metrics {
|
||||
switch m := metric.(type) {
|
||||
case *TTLGaugeVec:
|
||||
m.With(emptyLabels(m.labelNames)).Set(0)
|
||||
case *TTLCounterVec:
|
||||
m.With(emptyLabels(m.labelNames)).Set(0)
|
||||
default:
|
||||
t.Fatalf("Unknown TTL metric type %T.", metric)
|
||||
}
|
||||
}
|
||||
|
||||
families, err := registry.Gather()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to gather metrics. Error: %s.", err)
|
||||
}
|
||||
if len(families) != len(ttlRegistry.metrics) {
|
||||
t.Fatalf("Gathered %d metric families but %d metrics are registered.", len(families), len(ttlRegistry.metrics))
|
||||
}
|
||||
|
||||
problems, err := promlint.NewWithMetricFamilies(families).Lint()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to lint metrics. Error: %s.", err)
|
||||
}
|
||||
|
||||
for _, problem := range problems {
|
||||
t.Errorf("Metric '%s' violates the Prometheus naming conventions: %s.", problem.Metric, problem.Text)
|
||||
}
|
||||
}
|
||||
|
||||
// emptyLabels builds a label set with all given label names set to an empty value.
|
||||
func emptyLabels(labelNames []string) prometheus.Labels {
|
||||
labels := prometheus.Labels{}
|
||||
for _, name := range labelNames {
|
||||
labels[name] = ""
|
||||
}
|
||||
return labels
|
||||
}
|
||||
Reference in New Issue
Block a user