-
Notifications
You must be signed in to change notification settings - Fork 5
/
resolver.go
114 lines (102 loc) · 3.4 KB
/
resolver.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
package pushgateway
import (
"fmt"
"strings"
"time"
"github.com/prometheus/client_golang/prometheus"
"go.k6.io/k6/metrics"
)
// CollectorResolver is an interface to resolve the various types of the [metrics.Metric]
// to the [prometheus.Collector].
// Respective [k6 metric type] are solved by following the [conversion rule] which
// the [xk6-output-prometheus-remote] extension applies.
//
// [k6 metric type]: https://k6.io/docs/using-k6/metrics/#metric-types
// [conversion rule]: https://k6.io/blog/k6-loves-prometheus/#mapping-k6-metrics-types
// [xk6-output-prometheus-remote]: https://github.com/grafana/xk6-output-prometheus-remote
type CollectorResolver func(sample metrics.Sample, labels prometheus.Labels, prefix string) []prometheus.Collector
// CreateResolveer is a factory method to create the [ColloectorResolver] implementation
// corresponding to the given [k6 metric type].
//
// Example use case:
//
// collectorResolver := collector_resolver.CreateResolver(sample.Metric.Type)
// collectors := collectorResolver(sample.Metric, time.Now())
//
// [k6 metric type]: https://k6.io/docs/using-k6/metrics/#metric-types
func CreateResolver(t metrics.MetricType) CollectorResolver {
var resolver CollectorResolver
switch t {
case metrics.Counter:
resolver = resolveCounter
case metrics.Gauge:
resolver = resolveGauge
case metrics.Rate:
resolver = resolveRate
case metrics.Trend:
resolver = resolveTrend
}
return resolver
}
func resolveCounter(sample metrics.Sample, labels prometheus.Labels, prefix string) []prometheus.Collector {
counter := prometheus.NewCounterFunc(
prometheus.CounterOpts{
Name: getPrefixedName(prefix, sample.Metric.Name),
ConstLabels: labels,
},
func() float64 {
counterSink := sample.Metric.Sink.(*metrics.CounterSink)
return sample.Metric.Sink.Format(sample.GetTime().Sub(counterSink.First))["rate"]
},
)
return []prometheus.Collector{counter}
}
func resolveGauge(sample metrics.Sample, labels prometheus.Labels, prefix string) []prometheus.Collector {
gauge := prometheus.NewGaugeFunc(
prometheus.GaugeOpts{
Name: getPrefixedName(prefix, sample.Metric.Name),
ConstLabels: labels,
},
func() float64 {
return sample.Value
},
)
return []prometheus.Collector{gauge}
}
func resolveRate(sample metrics.Sample, labels prometheus.Labels, prefix string) []prometheus.Collector {
gauge := prometheus.NewGaugeFunc(
prometheus.GaugeOpts{
Name: getPrefixedName(prefix, sample.Metric.Name),
ConstLabels: labels,
},
func() float64 {
return sample.Value
},
)
return []prometheus.Collector{gauge}
}
func resolveTrend(sample metrics.Sample, labels prometheus.Labels, prefix string) []prometheus.Collector {
sink := sample.Metric.Sink.Format(time.Duration(0))
collectors := make([]prometheus.Collector, 0)
for k, v := range sink {
// Remove "(" and ")" from the name of prometheus collector
// Becuase these are not acceptable as collector name.
suffix := strings.ReplaceAll(strings.ReplaceAll(k, "(", ""), ")", "")
name := fmt.Sprintf("%s_%s", sample.Metric.Name, suffix)
gauge := prometheus.NewGauge(
prometheus.GaugeOpts{
Name: getPrefixedName(prefix, name),
ConstLabels: labels,
},
)
gauge.Set(v)
collectors = append(collectors, gauge)
}
return collectors
}
func getPrefixedName(prefix string, name string) string {
if prefix == "" {
return name
}
return fmt.Sprintf("%s_%s", prefix, name)
}