/
exporter.go
141 lines (123 loc) · 3.79 KB
/
exporter.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
130
131
132
133
134
135
136
137
138
139
140
141
package go_metrics
import (
"github.com/rcrowley/go-metrics"
"github.com/signalfx/golib/v3/datapoint"
"github.com/signalfx/golib/v3/sfxclient"
)
var defaultQuantiles = []float64{.25, .5, .9, .99}
type memoryInner struct {
name string
dims map[string]string
}
// Harvester provides a way to extract dimensions from a metric name
type Harvester func(name string) (bool, string, map[string]string)
// Exporter wraps the go-metrics registry as an sfxclient.Collector
type Exporter struct {
r metrics.Registry
lastSize int
dims map[string]string
// this will be a leak if you are constantly adding and removing topics, my use case doesn't do that but if yours does...
memory map[string]*memoryInner
zHarvesters []Harvester
}
func (e *Exporter) metricToDatapoints(dps []*datapoint.Datapoint, name string, i interface{}) []*datapoint.Datapoint {
metricName, dims := e.harvestMetricInfo(name)
switch metric := i.(type) {
case metrics.Counter:
dps = append(dps, sfxclient.Cumulative(metricName, dims, metric.Count()))
case metrics.Gauge:
dps = append(dps, sfxclient.Gauge(metricName, dims, metric.Value()))
case metrics.GaugeFloat64:
dps = append(dps, sfxclient.GaugeF(metricName, dims, metric.Value()))
case metrics.Histogram:
h := metric.Snapshot()
dps = e.harvestHistoTypeThing(dps, metricName, h, dims)
case metrics.Meter:
m := metric.Snapshot()
dps = append(dps,
sfxclient.Cumulative(metricName+".count", e.dims, m.Count()),
sfxclient.GaugeF(metricName+".1m", dims, m.Rate1()),
sfxclient.GaugeF(metricName+".5m", dims, m.Rate5()),
sfxclient.GaugeF(metricName+".15m", dims, m.Rate15()),
sfxclient.GaugeF(metricName+".meanRate", dims, m.RateMean()),
)
case metrics.Timer:
t := metric.Snapshot()
dps = e.harvestHistoTypeThing(dps, metricName, t, dims)
}
return dps
}
type histoTypeThing interface {
Count() int64
Max() int64
Mean() float64
Min() int64
Percentile(float64) float64
Percentiles([]float64) []float64
StdDev() float64
Sum() int64
Variance() float64
}
func (e *Exporter) harvestMetricInfo(name string) (ret string, retm map[string]string) {
ret = name
retm = e.dims
if len(e.zHarvesters) > 0 {
var mem *memoryInner
var ok, broken bool
if mem, ok = e.memory[name]; !ok {
for _, h := range e.zHarvesters {
if ok, s, m := h(name); ok {
mem = &memoryInner{
name: s,
dims: datapoint.AddMaps(m, e.dims),
}
broken = true
break
}
}
if !broken {
mem = &memoryInner{
name: name,
dims: e.dims,
}
}
e.memory[name] = mem
}
ret = mem.name
retm = mem.dims
}
return ret, retm
}
func (e *Exporter) harvestHistoTypeThing(dps []*datapoint.Datapoint, metric string, h histoTypeThing, dims map[string]string) []*datapoint.Datapoint {
ps := h.Percentiles(defaultQuantiles)
dps = append(dps,
sfxclient.Cumulative(metric+".count", dims, h.Count()),
sfxclient.Gauge(metric+".min", dims, h.Min()),
sfxclient.Gauge(metric+".max", dims, h.Max()),
sfxclient.GaugeF(metric+".mean", dims, h.Mean()),
sfxclient.GaugeF(metric+".stdDev", dims, h.StdDev()),
sfxclient.GaugeF(metric+".p25", dims, ps[0]),
sfxclient.GaugeF(metric+".median", dims, ps[1]),
sfxclient.GaugeF(metric+".p90", dims, ps[2]),
sfxclient.GaugeF(metric+".p99", dims, ps[3]),
)
return dps
}
// Datapoints implements sfxclient.Collector
func (e *Exporter) Datapoints() []*datapoint.Datapoint {
dps := make([]*datapoint.Datapoint, 0, e.lastSize)
e.r.Each(func(name string, i interface{}) {
dps = e.metricToDatapoints(dps, name, i)
})
e.lastSize = len(dps)
return dps
}
// New returns a new &Exporter
func New(r metrics.Registry, dims map[string]string, zHarvesters ...Harvester) *Exporter {
return &Exporter{
r: r,
dims: dims,
zHarvesters: zHarvesters,
memory: make(map[string]*memoryInner),
}
}