[wip] initial providers commit
JP Robinson
7 years ago
0 | package provider | |
1 | ||
2 | import ( | |
3 | "errors" | |
4 | "net" | |
5 | "time" | |
6 | ||
7 | "github.com/go-kit/kit/log" | |
8 | "github.com/go-kit/kit/metrics" | |
9 | kitexp "github.com/go-kit/kit/metrics/expvar" | |
10 | "github.com/go-kit/kit/metrics/graphite" | |
11 | kitprom "github.com/go-kit/kit/metrics/prometheus" | |
12 | "github.com/go-kit/kit/metrics/statsd" | |
13 | "github.com/prometheus/client_golang/prometheus" | |
14 | ) | |
15 | ||
16 | // Provider represents a union set of constructors and lifecycle management | |
17 | // functions for each supported metrics backend. It should be used by those | |
18 | // who need to easily swap out implementations, e.g. dynamically, or at a | |
19 | // single point in an intermediating framework. | |
20 | type Provider interface { | |
21 | NewCounter(name string) metrics.Counter | |
22 | NewHistogram(name string, min, max int64, sigfigs int, quantiles ...int) (metrics.Histogram, error) | |
23 | NewGauge(name string) metrics.Gauge | |
24 | ||
25 | Stop() | |
26 | } | |
27 | ||
28 | // NewGraphiteProvider will return a Provider implementation that is a simple | |
29 | // wrapper around a graphite.Emitter. All metrics names will get prefixed | |
30 | // with the given value and data will be emitted once every interval. | |
31 | func NewGraphiteProvider(addr, net, prefix string, interval time.Duration, logger log.Logger) (Provider, error) { | |
32 | if addr == "" { | |
33 | return nil, errors.New("graphite server address is required") | |
34 | } | |
35 | if net == "" { | |
36 | net = "udp" | |
37 | } | |
38 | // nop logger for now :\ | |
39 | e := graphite.NewEmitter(addr, net, prefix, interval, logger) | |
40 | return &graphiteProvider{Emitter: e}, nil | |
41 | } | |
42 | ||
43 | type graphiteProvider struct { | |
44 | *graphite.Emitter | |
45 | } | |
46 | ||
47 | // NewStatsdProvider will create a UDP connection for each metric | |
48 | // with the given address. All metrics will use the given interval | |
49 | // and, if a prefix is provided, it will be included in metric names | |
50 | // with this format: | |
51 | // "prefix.name" | |
52 | func NewStatsdProvider(addr, prefix string, interval time.Duration, logger log.Logger) (Provider, error) { | |
53 | return &statsdProvider{addr: addr, prefix: prefix, interval: interval}, nil | |
54 | } | |
55 | ||
56 | type statsdProvider struct { | |
57 | addr string | |
58 | ||
59 | interval time.Duration | |
60 | prefix string | |
61 | ||
62 | logger log.Logger | |
63 | } | |
64 | ||
65 | func (s *statsdProvider) conn() (net.Conn, error) { | |
66 | return net.Dial("udp", s.addr) | |
67 | } | |
68 | ||
69 | func (s *statsdProvider) pref(name string) string { | |
70 | if len(s.prefix) > 0 { | |
71 | return s.prefix + "." + name | |
72 | } | |
73 | return name | |
74 | } | |
75 | ||
76 | func (s *statsdProvider) NewCounter(name string) metrics.Counter { | |
77 | conn, err := s.conn() | |
78 | if err != nil { | |
79 | s.logger.Log("during", "new counter", "err", err) | |
80 | return nil | |
81 | } | |
82 | return statsd.NewCounter(conn, s.pref(name), s.interval) | |
83 | } | |
84 | ||
85 | func (s *statsdProvider) NewHistogram(name string, min, max int64, sigfigs int, quantiles ...int) (metrics.Histogram, error) { | |
86 | conn, err := s.conn() | |
87 | if err != nil { | |
88 | return nil, err | |
89 | } | |
90 | return statsd.NewHistogram(conn, s.pref(name), s.interval), nil | |
91 | } | |
92 | ||
93 | func (s *statsdProvider) NewGauge(name string) metrics.Gauge { | |
94 | conn, err := s.conn() | |
95 | if err != nil { | |
96 | s.logger.Log("during", "new gauge", "err", err) | |
97 | return nil | |
98 | } | |
99 | return statsd.NewGauge(conn, s.pref(name), s.interval) | |
100 | } | |
101 | ||
102 | // Stop is a no-op (should we try to close the UDP connections here?) | |
103 | func (s *statsdProvider) Stop() {} | |
104 | ||
105 | // NewExpvarProvider is a very thin wrapper over the expvar package. | |
106 | // If a prefix is provided, it will be included in metric names with this | |
107 | // format: | |
108 | // "prefix.name" | |
109 | func NewExpvarProvider(prefix string) Provider { | |
110 | return &expvarProvider{prefix: prefix} | |
111 | } | |
112 | ||
113 | type expvarProvider struct { | |
114 | prefix string | |
115 | } | |
116 | ||
117 | func (e *expvarProvider) pref(name string) string { | |
118 | if len(e.prefix) > 0 { | |
119 | return e.prefix + "." + name | |
120 | } | |
121 | return name | |
122 | } | |
123 | ||
124 | func (e *expvarProvider) NewCounter(name string) metrics.Counter { | |
125 | return kitexp.NewCounter(e.pref(name)) | |
126 | } | |
127 | ||
128 | func (e *expvarProvider) NewHistogram(name string, min, max int64, sigfigs int, quantiles ...int) (metrics.Histogram, error) { | |
129 | return kitexp.NewHistogram(e.pref(name), min, max, sigfigs, quantiles...), nil | |
130 | } | |
131 | ||
132 | func (e *expvarProvider) NewGauge(name string) metrics.Gauge { | |
133 | return kitexp.NewGauge(e.pref(name)) | |
134 | } | |
135 | ||
136 | // Stop is a no-op. | |
137 | func (e *expvarProvider) Stop() {} | |
138 | ||
139 | type prometheusProvider struct { | |
140 | ns string | |
141 | } | |
142 | ||
143 | // NewPrometheusProvider will use the given namespace | |
144 | // for all metrics' Opts. | |
145 | func NewPrometheusProvider(namespace string) Provider { | |
146 | return &prometheusProvider{ns: namespace} | |
147 | } | |
148 | ||
149 | func (p *prometheusProvider) NewCounter(name string) metrics.Counter { | |
150 | opts := prometheus.CounterOpts{ | |
151 | Namespace: p.ns, | |
152 | Name: name, | |
153 | } | |
154 | return kitprom.NewCounter(opts, nil) | |
155 | } | |
156 | ||
157 | // NewHistogram ignores all NewHistogram parameters but `name`. | |
158 | func (p *prometheusProvider) NewHistogram(name string, min, max int64, sigfigs int, quantiles ...int) (metrics.Histogram, error) { | |
159 | opts := prometheus.HistogramOpts{ | |
160 | Namespace: p.ns, | |
161 | Name: name, | |
162 | } | |
163 | return kitprom.NewHistogram(opts, nil), nil | |
164 | } | |
165 | ||
166 | func (p *prometheusProvider) NewGauge(name string) metrics.Gauge { | |
167 | opts := prometheus.GaugeOpts{ | |
168 | Namespace: p.ns, | |
169 | Name: name, | |
170 | } | |
171 | return kitprom.NewGauge(opts, nil) | |
172 | } | |
173 | ||
174 | // Stop is a no-op | |
175 | func (p *prometheusProvider) Stop() {} |