1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
12 "github.com/prometheus/client_golang/prometheus"
13 "github.com/prometheus/client_golang/prometheus/promhttp"
16 type observer interface{ Observe(float64) }
17 type setter interface{ Set(float64) }
20 reg *prometheus.Registry
21 statsGauges map[string]setter
22 observers map[string]observer
27 func newMetrics() *metrics {
29 reg: prometheus.NewRegistry(),
30 statsGauges: map[string]setter{},
31 observers: map[string]observer{},
35 func (m *metrics) DurationObserver(name, help string) observer {
38 if obs, ok := m.observers[name]; ok {
41 summary := prometheus.NewSummary(prometheus.SummaryOpts{
44 Subsystem: "keepbalance",
47 m.reg.MustRegister(summary)
48 m.observers[name] = summary
52 // UpdateStats updates prometheus metrics using the given
53 // balancerStats. It creates and registers the needed gauges on its
55 func (m *metrics) UpdateStats(s balancerStats) {
60 s2g := map[string]gauge{
61 "total": {s.current, "current backend storage usage"},
62 "garbage": {s.garbage, "garbage (unreferenced, old)"},
63 "transient": {s.unref, "transient (unreferenced, new)"},
64 "overreplicated": {s.overrep, "overreplicated"},
65 "underreplicated": {s.underrep, "underreplicated"},
66 "lost": {s.lost, "lost"},
67 "dedup_byte_ratio": {s.dedupByteRatio(), "deduplication ratio, bytes referenced / bytes stored"},
68 "dedup_block_ratio": {s.dedupBlockRatio(), "deduplication ratio, blocks referenced / blocks stored"},
70 m.setupOnce.Do(func() {
71 // Register gauge(s) for each balancerStats field.
72 addGauge := func(name, help string) {
73 g := prometheus.NewGauge(prometheus.GaugeOpts{
80 m.statsGauges[name] = g
82 for name, gauge := range s2g {
83 switch gauge.Value.(type) {
85 for _, sub := range []string{"blocks", "bytes", "replicas"} {
86 addGauge(name+"_"+sub, sub+" of "+gauge.Help)
88 case int, int64, float64:
89 addGauge(name, gauge.Help)
91 panic(fmt.Sprintf("bad gauge type %T", gauge.Value))
95 // Set gauges to values from s.
96 for name, gauge := range s2g {
97 switch val := gauge.Value.(type) {
99 m.statsGauges[name+"_blocks"].Set(float64(val.blocks))
100 m.statsGauges[name+"_bytes"].Set(float64(val.bytes))
101 m.statsGauges[name+"_replicas"].Set(float64(val.replicas))
103 m.statsGauges[name].Set(float64(val))
105 m.statsGauges[name].Set(float64(val))
107 m.statsGauges[name].Set(float64(val))
109 panic(fmt.Sprintf("bad gauge type %T", gauge.Value))
114 func (m *metrics) Handler(log promhttp.Logger) http.Handler {
115 return promhttp.HandlerFor(m.reg, promhttp.HandlerOpts{