blob: 49ee973ac15e20116c4639521b0b2cad4ff6fe4a [file] [log] [blame]
Serge Bazanskif9a8dcd2024-07-31 14:46:06 +00001package supervisor
2
3import (
4 "fmt"
5
6 "github.com/prometheus/client_golang/prometheus"
7)
8
9// MetricsPrometheus is a Metrics implementation which exports the supervisor
10// metrics over some prometheus registry.
11//
12// This structure must be constructed with NewMetricsPrometheus.
13//
14// The metrics exported are:
15// - monogon_supervisor_dn_state_total
16// - monogon_superfisor_dn_state_transition_count
17type MetricsPrometheus struct {
18 exportedState *prometheus.GaugeVec
19 exportedEdge *prometheus.CounterVec
20 cachedState map[string]*NodeState
21}
22
23// NewMetricsPrometheus initializes Supervisor metrics in a prometheus registry
24// and return a Metrics instance to be used with WithMetrics.
25//
26// This should only be called once for a given registry.
27func NewMetricsPrometheus(registry *prometheus.Registry) (*MetricsPrometheus, error) {
28 res := &MetricsPrometheus{
29 exportedState: prometheus.NewGaugeVec(prometheus.GaugeOpts{
30 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"}),
35 exportedEdge: prometheus.NewCounterVec(prometheus.CounterOpts{
36 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 }
44 if err := registry.Register(res.exportedState); err != nil {
45 return nil, fmt.Errorf("when registering dn_state_total: %w", err)
46 }
47 if err := registry.Register(res.exportedEdge); err != nil {
48 return nil, fmt.Errorf("when registering dn_state_transition_count: %w", err)
49 }
50 return res, nil
51}
52
53func (m *MetricsPrometheus) exportState(dn string, state NodeState, value float64) {
54 m.exportedState.With(map[string]string{
55 "state": state.String(),
56 "dn": dn,
57 }).Set(value)
58}
59
60func (m *MetricsPrometheus) exportEdge(dn string, oldState, newState NodeState) {
61 m.exportedEdge.With(map[string]string{
62 "old_state": oldState.String(),
63 "new_state": newState.String(),
64 "dn": dn,
65 }).Inc()
66}
67
68func (m *MetricsPrometheus) NotifyNodeState(dn string, state NodeState) {
69 // Set all other exported states to zero, so that a given DN is only in a single
70 // state.
71 for _, st := range NodeStates {
72 if st == state {
73 continue
74 }
75 m.exportState(dn, st, 0.0)
76 }
77 // Export new state.
78 m.exportState(dn, state, 1.0)
79
80 // Export edge transition (assume previous state was Dead if this is the first
81 // time we see this DN).
82 previous := NodeStateDead
83 if m.cachedState[dn] != nil {
84 previous = *m.cachedState[dn]
85 }
86 m.exportEdge(dn, previous, state)
87 m.cachedState[dn] = &state
88}