blob: 87f3104a46619229d6ffe199a0342f543b584bf7 [file] [log] [blame]
// Copyright The Monogon Project Authors.
// SPDX-License-Identifier: Apache-2.0
package supervisor
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
// MetricsPrometheus is a Metrics implementation which exports the supervisor
// metrics over some prometheus registry.
//
// This structure must be constructed with NewMetricsPrometheus.
//
// The metrics exported are:
// - monogon_supervisor_dn_state_total
// - monogon_superfisor_dn_state_transition_count
type MetricsPrometheus struct {
exportedState *prometheus.GaugeVec
exportedEdge *prometheus.CounterVec
cachedState map[string]*NodeState
}
// NewMetricsPrometheus initializes Supervisor metrics in a prometheus registry
// and return a Metrics instance to be used with WithMetrics.
//
// This should only be called once for a given registry.
func NewMetricsPrometheus(registry *prometheus.Registry) *MetricsPrometheus {
factory := promauto.With(registry)
res := &MetricsPrometheus{
exportedState: factory.NewGaugeVec(prometheus.GaugeOpts{
Namespace: "monogon",
Subsystem: "supervisor",
Name: "dn_state_total",
Help: "Total count of supervisor runnables, broken up by DN and state",
}, []string{"dn", "state"}),
exportedEdge: factory.NewCounterVec(prometheus.CounterOpts{
Namespace: "monogon",
Subsystem: "supervisor",
Name: "dn_state_transition_count",
Help: "Total count of supervisor runnable state transitions, broken up by DN and (old_state, new_state) tuple",
ConstLabels: nil,
}, []string{"dn", "old_state", "new_state"}),
cachedState: make(map[string]*NodeState),
}
return res
}
func (m *MetricsPrometheus) exportState(dn string, state NodeState, value float64) {
m.exportedState.With(map[string]string{
"state": state.String(),
"dn": dn,
}).Set(value)
}
func (m *MetricsPrometheus) exportEdge(dn string, oldState, newState NodeState) {
m.exportedEdge.With(map[string]string{
"old_state": oldState.String(),
"new_state": newState.String(),
"dn": dn,
}).Inc()
}
func (m *MetricsPrometheus) NotifyNodeState(dn string, state NodeState) {
// Set all other exported states to zero, so that a given DN is only in a single
// state.
for _, st := range NodeStates {
if st == state {
continue
}
m.exportState(dn, st, 0.0)
}
// Export new state.
m.exportState(dn, state, 1.0)
// Export edge transition (assume previous state was Dead if this is the first
// time we see this DN).
previous := NodeStateDead
if m.cachedState[dn] != nil {
previous = *m.cachedState[dn]
}
m.exportEdge(dn, previous, state)
m.cachedState[dn] = &state
}