forked from lablabs/cloudflare-exporter
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmetrics.go
More file actions
123 lines (101 loc) · 2.5 KB
/
metrics.go
File metadata and controls
123 lines (101 loc) · 2.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package main
import (
"strings"
"sync"
"time"
"github.com/prometheus/client_golang/prometheus"
)
const joinChar = "|"
const maxAge = 1 * time.Hour
type trackedMetric interface {
MustRegisterWith(prometheus.Registerer)
}
type reportableMetrics []*metricTracker
var registeredMetrics = reportableMetrics{}
func (rm reportableMetrics) Report(gauge prometheus.Gauge) {
total := 0
for _, m := range rm {
total += len(m.expirations)
}
gauge.Set(float64(total))
}
func register(m *metricTracker) {
registeredMetrics = append(registeredMetrics, m)
}
type metricTracker struct {
sync.Mutex
registered bool
collector prometheus.Collector
del func(...string) bool
expirations map[string]time.Time
}
func newMetricTracker(collector prometheus.Collector, del func(...string) bool) *metricTracker {
mt := &metricTracker{
registered: false,
collector: collector,
del: del,
expirations: map[string]time.Time{},
}
register(mt)
return mt
}
func (mt *metricTracker) update(labels []string, fn func()) {
if !mt.registered {
return
}
mt.Lock()
mt.expirations[strings.Join(labels, joinChar)] = time.Now().Add(maxAge)
defer mt.Unlock()
fn()
}
func (mt *metricTracker) MustRegisterWith(registry prometheus.Registerer) {
mt.registered = true
registry.MustRegister(mt)
}
func (mt *metricTracker) Describe(ch chan<- *prometheus.Desc) {
mt.collector.Describe(ch)
}
func (mt *metricTracker) Collect(ch chan<- prometheus.Metric) {
mt.Lock()
defer mt.Unlock()
now := time.Now()
for k, v := range mt.expirations {
if v.Before(now) {
delete(mt.expirations, k)
if mt.del(strings.Split(k, joinChar)...) {
expiredMetrics.Inc()
}
}
}
mt.collector.Collect(ch)
}
type trackedGauge struct {
*metricTracker
gauge *prometheus.GaugeVec
}
func NewTrackedGauge(gauge *prometheus.GaugeVec) *trackedGauge {
return &trackedGauge{
metricTracker: newMetricTracker(gauge, gauge.DeleteLabelValues),
gauge: gauge,
}
}
func (tg *trackedGauge) Set(val float64, labels ...string) {
tg.update(labels, func() {
tg.gauge.WithLabelValues(labels...).Set(val)
})
}
type trackedCounter struct {
*metricTracker
counter *prometheus.CounterVec
}
func NewTrackedCounter(counter *prometheus.CounterVec) *trackedCounter {
return &trackedCounter{
metricTracker: newMetricTracker(counter, counter.DeleteLabelValues),
counter: counter,
}
}
func (tc *trackedCounter) Add(val float64, labels ...string) {
tc.update(labels, func() {
tc.counter.WithLabelValues(labels...).Add(val)
})
}