master
go 816 lines 23.6 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package nats
4
5 import (
6 "fmt"
7 "maps"
8 "strconv"
9 "strings"
10
11 "golang.org/x/text/cases"
12 "golang.org/x/text/language"
13
14 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
15 )
16
17 const (
18 prioServerTraffic = collectorapi.Priority + iota
19 prioServerMessages
20 prioServerConnections
21 prioServerConnectionsRate
22 prioHttpEndpointRequests
23 prioServerHealthProbeStatus
24 prioServerCpuUsage
25 prioServerMemoryUsage
26 prioServerUptime
27
28 prioJetStreamStatus
29 prioJetStreamStreams
30 prioJetStreamConsumers
31 prioJetStreamBytes
32 prioJetStreamMessages
33 prioJetStreamApiRequests
34 prioJetStreamApiErrors
35 prioJetStreamApiInflight
36 prioJetStreamMemoryUsed
37 prioJetStreamStorageUsed
38
39 prioAccountTraffic
40 prioAccountMessages
41 prioAccountConnections
42 prioAccountConnectionsRate
43 prioAccountSubscriptions
44 prioAccountSlowConsumers
45 prioAccountLeafNodes
46
47 prioRouteTraffic
48 prioRouteMessages
49 prioRouteSubscriptions
50
51 prioGatewayConnTraffic
52 prioGatewayConnMessages
53 prioGatewayConnSubscriptions
54 prioGatewayConnUptime
55
56 prioLeafConnTraffic
57 prioLeafConnMessages
58 prioLeafConnSubscriptions
59 prioLeafRTT
60 )
61
62 func serverCharts() *collectorapi.Charts {
63 charts := collectorapi.Charts{
64 chartServerConnectionsCurrent.Copy(),
65 chartServerConnectionsRate.Copy(),
66 chartServerTraffic.Copy(),
67 chartServerMessages.Copy(),
68 chartServerHealthProbeStatus.Copy(),
69 chartServerCpuUsage.Copy(),
70 chartServerMemUsage.Copy(),
71 chartServerUptime.Copy(),
72 }
73 charts = append(charts, httpEndpointsCharts()...)
74 charts = append(charts, *jetStreamCharts.Copy()...)
75 return charts.Copy()
76 }
77
78 var (
79 chartServerTraffic = collectorapi.Chart{
80 ID: "server_traffic",
81 Title: "Server Traffic",
82 Units: "bytes/s",
83 Fam: "traffic",
84 Ctx: "nats.server_traffic",
85 Priority: prioServerTraffic,
86 Type: collectorapi.Area,
87 Dims: collectorapi.Dims{
88 {ID: "varz_srv_in_bytes", Name: "received", Algo: collectorapi.Incremental},
89 {ID: "varz_srv_out_bytes", Name: "sent", Mul: -1, Algo: collectorapi.Incremental},
90 },
91 }
92 chartServerMessages = collectorapi.Chart{
93 ID: "server_messages",
94 Title: "Server Messages",
95 Units: "messages/s",
96 Fam: "traffic",
97 Ctx: "nats.server_messages",
98 Priority: prioServerMessages,
99 Dims: collectorapi.Dims{
100 {ID: "varz_srv_in_msgs", Name: "received", Algo: collectorapi.Incremental},
101 {ID: "varz_srv_out_msgs", Name: "sent", Mul: -1, Algo: collectorapi.Incremental},
102 },
103 }
104 chartServerConnectionsCurrent = collectorapi.Chart{
105 ID: "server_connections",
106 Title: "Server Active Connections",
107 Units: "connections",
108 Fam: "connections",
109 Ctx: "nats.server_connections",
110 Priority: prioServerConnections,
111 Dims: collectorapi.Dims{
112 {ID: "varz_srv_connections", Name: "active"},
113 },
114 }
115 chartServerConnectionsRate = collectorapi.Chart{
116 ID: "server_connections_rate",
117 Title: "Server Connections",
118 Units: "connections/s",
119 Fam: "connections",
120 Ctx: "nats.server_connections_rate",
121 Priority: prioServerConnectionsRate,
122 Dims: collectorapi.Dims{
123 {ID: "varz_srv_total_connections", Name: "connections", Algo: collectorapi.Incremental},
124 },
125 }
126 chartServerHealthProbeStatus = collectorapi.Chart{
127 ID: "server_health_probe_status",
128 Title: "Server Health Probe Status",
129 Units: "status",
130 Fam: "health",
131 Ctx: "nats.server_health_probe_status",
132 Priority: prioServerHealthProbeStatus,
133 Dims: collectorapi.Dims{
134 {ID: "varz_srv_healthz_status_ok", Name: "ok"},
135 {ID: "varz_srv_healthz_status_error", Name: "error"},
136 },
137 }
138 chartServerCpuUsage = collectorapi.Chart{
139 ID: "server_cpu_usage",
140 Title: "Server CPU Usage",
141 Units: "percent",
142 Fam: "rusage",
143 Ctx: "nats.server_cpu_usage",
144 Priority: prioServerCpuUsage,
145 Type: collectorapi.Area,
146 Dims: collectorapi.Dims{
147 {ID: "varz_srv_cpu", Name: "used"},
148 },
149 }
150 chartServerMemUsage = collectorapi.Chart{
151 ID: "server_mem_usage",
152 Title: "Server Memory Usage",
153 Units: "bytes",
154 Fam: "rusage",
155 Ctx: "nats.server_mem_usage",
156 Priority: prioServerMemoryUsage,
157 Type: collectorapi.Area,
158 Dims: collectorapi.Dims{
159 {ID: "varz_srv_mem", Name: "used"},
160 },
161 }
162 chartServerUptime = collectorapi.Chart{
163 ID: "server_uptime",
164 Title: "Server Uptime",
165 Units: "seconds",
166 Fam: "uptime",
167 Ctx: "nats.server_uptime",
168 Priority: prioServerUptime,
169 Dims: collectorapi.Dims{
170 {ID: "varz_srv_uptime", Name: "uptime"},
171 },
172 }
173 )
174
175 func httpEndpointsCharts() collectorapi.Charts {
176 var charts collectorapi.Charts
177
178 for _, path := range httpEndpoints {
179 chart := httpEndpointRequestsChartTmpl.Copy()
180
181 chart.ID = fmt.Sprintf(chart.ID, path)
182 chart.Labels = []collectorapi.Label{
183 {Key: "http_endpoint", Value: path},
184 }
185 for _, dim := range chart.Dims {
186 dim.ID = fmt.Sprintf(dim.ID, path)
187 }
188 charts = append(charts, chart)
189 }
190
191 return charts
192 }
193
194 var httpEndpointRequestsChartTmpl = collectorapi.Chart{
195 ID: "http_endpoint_%s_requests",
196 Title: "HTTP Endpoint Requests",
197 Units: "requests/s",
198 Fam: "http requests",
199 Ctx: "nats.http_endpoint_requests",
200 Priority: prioHttpEndpointRequests,
201 Dims: collectorapi.Dims{
202 {ID: "varz_http_endpoint_%s_req", Name: "requests", Algo: collectorapi.Incremental},
203 },
204 }
205
206 var jetStreamCharts = collectorapi.Charts{
207 jetStreamStatus.Copy(),
208 jetStreamStreams.Copy(),
209 jetStreamStreamsStorageBytes.Copy(),
210 jetStreamStreamsStorageMessages.Copy(),
211 jetStreamConsumers.Copy(),
212 jetStreamApiRequests.Copy(),
213 jetStreamApiInflightRequests.Copy(),
214 jetStreamApiErrors.Copy(),
215 jetStreamMemoryUsed.Copy(),
216 jetStreamStorageUsed.Copy(),
217 }
218
219 var (
220 jetStreamStatus = collectorapi.Chart{
221 ID: "jetstream_status",
222 Title: "JetStream Status",
223 Units: "status",
224 Fam: "jstream streams",
225 Ctx: "nats.jetstream_status",
226 Priority: prioJetStreamStatus,
227 Dims: collectorapi.Dims{
228 {ID: "jsz_enabled", Name: "enabled"},
229 {ID: "jsz_disabled", Name: "disabled"},
230 },
231 }
232 jetStreamStreams = collectorapi.Chart{
233 ID: "jetstream_streams",
234 Title: "JetStream Streams",
235 Units: "streams",
236 Fam: "jstream streams",
237 Ctx: "nats.jetstream_streams",
238 Priority: prioJetStreamStreams,
239 Dims: collectorapi.Dims{
240 {ID: "jsz_streams", Name: "active"},
241 },
242 }
243 jetStreamStreamsStorageBytes = collectorapi.Chart{
244 ID: "jetstream_streams_storage_bytes",
245 Title: "JetStream Bytes",
246 Units: "bytes",
247 Fam: "jstream streams",
248 Ctx: "nats.jetstream_streams_storage_bytes",
249 Priority: prioJetStreamBytes,
250 Type: collectorapi.Area,
251 Dims: collectorapi.Dims{
252 {ID: "jsz_bytes", Name: "used"},
253 },
254 }
255 jetStreamStreamsStorageMessages = collectorapi.Chart{
256 ID: "jetstream_streams_storage_messages",
257 Title: "JetStream Messages",
258 Units: "messages",
259 Fam: "jstream streams",
260 Ctx: "nats.jetstream_streams_storage_messages",
261 Priority: prioJetStreamMessages,
262 Dims: collectorapi.Dims{
263 {ID: "jsz_messages", Name: "stored"},
264 },
265 }
266 jetStreamConsumers = collectorapi.Chart{
267 ID: "jetstream_consumers",
268 Title: "JetStream Consumers",
269 Units: "consumers",
270 Fam: "jstream consumers",
271 Ctx: "nats.jetstream_consumers",
272 Priority: prioJetStreamConsumers,
273 Dims: collectorapi.Dims{
274 {ID: "jsz_consumers", Name: "active"},
275 },
276 }
277 jetStreamApiRequests = collectorapi.Chart{
278 ID: "jetstream_api_requests",
279 Title: "JetStream API Requests",
280 Units: "requests/s",
281 Fam: "jstream api",
282 Ctx: "nats.jetstream_api_requests",
283 Priority: prioJetStreamApiRequests,
284 Dims: collectorapi.Dims{
285 {ID: "jsz_api_total", Name: "requests", Algo: collectorapi.Incremental},
286 },
287 }
288 jetStreamApiErrors = collectorapi.Chart{
289 ID: "jetstream_api_errors",
290 Title: "JetStream API Errors",
291 Units: "errors/s",
292 Fam: "jstream api",
293 Ctx: "nats.jetstream_api_errors",
294 Priority: prioJetStreamApiErrors,
295 Dims: collectorapi.Dims{
296 {ID: "jsz_api_errors", Name: "errors", Algo: collectorapi.Incremental},
297 },
298 }
299 jetStreamApiInflightRequests = collectorapi.Chart{
300 ID: "jetstream_api_inflight",
301 Title: "JetStream API Inflight",
302 Units: "requests",
303 Fam: "jstream api",
304 Ctx: "nats.jetstream_api_inflight",
305 Priority: prioJetStreamApiInflight,
306 Dims: collectorapi.Dims{
307 {ID: "jsz_api_inflight", Name: "inflight"},
308 },
309 }
310 jetStreamMemoryUsed = collectorapi.Chart{
311 ID: "jetstream_memory_used",
312 Title: "JetStream Used Memory",
313 Units: "bytes",
314 Fam: "jstream rusage",
315 Ctx: "nats.jetstream_memory_used",
316 Priority: prioJetStreamMemoryUsed,
317 Type: collectorapi.Area,
318 Dims: collectorapi.Dims{
319 {ID: "jsz_memory_used", Name: "used"},
320 },
321 }
322 jetStreamStorageUsed = collectorapi.Chart{
323 ID: "jetstream_storage_used",
324 Title: "JetStream Used Storage",
325 Units: "bytes",
326 Fam: "jstream rusage",
327 Ctx: "nats.jetstream_storage_used",
328 Priority: prioJetStreamStorageUsed,
329 Dims: collectorapi.Dims{
330 {ID: "jsz_store_used", Name: "used"},
331 },
332 }
333 )
334
335 var accountChartsTmpl = collectorapi.Charts{
336 accountTrafficTmpl.Copy(),
337 accountMessagesTmpl.Copy(),
338 accountConnectionsCurrentTmpl.Copy(),
339 accountConnectionsRateTmpl.Copy(),
340 accountSubscriptionsTmpl.Copy(),
341 accountSlowConsumersTmpl.Copy(),
342 accountLeadNodesTmpl.Copy(),
343 }
344
345 var (
346 accountTrafficTmpl = collectorapi.Chart{
347 ID: "account_%s_traffic",
348 Title: "Account Traffic",
349 Units: "bytes/s",
350 Fam: "acc traffic",
351 Ctx: "nats.account_traffic",
352 Priority: prioAccountTraffic,
353 Type: collectorapi.Area,
354 Dims: collectorapi.Dims{
355 {ID: "accstatz_acc_%s_received_bytes", Name: "received", Algo: collectorapi.Incremental},
356 {ID: "accstatz_acc_%s_sent_bytes", Name: "sent", Mul: -1, Algo: collectorapi.Incremental},
357 },
358 }
359 accountMessagesTmpl = collectorapi.Chart{
360 ID: "account_%s_messages",
361 Title: "Account Messages",
362 Units: "messages/s",
363 Fam: "acc traffic",
364 Ctx: "nats.account_messages",
365 Priority: prioAccountMessages,
366 Type: collectorapi.Line,
367 Dims: collectorapi.Dims{
368 {ID: "accstatz_acc_%s_received_msgs", Name: "received", Algo: collectorapi.Incremental},
369 {ID: "accstatz_acc_%s_sent_msgs", Name: "sent", Mul: -1, Algo: collectorapi.Incremental},
370 },
371 }
372 accountConnectionsCurrentTmpl = collectorapi.Chart{
373 ID: "account_%s_connections",
374 Title: "Account Active Connections",
375 Units: "connections",
376 Fam: "acc connections",
377 Ctx: "nats.account_connections",
378 Priority: prioAccountConnections,
379 Type: collectorapi.Line,
380 Dims: collectorapi.Dims{
381 {ID: "accstatz_acc_%s_conns", Name: "active"},
382 },
383 }
384 accountConnectionsRateTmpl = collectorapi.Chart{
385 ID: "account_%s_connections_rate",
386 Title: "Account Connections",
387 Units: "connections/s",
388 Fam: "acc connections",
389 Ctx: "nats.account_connections_rate",
390 Priority: prioAccountConnectionsRate,
391 Type: collectorapi.Line,
392 Dims: collectorapi.Dims{
393 {ID: "accstatz_acc_%s_total_conns", Name: "connections", Algo: collectorapi.Incremental},
394 },
395 }
396 accountSubscriptionsTmpl = collectorapi.Chart{
397 ID: "account_%s_subscriptions",
398 Title: "Account Active Subscriptions",
399 Units: "subscriptions",
400 Fam: "acc subscriptions",
401 Ctx: "nats.account_subscriptions",
402 Priority: prioAccountSubscriptions,
403 Type: collectorapi.Line,
404 Dims: collectorapi.Dims{
405 {ID: "accstatz_acc_%s_num_subs", Name: "active"},
406 },
407 }
408 accountSlowConsumersTmpl = collectorapi.Chart{
409 ID: "account_%s_slow_consumers",
410 Title: "Account Slow Consumers",
411 Units: "consumers/s",
412 Fam: "acc consumers",
413 Ctx: "nats.account_slow_consumers",
414 Priority: prioAccountSlowConsumers,
415 Type: collectorapi.Line,
416 Dims: collectorapi.Dims{
417 {ID: "accstatz_acc_%s_slow_consumers", Name: "slow", Algo: collectorapi.Incremental},
418 },
419 }
420 accountLeadNodesTmpl = collectorapi.Chart{
421 ID: "account_%s_leaf_nodes",
422 Title: "Account Leaf Nodes",
423 Units: "servers",
424 Fam: "acc leaf nodes",
425 Ctx: "nats.account_leaf_nodes",
426 Priority: prioAccountLeafNodes,
427 Type: collectorapi.Line,
428 Dims: collectorapi.Dims{
429 {ID: "accstatz_acc_%s_leaf_nodes", Name: "leafnode"},
430 },
431 }
432 )
433
434 var routeChartsTmpl = collectorapi.Charts{
435 routeTrafficTmpl.Copy(),
436 routeMessagesTmpl.Copy(),
437 routeSubscriptionsTmpl.Copy(),
438 }
439
440 var (
441 routeTrafficTmpl = collectorapi.Chart{
442 ID: "route_%d_traffic",
443 Title: "Route Traffic",
444 Units: "bytes/s",
445 Fam: "route traffic",
446 Ctx: "nats.route_traffic",
447 Priority: prioRouteTraffic,
448 Type: collectorapi.Area,
449 Dims: collectorapi.Dims{
450 {ID: "routez_route_id_%d_in_bytes", Name: "in", Algo: collectorapi.Incremental},
451 {ID: "routez_route_id_%d_out_bytes", Name: "out", Mul: -1, Algo: collectorapi.Incremental},
452 },
453 }
454 routeMessagesTmpl = collectorapi.Chart{
455 ID: "route_%d_messages",
456 Title: "Route Messages",
457 Units: "messages/s",
458 Fam: "route traffic",
459 Ctx: "nats.route_messages",
460 Priority: prioRouteMessages,
461 Type: collectorapi.Line,
462 Dims: collectorapi.Dims{
463 {ID: "routez_route_id_%d_in_msgs", Name: "in", Algo: collectorapi.Incremental},
464 {ID: "routez_route_id_%d_out_msgs", Name: "out", Mul: -1, Algo: collectorapi.Incremental},
465 },
466 }
467 routeSubscriptionsTmpl = collectorapi.Chart{
468 ID: "route_%d_subscriptions",
469 Title: "Route Active Subscriptions",
470 Units: "subscriptions",
471 Fam: "route subscriptions",
472 Ctx: "nats.route_subscriptions",
473 Priority: prioRouteSubscriptions,
474 Type: collectorapi.Line,
475 Dims: collectorapi.Dims{
476 {ID: "routez_route_id_%d_num_subs", Name: "active"},
477 },
478 }
479 )
480
481 var gatewayConnChartsTmpl = collectorapi.Charts{
482 gatewayConnTrafficTmpl.Copy(),
483 gatewayConnMessagesTmpl.Copy(),
484 gatewayConnSubscriptionsTmpl.Copy(),
485 gatewayConnUptime.Copy(),
486 }
487
488 var (
489 gatewayConnTrafficTmpl = collectorapi.Chart{
490 ID: "%s_gw_%s_cid_%d_traffic",
491 Title: "%s Gateway Traffic",
492 Units: "bytes/s",
493 Fam: "gw traffic",
494 Ctx: "nats.%s_gateway_conn_traffic",
495 Priority: prioGatewayConnTraffic,
496 Type: collectorapi.Area,
497 Dims: collectorapi.Dims{
498 {ID: "gatewayz_%s_gw_%s_cid_%d_in_bytes", Name: "in", Algo: collectorapi.Incremental},
499 {ID: "gatewayz_%s_gw_%s_cid_%d_out_bytes", Name: "out", Mul: -1, Algo: collectorapi.Incremental},
500 },
501 }
502 gatewayConnMessagesTmpl = collectorapi.Chart{
503 ID: "%s_gw_%s_cid_%d_messages",
504 Title: "%s Gateway Messages",
505 Units: "messages/s",
506 Fam: "gw traffic",
507 Ctx: "nats.%s_gateway_conn_messages",
508 Priority: prioGatewayConnMessages,
509 Type: collectorapi.Line,
510 Dims: collectorapi.Dims{
511 {ID: "gatewayz_%s_gw_%s_cid_%d_in_msgs", Name: "in", Algo: collectorapi.Incremental},
512 {ID: "gatewayz_%s_gw_%s_cid_%d_out_msgs", Name: "out", Mul: -1, Algo: collectorapi.Incremental},
513 },
514 }
515 gatewayConnSubscriptionsTmpl = collectorapi.Chart{
516 ID: "%s_gw_%s_cid_%d_subscriptions",
517 Title: "%s Gateway Active Subscriptions",
518 Units: "subscriptions",
519 Fam: "gw subscriptions",
520 Ctx: "nats.%s_gateway_conn_subscriptions",
521 Priority: prioGatewayConnSubscriptions,
522 Type: collectorapi.Line,
523 Dims: collectorapi.Dims{
524 {ID: "gatewayz_%s_gw_%s_cid_%d_num_subs", Name: "active"},
525 },
526 }
527 gatewayConnUptime = collectorapi.Chart{
528 ID: "%s_gw_%s_cid_%d_uptime",
529 Title: "%s Gateway Connection Uptime",
530 Units: "seconds",
531 Fam: "gw uptime",
532 Ctx: "nats.%s_gateway_conn_uptime",
533 Priority: prioGatewayConnUptime,
534 Dims: collectorapi.Dims{
535 {ID: "gatewayz_%s_gw_%s_cid_%d_uptime", Name: "uptime"},
536 },
537 }
538 )
539
540 var leafConnChartsTmpl = collectorapi.Charts{
541 leafConnTrafficTmpl.Copy(),
542 leafConnMessagesTmpl.Copy(),
543 leafConnSubscriptionsTmpl.Copy(),
544 leafConnRTT.Copy(),
545 }
546
547 var (
548 leafConnTrafficTmpl = collectorapi.Chart{
549 ID: "leaf_node_conn_%s_%s_%s_%d_traffic",
550 Title: "Leaf Node Connection Traffic",
551 Units: "bytes/s",
552 Fam: "leaf traffic",
553 Ctx: "nats.leaf_node_conn_traffic",
554 Priority: prioLeafConnTraffic,
555 Type: collectorapi.Area,
556 Dims: collectorapi.Dims{
557 {ID: "leafz_leaf_%s_%s_%s_%d_in_bytes", Name: "in", Algo: collectorapi.Incremental},
558 {ID: "leafz_leaf_%s_%s_%s_%d_out_bytes", Name: "out", Mul: -1, Algo: collectorapi.Incremental},
559 },
560 }
561 leafConnMessagesTmpl = collectorapi.Chart{
562 ID: "leaf_node_conn_%s_%s_%s_%d_messages",
563 Title: "Leaf Node Connection Messages",
564 Units: "messages/s",
565 Fam: "leaf traffic",
566 Ctx: "nats.leaf_node_conn_messages",
567 Priority: prioLeafConnMessages,
568 Type: collectorapi.Line,
569 Dims: collectorapi.Dims{
570 {ID: "leafz_leaf_%s_%s_%s_%d_in_msgs", Name: "in", Algo: collectorapi.Incremental},
571 {ID: "leafz_leaf_%s_%s_%s_%d_out_msgs", Name: "out", Mul: -1, Algo: collectorapi.Incremental},
572 },
573 }
574 leafConnSubscriptionsTmpl = collectorapi.Chart{
575 ID: "leaf_node_conn_%s_%s_%s_%d_subscriptions",
576 Title: "Leaf Node Connection Active Subscriptions",
577 Units: "subscriptions",
578 Fam: "leaf subscriptions",
579 Ctx: "nats.leaf_node_conn_subscriptions",
580 Priority: prioLeafConnSubscriptions,
581 Type: collectorapi.Line,
582 Dims: collectorapi.Dims{
583 {ID: "leafz_leaf_%s_%s_%s_%d_num_subs", Name: "active"},
584 },
585 }
586 leafConnRTT = collectorapi.Chart{
587 ID: "leaf_node_conn_%s_%s_%s_%d_rtt",
588 Title: "Leaf Node Connection RTT",
589 Units: "microseconds",
590 Fam: "leaf rtt",
591 Ctx: "nats.leaf_node_conn_rtt",
592 Priority: prioLeafRTT,
593 Dims: collectorapi.Dims{
594 {ID: "leafz_leaf_%s_%s_%s_%d_rtt", Name: "rtt"},
595 },
596 }
597 )
598
599 func (c *Collector) updateCharts() {
600 c.onceAddSrvCharts.Do(c.addServerCharts)
601
602 maps.DeleteFunc(c.cache.accounts, func(_ string, acc *accCacheEntry) bool {
603 if !acc.updated {
604 c.removeAccountCharts(acc)
605 return true
606 }
607 if !acc.hasCharts {
608 acc.hasCharts = true
609 c.addAccountCharts(acc)
610 }
611 return false
612 })
613 maps.DeleteFunc(c.cache.routes, func(_ uint64, route *routeCacheEntry) bool {
614 if !route.updated {
615 c.removeRouteCharts(route)
616 return true
617 }
618 if !route.hasCharts {
619 route.hasCharts = true
620 c.addRouteCharts(route)
621 }
622 return false
623 })
624 maps.DeleteFunc(c.cache.inGateways, func(_ string, igw *gwCacheEntry) bool {
625 maps.DeleteFunc(igw.conns, func(_ uint64, inConn *gwConnCacheEntry) bool {
626 if !inConn.updated {
627 c.removeGatewayConnCharts(inConn, true)
628 return true
629 }
630 if !inConn.hasCharts {
631 inConn.hasCharts = true
632 c.addGatewayConnCharts(inConn, true)
633 }
634 return false
635 })
636 return false
637 })
638 maps.DeleteFunc(c.cache.outGateways, func(_ string, ogw *gwCacheEntry) bool {
639 maps.DeleteFunc(ogw.conns, func(_ uint64, outConn *gwConnCacheEntry) bool {
640 if !outConn.updated {
641 c.removeGatewayConnCharts(outConn, false)
642 return true
643 }
644 if !outConn.hasCharts {
645 outConn.hasCharts = true
646 c.addGatewayConnCharts(outConn, false)
647 }
648 return false
649 })
650 return false
651 })
652 maps.DeleteFunc(c.cache.leafs, func(_ string, leaf *leafCacheEntry) bool {
653 if !leaf.updated {
654 c.removeLeafCharts(leaf)
655 return true
656 }
657 if !leaf.hasCharts {
658 leaf.hasCharts = true
659 c.addLeafCharts(leaf)
660 }
661 return false
662 })
663 }
664
665 func (c *Collector) addServerCharts() {
666 charts := serverCharts()
667
668 for _, chart := range *charts {
669 chart.Labels = []collectorapi.Label{
670 {Key: "cluster_name", Value: c.srvMeta.clusterName},
671 {Key: "server_id", Value: c.srvMeta.id},
672 {Key: "server_name", Value: c.srvMeta.name},
673 }
674 }
675
676 if err := c.Charts().Add(*charts...); err != nil {
677 c.Warningf("failed to add server charts: %v", err)
678 }
679 }
680
681 func (c *Collector) addAccountCharts(acc *accCacheEntry) {
682 charts := accountChartsTmpl.Copy()
683
684 for _, chart := range *charts {
685 chart.ID = fmt.Sprintf(chart.ID, acc.accName)
686 chart.Labels = []collectorapi.Label{
687 {Key: "cluster_name", Value: c.srvMeta.clusterName},
688 {Key: "server_id", Value: c.srvMeta.id},
689 {Key: "server_name", Value: c.srvMeta.name},
690 {Key: "account", Value: acc.accName},
691 }
692 for _, dim := range chart.Dims {
693 dim.ID = fmt.Sprintf(dim.ID, acc.accName)
694 }
695 }
696
697 if err := c.Charts().Add(*charts...); err != nil {
698 c.Warningf("failed to add charts for account %s: %s", acc.accName, err)
699 }
700 }
701
702 func (c *Collector) removeAccountCharts(acc *accCacheEntry) {
703 px := fmt.Sprintf("account_%s_", acc.accName)
704 c.removeCharts(px)
705 }
706
707 func (c *Collector) addRouteCharts(route *routeCacheEntry) {
708 charts := routeChartsTmpl.Copy()
709
710 for _, chart := range *charts {
711 chart.ID = fmt.Sprintf(chart.ID, route.rid)
712 chart.Labels = []collectorapi.Label{
713 {Key: "cluster_name", Value: c.srvMeta.clusterName},
714 {Key: "server_id", Value: c.srvMeta.id},
715 {Key: "server_name", Value: c.srvMeta.name},
716 {Key: "route_id", Value: strconv.FormatUint(route.rid, 10)},
717 {Key: "remote_id", Value: route.remoteId},
718 }
719 for _, dim := range chart.Dims {
720 dim.ID = fmt.Sprintf(dim.ID, route.rid)
721 }
722 }
723
724 if err := c.Charts().Add(*charts...); err != nil {
725 c.Warningf("failed to add charts for route id %d: %s", route.rid, err)
726 }
727 }
728
729 func (c *Collector) removeRouteCharts(route *routeCacheEntry) {
730 px := fmt.Sprintf("route_%d_", route.rid)
731 c.removeCharts(px)
732 }
733
734 func (c *Collector) addGatewayConnCharts(gwConn *gwConnCacheEntry, isInbound bool) {
735 direction := "outbound"
736 if isInbound {
737 direction = "inbound"
738 }
739
740 charts := gatewayConnChartsTmpl.Copy()
741
742 for _, chart := range *charts {
743 chart.ID = fmt.Sprintf(chart.ID, direction, gwConn.rgwName, gwConn.cid)
744 chart.Title = fmt.Sprintf(chart.Title, cases.Title(language.English, cases.Compact).String(direction))
745 chart.Ctx = fmt.Sprintf(chart.Ctx, direction)
746 chart.Labels = []collectorapi.Label{
747 {Key: "cluster_name", Value: c.srvMeta.clusterName},
748 {Key: "server_id", Value: c.srvMeta.id},
749 {Key: "server_name", Value: c.srvMeta.name},
750 {Key: "gateway", Value: gwConn.gwName},
751 {Key: "remote_gateway", Value: gwConn.rgwName},
752 {Key: "cid", Value: strconv.FormatUint(gwConn.cid, 10)},
753 }
754 for _, dim := range chart.Dims {
755 dim.ID = fmt.Sprintf(dim.ID, direction, gwConn.rgwName, gwConn.cid)
756 }
757 }
758
759 if err := c.Charts().Add(*charts...); err != nil {
760 c.Warningf("failed to add charts for gateway %s %s %d: %s", direction, gwConn.rgwName, gwConn.cid, err)
761 }
762 }
763
764 func (c *Collector) removeGatewayConnCharts(gwConn *gwConnCacheEntry, isInbound bool) {
765 direction := "outbound"
766 if isInbound {
767 direction = "inbound"
768 }
769 px := fmt.Sprintf("%s_gw_%s_cid_%d_", direction, gwConn.rgwName, gwConn.cid)
770 c.removeCharts(px)
771 }
772
773 func (c *Collector) addLeafCharts(leaf *leafCacheEntry) {
774 charts := leafConnChartsTmpl.Copy()
775
776 for _, chart := range *charts {
777 chart.ID = fmt.Sprintf(chart.ID, leaf.leafName, leaf.account, leaf.ip, leaf.port)
778 chart.ID = cleanChartID(chart.ID)
779 chart.Labels = []collectorapi.Label{
780 {Key: "cluster_name", Value: c.srvMeta.clusterName},
781 {Key: "server_id", Value: c.srvMeta.id},
782 {Key: "server_name", Value: c.srvMeta.name},
783 {Key: "remote_name", Value: leaf.leafName},
784 {Key: "account", Value: leaf.account},
785 {Key: "ip", Value: leaf.ip},
786 {Key: "port", Value: strconv.Itoa(leaf.port)},
787 }
788 for _, dim := range chart.Dims {
789 dim.ID = fmt.Sprintf(dim.ID, leaf.leafName, leaf.account, leaf.ip, leaf.port)
790 }
791 }
792
793 if err := c.Charts().Add(*charts...); err != nil {
794 c.Warningf("failed to add charts for leaf %s: %s", leaf.leafName, err)
795 }
796 }
797
798 func (c *Collector) removeLeafCharts(leaf *leafCacheEntry) {
799 px := fmt.Sprintf("leaf_node_conn_%s_%s_%s_%d_", leaf.leafName, leaf.account, leaf.ip, leaf.port)
800 cleanChartID(px)
801 c.removeCharts(px)
802 }
803
804 func (c *Collector) removeCharts(prefix string) {
805 for _, chart := range *c.Charts() {
806 if strings.HasPrefix(chart.ID, prefix) {
807 chart.MarkRemove()
808 chart.MarkNotCreated()
809 }
810 }
811 }
812
813 func cleanChartID(id string) string {
814 r := strings.NewReplacer(".", "_", " ", "_")
815 return strings.ToLower(r.Replace(id))
816 }