13 | 13 |
"github.com/go-kit/kit/metrics"
|
14 | 14 |
"github.com/go-kit/kit/metrics/generic"
|
15 | 15 |
"github.com/go-kit/kit/metrics/internal/lv"
|
|
16 |
"strconv"
|
16 | 17 |
)
|
17 | 18 |
|
18 | 19 |
const (
|
|
37 | 38 |
counters *lv.Space
|
38 | 39 |
gauges *lv.Space
|
39 | 40 |
histograms *lv.Space
|
40 | |
percentiles Percentiles
|
|
41 |
percentiles []float64 // percentiles to track
|
41 | 42 |
logger log.Logger
|
42 | 43 |
numConcurrentRequests int
|
43 | 44 |
}
|
|
56 | 57 |
}
|
57 | 58 |
}
|
58 | 59 |
|
59 | |
func WithPercentiles(p Percentiles) option {
|
|
60 |
// WithPercentiles registers the percentiles to track, overriding the
|
|
61 |
// existing/default values.
|
|
62 |
// Reason is that Cloudwatch makes you pay per metric, so you can save half the money
|
|
63 |
// by only using 2 metrics instead of the default 4.
|
|
64 |
func WithPercentiles(percentiles ...float64) option {
|
60 | 65 |
return func(c *CloudWatch) {
|
61 | |
validated := Percentiles{}
|
62 | |
for _, entry := range p {
|
63 | |
if entry.f < 0 || entry.f > 1 {
|
64 | |
continue // illegal entry
|
|
66 |
c.percentiles = make([]float64, 0, len(percentiles))
|
|
67 |
for _, p := range percentiles {
|
|
68 |
if p < 0 || p > 1 {
|
|
69 |
continue // illegal entry; ignore
|
65 | 70 |
}
|
66 | |
validated = append(validated, entry)
|
67 | |
}
|
68 | |
c.percentiles = validated
|
|
71 |
c.percentiles = append(c.percentiles, p)
|
|
72 |
}
|
69 | 73 |
}
|
70 | 74 |
}
|
71 | 75 |
|
|
92 | 96 |
histograms: lv.NewSpace(),
|
93 | 97 |
numConcurrentRequests: 10,
|
94 | 98 |
logger: log.NewLogfmtLogger(os.Stderr),
|
95 | |
percentiles: Percentiles{
|
96 | |
{"50", 0.50},
|
97 | |
{"90", 0.90},
|
98 | |
{"95", 0.95},
|
99 | |
{"99", 0.99},
|
100 | |
},
|
|
99 |
percentiles: []float64{0.50, 0.90, 0.95, 0.99},
|
101 | 100 |
}
|
102 | 101 |
|
103 | 102 |
for _, optFunc := range options {
|
|
178 | 177 |
return true
|
179 | 178 |
})
|
180 | 179 |
|
|
180 |
// format a [0,1]-float value to a percentile value, with minimum nr of decimals
|
|
181 |
// 0.90 -> "90"
|
|
182 |
// 0.95 -> "95"
|
|
183 |
// 0.999 -> "99.9"
|
|
184 |
formatPerc := func(p float64) string {
|
|
185 |
return strconv.FormatFloat(p*100, 'f', -1, 64)
|
|
186 |
}
|
|
187 |
|
181 | 188 |
cw.histograms.Reset().Walk(func(name string, lvs lv.LabelValues, values []float64) bool {
|
182 | 189 |
histogram := generic.NewHistogram(name, 50)
|
183 | 190 |
|
|
185 | 192 |
histogram.Observe(v)
|
186 | 193 |
}
|
187 | 194 |
|
188 | |
for _, p := range cw.percentiles {
|
189 | |
value := histogram.Quantile(p.f)
|
|
195 |
for _, perc := range cw.percentiles {
|
|
196 |
value := histogram.Quantile(perc)
|
190 | 197 |
datums = append(datums, &cloudwatch.MetricDatum{
|
191 | |
MetricName: aws.String(fmt.Sprintf("%s_%s", name, p.s)),
|
|
198 |
MetricName: aws.String(fmt.Sprintf("%s_%s", name, formatPerc(perc))),
|
192 | 199 |
Dimensions: makeDimensions(lvs...),
|
193 | 200 |
Value: aws.Float64(value),
|
194 | 201 |
Timestamp: aws.Time(now),
|