cloudflare/cloudflared

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2019.7.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

origin/metrics.go

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