-
Notifications
You must be signed in to change notification settings - Fork 0
/
metric.go
129 lines (113 loc) · 2.01 KB
/
metric.go
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
124
125
126
127
128
129
package stats
import (
"hash/fnv"
"math"
)
var statsMap = map[string]bool{
"count": true,
"sum": true,
"gauge": true,
"avg": true,
"min": true,
"max": true,
}
type metric struct {
Descr metricDescr
Value metricValue
Stats metricStats
Observed bool
}
func (m *metric) hash() uint64 {
h := fnv.New64a()
h.Write([]byte(m.Descr.Name))
for _, v := range m.Descr.Labels {
h.Write([]byte(v.Key))
h.Write([]byte(v.Value))
}
return h.Sum64()
}
func (m *metric) observe(value float64) {
// count calc
if m.Value.Count+1 == math.MaxFloat64 {
m.Value.Count = 0
}
m.Value.Count += 1
// sum calc
if m.Value.Sum+value == math.MaxFloat64 {
m.Value.Sum = 0
}
m.Value.Sum += value
// save gauge
m.Value.Gauge = value
// avg, min and max calc
if m.Observed {
if value < m.Value.Min {
m.Value.Min = value
}
if value > m.Value.Max {
m.Value.Max = value
}
m.Value.count2 += 1
// new average = old average * (n-1)/n + new value /n
m.Value.Avg = m.Value.Avg*(m.Value.count2-1)/m.Value.count2 + value/m.Value.count2
} else {
m.Value.Avg = value
m.Value.Min = value
m.Value.Max = value
m.Value.count2 = 1
m.Observed = true
}
}
// count, sum and gauge are not reset
func (m *metric) reset() {
m.Observed = false
m.Value.count2 = 0
m.Value.Avg = 0
m.Value.Min = 0
m.Value.Max = 0
}
type metricDescr struct {
Name string
Labels []metricLabel
}
type metricLabel struct {
Key string
Value string
}
type metricValue struct {
Count float64
Sum float64
Gauge float64
Avg float64
Min float64
Max float64
count2 float64 // count for moving average
}
type metricStats struct {
Count bool
Sum bool
Gauge bool
Avg bool
Min bool
Max bool
}
func stats(stats []string) metricStats {
s := metricStats{}
for _, v := range stats {
switch v {
case "sum":
s.Sum = true
case "count":
s.Count = true
case "gauge":
s.Gauge = true
case "avg":
s.Avg = true
case "min":
s.Min = true
case "max":
s.Max = true
}
}
return s
}