cloudflare/cloudflared

Public

mirrored from https://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2019.3.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

origin/metrics.go

444lines · modecode

1package origin
2
3import (
4 "sync"
5 "time"
6
7 "github.com/cloudflare/cloudflared/h2mux"
8
9 "github.com/prometheus/client_golang/prometheus"
10)
11
12type muxerMetrics struct {
13 rtt *prometheus.GaugeVec
14 rttMin *prometheus.GaugeVec
15 rttMax *prometheus.GaugeVec
16 receiveWindowAve *prometheus.GaugeVec
17 sendWindowAve *prometheus.GaugeVec
18 receiveWindowMin *prometheus.GaugeVec
19 receiveWindowMax *prometheus.GaugeVec
20 sendWindowMin *prometheus.GaugeVec
21 sendWindowMax *prometheus.GaugeVec
22 inBoundRateCurr *prometheus.GaugeVec
23 inBoundRateMin *prometheus.GaugeVec
24 inBoundRateMax *prometheus.GaugeVec
25 outBoundRateCurr *prometheus.GaugeVec
26 outBoundRateMin *prometheus.GaugeVec
27 outBoundRateMax *prometheus.GaugeVec
28 compBytesBefore *prometheus.GaugeVec
29 compBytesAfter *prometheus.GaugeVec
30 compRateAve *prometheus.GaugeVec
31}
32
33type TunnelMetrics struct {
34 haConnections prometheus.Gauge
35 totalRequests prometheus.Counter
36 requestsPerTunnel *prometheus.CounterVec
37 // concurrentRequestsLock is a mutex for concurrentRequests and maxConcurrentRequests
38 concurrentRequestsLock sync.Mutex
39 concurrentRequestsPerTunnel *prometheus.GaugeVec
40 // concurrentRequests records count of concurrent requests for each tunnel
41 concurrentRequests map[string]uint64
42 maxConcurrentRequestsPerTunnel *prometheus.GaugeVec
43 // concurrentRequests records max count of concurrent requests for each tunnel
44 maxConcurrentRequests map[string]uint64
45 timerRetries prometheus.Gauge
46 responseByCode *prometheus.CounterVec
47 responseCodePerTunnel *prometheus.CounterVec
48 serverLocations *prometheus.GaugeVec
49 // locationLock is a mutex for oldServerLocations
50 locationLock sync.Mutex
51 // oldServerLocations stores the last server the tunnel was connected to
52 oldServerLocations map[string]string
53
54 regSuccess prometheus.Counter
55 regFail *prometheus.CounterVec
56
57 muxerMetrics *muxerMetrics
58 tunnelsHA tunnelsForHA
59}
60
61func newMuxerMetrics() *muxerMetrics {
62 rtt := prometheus.NewGaugeVec(
63 prometheus.GaugeOpts{
64 Name: "rtt",
65 Help: "Round-trip time in millisecond",
66 },
67 []string{"connection_id"},
68 )
69 prometheus.MustRegister(rtt)
70
71 rttMin := prometheus.NewGaugeVec(
72 prometheus.GaugeOpts{
73 Name: "rtt_min",
74 Help: "Shortest round-trip time in millisecond",
75 },
76 []string{"connection_id"},
77 )
78 prometheus.MustRegister(rttMin)
79
80 rttMax := prometheus.NewGaugeVec(
81 prometheus.GaugeOpts{
82 Name: "rtt_max",
83 Help: "Longest round-trip time in millisecond",
84 },
85 []string{"connection_id"},
86 )
87 prometheus.MustRegister(rttMax)
88
89 receiveWindowAve := prometheus.NewGaugeVec(
90 prometheus.GaugeOpts{
91 Name: "receive_window_ave",
92 Help: "Average receive window size in bytes",
93 },
94 []string{"connection_id"},
95 )
96 prometheus.MustRegister(receiveWindowAve)
97
98 sendWindowAve := prometheus.NewGaugeVec(
99 prometheus.GaugeOpts{
100 Name: "send_window_ave",
101 Help: "Average send window size in bytes",
102 },
103 []string{"connection_id"},
104 )
105 prometheus.MustRegister(sendWindowAve)
106
107 receiveWindowMin := prometheus.NewGaugeVec(
108 prometheus.GaugeOpts{
109 Name: "receive_window_min",
110 Help: "Smallest receive window size in bytes",
111 },
112 []string{"connection_id"},
113 )
114 prometheus.MustRegister(receiveWindowMin)
115
116 receiveWindowMax := prometheus.NewGaugeVec(
117 prometheus.GaugeOpts{
118 Name: "receive_window_max",
119 Help: "Largest receive window size in bytes",
120 },
121 []string{"connection_id"},
122 )
123 prometheus.MustRegister(receiveWindowMax)
124
125 sendWindowMin := prometheus.NewGaugeVec(
126 prometheus.GaugeOpts{
127 Name: "send_window_min",
128 Help: "Smallest send window size in bytes",
129 },
130 []string{"connection_id"},
131 )
132 prometheus.MustRegister(sendWindowMin)
133
134 sendWindowMax := prometheus.NewGaugeVec(
135 prometheus.GaugeOpts{
136 Name: "send_window_max",
137 Help: "Largest send window size in bytes",
138 },
139 []string{"connection_id"},
140 )
141 prometheus.MustRegister(sendWindowMax)
142
143 inBoundRateCurr := prometheus.NewGaugeVec(
144 prometheus.GaugeOpts{
145 Name: "inbound_bytes_per_sec_curr",
146 Help: "Current inbounding bytes per second, 0 if there is no incoming connection",
147 },
148 []string{"connection_id"},
149 )
150 prometheus.MustRegister(inBoundRateCurr)
151
152 inBoundRateMin := prometheus.NewGaugeVec(
153 prometheus.GaugeOpts{
154 Name: "inbound_bytes_per_sec_min",
155 Help: "Minimum non-zero inbounding bytes per second",
156 },
157 []string{"connection_id"},
158 )
159 prometheus.MustRegister(inBoundRateMin)
160
161 inBoundRateMax := prometheus.NewGaugeVec(
162 prometheus.GaugeOpts{
163 Name: "inbound_bytes_per_sec_max",
164 Help: "Maximum inbounding bytes per second",
165 },
166 []string{"connection_id"},
167 )
168 prometheus.MustRegister(inBoundRateMax)
169
170 outBoundRateCurr := prometheus.NewGaugeVec(
171 prometheus.GaugeOpts{
172 Name: "outbound_bytes_per_sec_curr",
173 Help: "Current outbounding bytes per second, 0 if there is no outgoing traffic",
174 },
175 []string{"connection_id"},
176 )
177 prometheus.MustRegister(outBoundRateCurr)
178
179 outBoundRateMin := prometheus.NewGaugeVec(
180 prometheus.GaugeOpts{
181 Name: "outbound_bytes_per_sec_min",
182 Help: "Minimum non-zero outbounding bytes per second",
183 },
184 []string{"connection_id"},
185 )
186 prometheus.MustRegister(outBoundRateMin)
187
188 outBoundRateMax := prometheus.NewGaugeVec(
189 prometheus.GaugeOpts{
190 Name: "outbound_bytes_per_sec_max",
191 Help: "Maximum outbounding bytes per second",
192 },
193 []string{"connection_id"},
194 )
195 prometheus.MustRegister(outBoundRateMax)
196
197 compBytesBefore := prometheus.NewGaugeVec(
198 prometheus.GaugeOpts{
199 Name: "comp_bytes_before",
200 Help: "Bytes sent via cross-stream compression, pre compression",
201 },
202 []string{"connection_id"},
203 )
204 prometheus.MustRegister(compBytesBefore)
205
206 compBytesAfter := prometheus.NewGaugeVec(
207 prometheus.GaugeOpts{
208 Name: "comp_bytes_after",
209 Help: "Bytes sent via cross-stream compression, post compression",
210 },
211 []string{"connection_id"},
212 )
213 prometheus.MustRegister(compBytesAfter)
214
215 compRateAve := prometheus.NewGaugeVec(
216 prometheus.GaugeOpts{
217 Name: "comp_rate_ave",
218 Help: "Average outbound cross-stream compression ratio",
219 },
220 []string{"connection_id"},
221 )
222 prometheus.MustRegister(compRateAve)
223
224 return &muxerMetrics{
225 rtt: rtt,
226 rttMin: rttMin,
227 rttMax: rttMax,
228 receiveWindowAve: receiveWindowAve,
229 sendWindowAve: sendWindowAve,
230 receiveWindowMin: receiveWindowMin,
231 receiveWindowMax: receiveWindowMax,
232 sendWindowMin: sendWindowMin,
233 sendWindowMax: sendWindowMax,
234 inBoundRateCurr: inBoundRateCurr,
235 inBoundRateMin: inBoundRateMin,
236 inBoundRateMax: inBoundRateMax,
237 outBoundRateCurr: outBoundRateCurr,
238 outBoundRateMin: outBoundRateMin,
239 outBoundRateMax: outBoundRateMax,
240 compBytesBefore: compBytesBefore,
241 compBytesAfter: compBytesAfter,
242 compRateAve: compRateAve,
243 }
244}
245
246func (m *muxerMetrics) update(connectionID string, metrics *h2mux.MuxerMetrics) {
247 m.rtt.WithLabelValues(connectionID).Set(convertRTTMilliSec(metrics.RTT))
248 m.rttMin.WithLabelValues(connectionID).Set(convertRTTMilliSec(metrics.RTTMin))
249 m.rttMax.WithLabelValues(connectionID).Set(convertRTTMilliSec(metrics.RTTMax))
250 m.receiveWindowAve.WithLabelValues(connectionID).Set(metrics.ReceiveWindowAve)
251 m.sendWindowAve.WithLabelValues(connectionID).Set(metrics.SendWindowAve)
252 m.receiveWindowMin.WithLabelValues(connectionID).Set(float64(metrics.ReceiveWindowMin))
253 m.receiveWindowMax.WithLabelValues(connectionID).Set(float64(metrics.ReceiveWindowMax))
254 m.sendWindowMin.WithLabelValues(connectionID).Set(float64(metrics.SendWindowMin))
255 m.sendWindowMax.WithLabelValues(connectionID).Set(float64(metrics.SendWindowMax))
256 m.inBoundRateCurr.WithLabelValues(connectionID).Set(float64(metrics.InBoundRateCurr))
257 m.inBoundRateMin.WithLabelValues(connectionID).Set(float64(metrics.InBoundRateMin))
258 m.inBoundRateMax.WithLabelValues(connectionID).Set(float64(metrics.InBoundRateMax))
259 m.outBoundRateCurr.WithLabelValues(connectionID).Set(float64(metrics.OutBoundRateCurr))
260 m.outBoundRateMin.WithLabelValues(connectionID).Set(float64(metrics.OutBoundRateMin))
261 m.outBoundRateMax.WithLabelValues(connectionID).Set(float64(metrics.OutBoundRateMax))
262 m.compBytesBefore.WithLabelValues(connectionID).Set(float64(metrics.CompBytesBefore.Value()))
263 m.compBytesAfter.WithLabelValues(connectionID).Set(float64(metrics.CompBytesAfter.Value()))
264 m.compRateAve.WithLabelValues(connectionID).Set(float64(metrics.CompRateAve()))
265}
266
267func convertRTTMilliSec(t time.Duration) float64 {
268 return float64(t / time.Millisecond)
269}
270
271// Metrics that can be collected without asking the edge
272func NewTunnelMetrics() *TunnelMetrics {
273 haConnections := prometheus.NewGauge(
274 prometheus.GaugeOpts{
275 Name: "ha_connections",
276 Help: "Number of active ha connections",
277 })
278 prometheus.MustRegister(haConnections)
279
280 totalRequests := prometheus.NewCounter(
281 prometheus.CounterOpts{
282 Name: "total_requests",
283 Help: "Amount of requests proxied through all the tunnels",
284 })
285 prometheus.MustRegister(totalRequests)
286
287 requestsPerTunnel := prometheus.NewCounterVec(
288 prometheus.CounterOpts{
289 Name: "requests_per_tunnel",
290 Help: "Amount of requests proxied through each tunnel",
291 },
292 []string{"connection_id"},
293 )
294 prometheus.MustRegister(requestsPerTunnel)
295
296 concurrentRequestsPerTunnel := prometheus.NewGaugeVec(
297 prometheus.GaugeOpts{
298 Name: "concurrent_requests_per_tunnel",
299 Help: "Concurrent requests proxied through each tunnel",
300 },
301 []string{"connection_id"},
302 )
303 prometheus.MustRegister(concurrentRequestsPerTunnel)
304
305 maxConcurrentRequestsPerTunnel := prometheus.NewGaugeVec(
306 prometheus.GaugeOpts{
307 Name: "max_concurrent_requests_per_tunnel",
308 Help: "Largest number of concurrent requests proxied through each tunnel so far",
309 },
310 []string{"connection_id"},
311 )
312 prometheus.MustRegister(maxConcurrentRequestsPerTunnel)
313
314 timerRetries := prometheus.NewGauge(
315 prometheus.GaugeOpts{
316 Name: "timer_retries",
317 Help: "Unacknowledged heart beats count",
318 })
319 prometheus.MustRegister(timerRetries)
320
321 responseByCode := prometheus.NewCounterVec(
322 prometheus.CounterOpts{
323 Name: "response_by_code",
324 Help: "Count of responses by HTTP status code",
325 },
326 []string{"status_code"},
327 )
328 prometheus.MustRegister(responseByCode)
329
330 responseCodePerTunnel := prometheus.NewCounterVec(
331 prometheus.CounterOpts{
332 Name: "response_code_per_tunnel",
333 Help: "Count of responses by HTTP status code fore each tunnel",
334 },
335 []string{"connection_id", "status_code"},
336 )
337 prometheus.MustRegister(responseCodePerTunnel)
338
339 serverLocations := prometheus.NewGaugeVec(
340 prometheus.GaugeOpts{
341 Name: "server_locations",
342 Help: "Where each tunnel is connected to. 1 means current location, 0 means previous locations.",
343 },
344 []string{"connection_id", "location"},
345 )
346 prometheus.MustRegister(serverLocations)
347
348 registerFail := prometheus.NewCounterVec(
349 prometheus.CounterOpts{
350 Name: "tunnel_register_fail",
351 Help: "Count of tunnel registration errors by type",
352 },
353 []string{"error"},
354 )
355 prometheus.MustRegister(registerFail)
356
357 registerSuccess := prometheus.NewCounter(
358 prometheus.CounterOpts{
359 Name: "tunnel_register_success",
360 Help: "Count of successful tunnel registrations",
361 })
362 prometheus.MustRegister(registerSuccess)
363
364 return &TunnelMetrics{
365 haConnections: haConnections,
366 totalRequests: totalRequests,
367 requestsPerTunnel: requestsPerTunnel,
368 concurrentRequestsPerTunnel: concurrentRequestsPerTunnel,
369 concurrentRequests: make(map[string]uint64),
370 maxConcurrentRequestsPerTunnel: maxConcurrentRequestsPerTunnel,
371 maxConcurrentRequests: make(map[string]uint64),
372 timerRetries: timerRetries,
373 responseByCode: responseByCode,
374 responseCodePerTunnel: responseCodePerTunnel,
375 serverLocations: serverLocations,
376 oldServerLocations: make(map[string]string),
377 muxerMetrics: newMuxerMetrics(),
378 tunnelsHA: NewTunnelsForHA(),
379 regSuccess: registerSuccess,
380 regFail: registerFail,
381 }
382}
383
384func (t *TunnelMetrics) incrementHaConnections() {
385 t.haConnections.Inc()
386}
387
388func (t *TunnelMetrics) decrementHaConnections() {
389 t.haConnections.Dec()
390}
391
392func (t *TunnelMetrics) updateMuxerMetrics(connectionID string, metrics *h2mux.MuxerMetrics) {
393 t.muxerMetrics.update(connectionID, metrics)
394}
395
396func (t *TunnelMetrics) incrementRequests(connectionID string) {
397 t.concurrentRequestsLock.Lock()
398 var concurrentRequests uint64
399 var ok bool
400 if concurrentRequests, ok = t.concurrentRequests[connectionID]; ok {
401 t.concurrentRequests[connectionID]++
402 concurrentRequests++
403 } else {
404 t.concurrentRequests[connectionID] = 1
405 concurrentRequests = 1
406 }
407 if maxConcurrentRequests, ok := t.maxConcurrentRequests[connectionID]; (ok && maxConcurrentRequests < concurrentRequests) || !ok {
408 t.maxConcurrentRequests[connectionID] = concurrentRequests
409 t.maxConcurrentRequestsPerTunnel.WithLabelValues(connectionID).Set(float64(concurrentRequests))
410 }
411 t.concurrentRequestsLock.Unlock()
412
413 t.totalRequests.Inc()
414 t.requestsPerTunnel.WithLabelValues(connectionID).Inc()
415 t.concurrentRequestsPerTunnel.WithLabelValues(connectionID).Inc()
416}
417
418func (t *TunnelMetrics) decrementConcurrentRequests(connectionID string) {
419 t.concurrentRequestsLock.Lock()
420 if _, ok := t.concurrentRequests[connectionID]; ok {
421 t.concurrentRequests[connectionID]--
422 }
423 t.concurrentRequestsLock.Unlock()
424
425 t.concurrentRequestsPerTunnel.WithLabelValues(connectionID).Dec()
426}
427
428func (t *TunnelMetrics) incrementResponses(connectionID, code string) {
429 t.responseByCode.WithLabelValues(code).Inc()
430 t.responseCodePerTunnel.WithLabelValues(connectionID, code).Inc()
431
432}
433
434func (t *TunnelMetrics) registerServerLocation(connectionID, loc string) {
435 t.locationLock.Lock()
436 defer t.locationLock.Unlock()
437 if oldLoc, ok := t.oldServerLocations[connectionID]; ok && oldLoc == loc {
438 return
439 } else if ok {
440 t.serverLocations.WithLabelValues(connectionID, oldLoc).Dec()
441 }
442 t.serverLocations.WithLabelValues(connectionID, loc).Inc()
443 t.oldServerLocations[connectionID] = loc
444}
445