blob: 9ae18a8675ea53748b967c6f70dc89071a382ebd [file] [log] [blame]
Serge Bazanskif9a8dcd2024-07-31 14:46:06 +00001package supervisor
2
3import (
Serge Bazanskif9a8dcd2024-07-31 14:46:06 +00004 "github.com/prometheus/client_golang/prometheus"
Tim Windelschmidt3c6183f2024-12-16 02:42:21 +01005 "github.com/prometheus/client_golang/prometheus/promauto"
Serge Bazanskif9a8dcd2024-07-31 14:46:06 +00006)
7
8// MetricsPrometheus is a Metrics implementation which exports the supervisor
9// metrics over some prometheus registry.
10//
11// This structure must be constructed with NewMetricsPrometheus.
12//
13// The metrics exported are:
14// - monogon_supervisor_dn_state_total
15// - monogon_superfisor_dn_state_transition_count
16type MetricsPrometheus struct {
17 exportedState *prometheus.GaugeVec
18 exportedEdge *prometheus.CounterVec
19 cachedState map[string]*NodeState
20}
21
22// NewMetricsPrometheus initializes Supervisor metrics in a prometheus registry
23// and return a Metrics instance to be used with WithMetrics.
24//
25// This should only be called once for a given registry.
Tim Windelschmidt3c6183f2024-12-16 02:42:21 +010026func NewMetricsPrometheus(registry *prometheus.Registry) *MetricsPrometheus {
27 factory := promauto.With(registry)
Serge Bazanskif9a8dcd2024-07-31 14:46:06 +000028 res := &MetricsPrometheus{
Tim Windelschmidt3c6183f2024-12-16 02:42:21 +010029 exportedState: factory.NewGaugeVec(prometheus.GaugeOpts{
Serge Bazanskif9a8dcd2024-07-31 14:46:06 +000030 Namespace: "monogon",
31 Subsystem: "supervisor",
32 Name: "dn_state_total",
33 Help: "Total count of supervisor runnables, broken up by DN and state",
34 }, []string{"dn", "state"}),
Tim Windelschmidt3c6183f2024-12-16 02:42:21 +010035 exportedEdge: factory.NewCounterVec(prometheus.CounterOpts{
Serge Bazanskif9a8dcd2024-07-31 14:46:06 +000036 Namespace: "monogon",
37 Subsystem: "supervisor",
38 Name: "dn_state_transition_count",
39 Help: "Total count of supervisor runnable state transitions, broken up by DN and (old_state, new_state) tuple",
40 ConstLabels: nil,
41 }, []string{"dn", "old_state", "new_state"}),
42 cachedState: make(map[string]*NodeState),
43 }
Tim Windelschmidt3c6183f2024-12-16 02:42:21 +010044 return res
Serge Bazanskif9a8dcd2024-07-31 14:46:06 +000045}
46
47func (m *MetricsPrometheus) exportState(dn string, state NodeState, value float64) {
48 m.exportedState.With(map[string]string{
49 "state": state.String(),
50 "dn": dn,
51 }).Set(value)
52}
53
54func (m *MetricsPrometheus) exportEdge(dn string, oldState, newState NodeState) {
55 m.exportedEdge.With(map[string]string{
56 "old_state": oldState.String(),
57 "new_state": newState.String(),
58 "dn": dn,
59 }).Inc()
60}
61
62func (m *MetricsPrometheus) NotifyNodeState(dn string, state NodeState) {
63 // Set all other exported states to zero, so that a given DN is only in a single
64 // state.
65 for _, st := range NodeStates {
66 if st == state {
67 continue
68 }
69 m.exportState(dn, st, 0.0)
70 }
71 // Export new state.
72 m.exportState(dn, state, 1.0)
73
74 // Export edge transition (assume previous state was Dead if this is the first
75 // time we see this DN).
76 previous := NodeStateDead
77 if m.cachedState[dn] != nil {
78 previous = *m.cachedState[dn]
79 }
80 m.exportEdge(dn, previous, state)
81 m.cachedState[dn] = &state
82}