Use base units, export cumulative values as _total counters, update docs, dashboards and rules.
73 lines
2.5 KiB
Go
73 lines
2.5 KiB
Go
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
|
|
}
|