master
go 621 lines 19.7 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package rabbitmq
4
5 import (
6 "fmt"
7 "maps"
8 "strings"
9
10 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
11 )
12
13 const (
14 prioMessagesCount = collectorapi.Priority + iota
15 prioMessagesRate
16 prioObjectsCount
17 prioConnectionChurnRate
18 prioChannelChurnRate
19 prioQueueChurnRate
20
21 prioNodeAvailStatus
22 prioNodeNetworkPartitioningStatus
23 prioNodeMemAlarmStatus
24 prioNodeDiskFreeAlarmStatus
25 prioNodeFileDescriptorsUsage
26 prioNodeSocketsUsage
27 prioNodeErlangProcessesUsage
28 prioNodeErlangRunQueueProcessesCount
29 prioNodeMemoryUsage
30 prioNodeDiskSpaceFreeSize
31 prioNodeClusterLinkPeerTraffic
32 prioNodeUptime
33
34 prioVhostStatus
35 prioVhostMessagesCount
36 prioVhostMessagesRate
37
38 prioQueueStatus
39 prioQueueMessagesCount
40 prioQueueMessagesRate
41 )
42
43 var overviewCharts = collectorapi.Charts{
44 chartMessagesCount.Copy(),
45 chartMessagesRate.Copy(),
46 chartObjectsCount.Copy(),
47 chartConnectionChurnRate.Copy(),
48 chartChannelChurnRate.Copy(),
49 chartQueueChurnRate.Copy(),
50 }
51
52 var (
53 chartMessagesCount = collectorapi.Chart{
54 ID: "messages_count",
55 Title: "Messages",
56 Units: "messages",
57 Fam: "messages",
58 Ctx: "rabbitmq.messages_count",
59 Type: collectorapi.Stacked,
60 Priority: prioMessagesCount,
61 Dims: collectorapi.Dims{
62 {ID: "queue_totals_messages_ready", Name: "ready"},
63 {ID: "queue_totals_messages_unacknowledged", Name: "unacknowledged"},
64 },
65 }
66 chartMessagesRate = collectorapi.Chart{
67 ID: "messages_rate",
68 Title: "Messages",
69 Units: "messages/s",
70 Fam: "messages",
71 Ctx: "rabbitmq.messages_rate",
72 Priority: prioMessagesRate,
73 Dims: collectorapi.Dims{
74 {ID: "message_stats_ack", Name: "ack", Algo: collectorapi.Incremental},
75 {ID: "message_stats_publish", Name: "publish", Algo: collectorapi.Incremental},
76 {ID: "message_stats_publish_in", Name: "publish_in", Algo: collectorapi.Incremental},
77 {ID: "message_stats_publish_out", Name: "publish_out", Algo: collectorapi.Incremental},
78 {ID: "message_stats_confirm", Name: "confirm", Algo: collectorapi.Incremental},
79 {ID: "message_stats_deliver", Name: "deliver", Algo: collectorapi.Incremental},
80 {ID: "message_stats_deliver_no_ack", Name: "deliver_no_ack", Algo: collectorapi.Incremental},
81 {ID: "message_stats_get", Name: "get", Algo: collectorapi.Incremental},
82 {ID: "message_stats_get_empty", Name: "get_empty", Algo: collectorapi.Incremental},
83 {ID: "message_stats_get_no_ack", Name: "get_no_ack", Algo: collectorapi.Incremental},
84 {ID: "message_stats_deliver_get", Name: "deliver_get", Algo: collectorapi.Incremental},
85 {ID: "message_stats_redeliver", Name: "redeliver", Algo: collectorapi.Incremental},
86 {ID: "message_stats_return_unroutable", Name: "return_unroutable", Algo: collectorapi.Incremental},
87 },
88 }
89 chartObjectsCount = collectorapi.Chart{
90 ID: "objects_count",
91 Title: "Objects",
92 Units: "objects",
93 Fam: "objects",
94 Ctx: "rabbitmq.objects_count",
95 Priority: prioObjectsCount,
96 Dims: collectorapi.Dims{
97 {ID: "object_totals_channels", Name: "channels"},
98 {ID: "object_totals_consumers", Name: "consumers"},
99 {ID: "object_totals_connections", Name: "connections"},
100 {ID: "object_totals_queues", Name: "queues"},
101 {ID: "object_totals_exchanges", Name: "exchanges"},
102 },
103 }
104
105 chartConnectionChurnRate = collectorapi.Chart{
106 ID: "connection_churn_rate",
107 Title: "Connection churn",
108 Units: "operations/s",
109 Fam: "churn",
110 Ctx: "rabbitmq.connection_churn_rate",
111 Priority: prioConnectionChurnRate,
112 Dims: collectorapi.Dims{
113 {ID: "churn_rates_connection_created", Name: "created", Algo: collectorapi.Incremental},
114 {ID: "churn_rates_connection_closed", Name: "closed", Algo: collectorapi.Incremental},
115 },
116 }
117 chartChannelChurnRate = collectorapi.Chart{
118 ID: "channel_churn_rate",
119 Title: "Channel churn",
120 Units: "operations/s",
121 Fam: "churn",
122 Ctx: "rabbitmq.channel_churn_rate",
123 Priority: prioChannelChurnRate,
124 Dims: collectorapi.Dims{
125 {ID: "churn_rates_channel_created", Name: "created", Algo: collectorapi.Incremental},
126 {ID: "churn_rates_channel_closed", Name: "closed", Algo: collectorapi.Incremental},
127 },
128 }
129 chartQueueChurnRate = collectorapi.Chart{
130 ID: "queue_churn_rate",
131 Title: "Queue churn",
132 Units: "operations/s",
133 Fam: "churn",
134 Ctx: "rabbitmq.queue_churn_rate",
135 Priority: prioQueueChurnRate,
136 Dims: collectorapi.Dims{
137 {ID: "churn_rates_queue_created", Name: "created", Algo: collectorapi.Incremental},
138 {ID: "churn_rates_queue_deleted", Name: "deleted", Algo: collectorapi.Incremental},
139 {ID: "churn_rates_queue_declared", Name: "declared", Algo: collectorapi.Incremental},
140 },
141 }
142 )
143
144 var nodeChartsTmpl = collectorapi.Charts{
145 nodeAvailStatusChartTmpl.Copy(),
146 nodeNetworkPartitionStatusChartTmpl.Copy(),
147 nodeMemAlarmStatusChartTmpl.Copy(),
148 nodeDiskFreeAlarmStatusChartTmpl.Copy(),
149 nodeFileDescriptorsUsageChartTmpl.Copy(),
150 nodeSocketsUsageChartTmpl.Copy(),
151 nodeErlangProcessesUsageChartTmpl.Copy(),
152 nodeErlangRunQueueProcessesCountChartTmpl.Copy(),
153 nodeMemoryUsageChartTmpl.Copy(),
154 nodeDiskSpaceFreeSizeChartTmpl.Copy(),
155 nodeUptimeChartTmpl.Copy(),
156 }
157
158 var (
159 nodeAvailStatusChartTmpl = collectorapi.Chart{
160 ID: "node_%s_avail_status",
161 Title: "Node Availability Status",
162 Units: "status",
163 Fam: "node status",
164 Ctx: "rabbitmq.node_avail_status",
165 Type: collectorapi.Line,
166 Priority: prioNodeAvailStatus,
167 Dims: collectorapi.Dims{
168 {ID: "node_%s_avail_status_running", Name: "running"},
169 {ID: "node_%s_avail_status_down", Name: "down"},
170 },
171 }
172 nodeNetworkPartitionStatusChartTmpl = collectorapi.Chart{
173 ID: "node_%s_network_partition_status",
174 Title: "Node Network Partitioning Status",
175 Units: "status",
176 Fam: "node status",
177 Ctx: "rabbitmq.node_network_partition_status",
178 Type: collectorapi.Line,
179 Priority: prioNodeNetworkPartitioningStatus,
180 Dims: collectorapi.Dims{
181 {ID: "node_%s_network_partition_status_clear", Name: "clear"},
182 {ID: "node_%s_network_partition_status_detected", Name: "detected"},
183 },
184 }
185 nodeMemAlarmStatusChartTmpl = collectorapi.Chart{
186 ID: "node_%s_mem_alarm_status",
187 Title: "Node Memory Alarm Status",
188 Units: "status",
189 Fam: "node status",
190 Ctx: "rabbitmq.node_mem_alarm_status",
191 Type: collectorapi.Line,
192 Priority: prioNodeMemAlarmStatus,
193 Dims: collectorapi.Dims{
194 {ID: "node_%s_mem_alarm_status_clear", Name: "clear"},
195 {ID: "node_%s_mem_alarm_status_triggered", Name: "triggered"},
196 },
197 }
198 nodeDiskFreeAlarmStatusChartTmpl = collectorapi.Chart{
199 ID: "node_%s_disk_free_alarm_status",
200 Title: "Node Disk Free Alarm Status",
201 Units: "status",
202 Fam: "node status",
203 Ctx: "rabbitmq.node_disk_free_alarm_status",
204 Type: collectorapi.Line,
205 Priority: prioNodeDiskFreeAlarmStatus,
206 Dims: collectorapi.Dims{
207 {ID: "node_%s_disk_free_alarm_status_clear", Name: "clear"},
208 {ID: "node_%s_disk_free_alarm_status_triggered", Name: "triggered"},
209 },
210 }
211 nodeFileDescriptorsUsageChartTmpl = collectorapi.Chart{
212 ID: "node_%s_file_descriptors_usage",
213 Title: "Node File Descriptors Usage",
214 Units: "fd",
215 Fam: "node fds",
216 Ctx: "rabbitmq.node_file_descriptors_usage",
217 Type: collectorapi.Line,
218 Priority: prioNodeFileDescriptorsUsage,
219 Dims: collectorapi.Dims{
220 {ID: "node_%s_fds_used", Name: "used"},
221 },
222 }
223 nodeSocketsUsageChartTmpl = collectorapi.Chart{
224 ID: "node_%s_sockets_used_usage",
225 Title: "Node Sockets Usage",
226 Units: "sockets",
227 Fam: "node sockets",
228 Ctx: "rabbitmq.node_sockets_usage",
229 Type: collectorapi.Line,
230 Priority: prioNodeSocketsUsage,
231 Dims: collectorapi.Dims{
232 {ID: "node_%s_sockets_used", Name: "used"},
233 },
234 }
235 nodeErlangProcessesUsageChartTmpl = collectorapi.Chart{
236 ID: "node_%s_erlang_processes_usage",
237 Title: "Node Erlang Processes Usage",
238 Units: "processes",
239 Fam: "node erlang",
240 Ctx: "rabbitmq.node_erlang_processes_usage",
241 Type: collectorapi.Line,
242 Priority: prioNodeErlangProcessesUsage,
243 Dims: collectorapi.Dims{
244 {ID: "node_%s_procs_used", Name: "used"},
245 },
246 }
247 nodeErlangRunQueueProcessesCountChartTmpl = collectorapi.Chart{
248 ID: "node_%s_erlang_run_queue_processes_count",
249 Title: "Node Erlang Run Queue",
250 Units: "processes",
251 Fam: "node erlang",
252 Ctx: "rabbitmq.node_erlang_run_queue_processes_count",
253 Type: collectorapi.Line,
254 Priority: prioNodeErlangRunQueueProcessesCount,
255 Dims: collectorapi.Dims{
256 {ID: "node_%s_run_queue", Name: "length"},
257 },
258 }
259 nodeMemoryUsageChartTmpl = collectorapi.Chart{
260 ID: "node_%s_memory_usage",
261 Title: "Node Memory Usage",
262 Units: "bytes",
263 Fam: "node mem",
264 Ctx: "rabbitmq.node_memory_usage",
265 Priority: prioNodeMemoryUsage,
266 Type: collectorapi.Area,
267 Dims: collectorapi.Dims{
268 {ID: "node_%s_mem_used", Name: "used"},
269 },
270 }
271 nodeDiskSpaceFreeSizeChartTmpl = collectorapi.Chart{
272 ID: "node_%s_disk_space_free_size",
273 Title: "Node Disk Free Space",
274 Units: "bytes",
275 Fam: "node disk",
276 Ctx: "rabbitmq.node_disk_space_free_size",
277 Type: collectorapi.Area,
278 Priority: prioNodeDiskSpaceFreeSize,
279 Dims: collectorapi.Dims{
280 {ID: "node_%s_disk_free_bytes", Name: "free"},
281 },
282 }
283 nodeUptimeChartTmpl = collectorapi.Chart{
284 ID: "node_%s_uptime",
285 Title: "Node Uptime",
286 Units: "seconds",
287 Fam: "node uptime",
288 Ctx: "rabbitmq.node_uptime",
289 Type: collectorapi.Line,
290 Priority: prioNodeUptime,
291 Dims: collectorapi.Dims{
292 {ID: "node_%s_uptime", Name: "uptime"},
293 },
294 }
295 )
296
297 var nodeClusterPeerChartsTmpl = collectorapi.Charts{
298 nodeClusterLinkPeerTrafficChartTmpl.Copy(),
299 }
300
301 var (
302 nodeClusterLinkPeerTrafficChartTmpl = collectorapi.Chart{
303 ID: "node_%s_peer_%s_cluster_link_traffic",
304 Title: "Node Cluster Link Peer Traffic",
305 Units: "bytes/s",
306 Fam: "node cluster link",
307 Ctx: "rabbitmq.node_peer_cluster_link_traffic",
308 Type: collectorapi.Area,
309 Priority: prioNodeClusterLinkPeerTraffic,
310 Dims: collectorapi.Dims{
311 {ID: "node_%s_peer_%s_cluster_link_recv_bytes", Name: "received", Algo: collectorapi.Incremental},
312 {ID: "node_%s_peer_%s_cluster_link_send_bytes", Name: "sent", Mul: -1, Algo: collectorapi.Incremental},
313 },
314 }
315 )
316
317 var vhostChartsTmpl = collectorapi.Charts{
318 vhostStatusChartTmpl.Copy(),
319 vhostMessageCountChartTmpl.Copy(),
320 vhostMessagesRateChartTmpl.Copy(),
321 }
322
323 var (
324 vhostStatusChartTmpl = collectorapi.Chart{
325 ID: "vhost_%s_status",
326 Title: "Vhost Status",
327 Units: "status",
328 Fam: "vhost status",
329 Ctx: "rabbitmq.vhost_status",
330 Type: collectorapi.Line,
331 Priority: prioVhostStatus,
332 Dims: collectorapi.Dims{
333 {ID: "vhost_%s_status_running", Name: "running"},
334 {ID: "vhost_%s_status_stopped", Name: "stopped"},
335 {ID: "vhost_%s_status_partial", Name: "partial"},
336 },
337 }
338 vhostMessageCountChartTmpl = collectorapi.Chart{
339 ID: "vhost_%s_message_count",
340 Title: "Vhost messages",
341 Units: "messages",
342 Fam: "vhost messages",
343 Ctx: "rabbitmq.vhost_messages_count",
344 Type: collectorapi.Stacked,
345 Priority: prioVhostMessagesCount,
346 Dims: collectorapi.Dims{
347 {ID: "vhost_%s_messages_ready", Name: "ready"},
348 {ID: "vhost_%s_messages_unacknowledged", Name: "unacknowledged"},
349 },
350 }
351 vhostMessagesRateChartTmpl = collectorapi.Chart{
352 ID: "vhost_%s_message_stats",
353 Title: "Vhost messages rate",
354 Units: "messages/s",
355 Fam: "vhost messages",
356 Ctx: "rabbitmq.vhost_messages_rate",
357 Type: collectorapi.Stacked,
358 Priority: prioVhostMessagesRate,
359 Dims: collectorapi.Dims{
360 {ID: "vhost_%s_message_stats_ack", Name: "ack", Algo: collectorapi.Incremental},
361 {ID: "vhost_%s_message_stats_confirm", Name: "confirm", Algo: collectorapi.Incremental},
362 {ID: "vhost_%s_message_stats_deliver", Name: "deliver", Algo: collectorapi.Incremental},
363 {ID: "vhost_%s_message_stats_get", Name: "get", Algo: collectorapi.Incremental},
364 {ID: "vhost_%s_message_stats_get_no_ack", Name: "get_no_ack", Algo: collectorapi.Incremental},
365 {ID: "vhost_%s_message_stats_publish", Name: "publish", Algo: collectorapi.Incremental},
366 {ID: "vhost_%s_message_stats_redeliver", Name: "redeliver", Algo: collectorapi.Incremental},
367 {ID: "vhost_%s_message_stats_return_unroutable", Name: "return_unroutable", Algo: collectorapi.Incremental},
368 },
369 }
370 )
371
372 var queueChartsTmpl = collectorapi.Charts{
373 queueStatusChartTmpl.Copy(),
374 queueMessagesCountChartTmpl.Copy(),
375 queueMessagesRateChartTmpl.Copy(),
376 }
377
378 var (
379 queueStatusChartTmpl = collectorapi.Chart{
380 ID: "queue_%s_vhost_%s_node_%s_status",
381 Title: "Queue status",
382 Units: "status",
383 Fam: "queue status",
384 Ctx: "rabbitmq.queue_status",
385 Type: collectorapi.Line,
386 Priority: prioQueueStatus,
387 Dims: collectorapi.Dims{
388 {ID: "queue_%s_vhost_%s_node_%s_status_running", Name: "running"},
389 {ID: "queue_%s_vhost_%s_node_%s_status_down", Name: "down"},
390 {ID: "queue_%s_vhost_%s_node_%s_status_idle", Name: "idle"},
391 {ID: "queue_%s_vhost_%s_node_%s_status_crashed", Name: "crashed"},
392 {ID: "queue_%s_vhost_%s_node_%s_status_stopped", Name: "stopped"},
393 {ID: "queue_%s_vhost_%s_node_%s_status_minority", Name: "minority"},
394 {ID: "queue_%s_vhost_%s_node_%s_status_terminated", Name: "terminated"},
395 },
396 }
397 queueMessagesCountChartTmpl = collectorapi.Chart{
398 ID: "queue_%s_vhost_%s_node_%s_message_count",
399 Title: "Queue messages",
400 Units: "messages",
401 Fam: "queue messages",
402 Ctx: "rabbitmq.queue_messages_count",
403 Type: collectorapi.Stacked,
404 Priority: prioQueueMessagesCount,
405 Dims: collectorapi.Dims{
406 {ID: "queue_%s_vhost_%s_node_%s_messages_ready", Name: "ready"},
407 {ID: "queue_%s_vhost_%s_node_%s_messages_unacknowledged", Name: "unacknowledged"},
408 {ID: "queue_%s_vhost_%s_node_%s_messages_paged_out", Name: "paged_out"},
409 {ID: "queue_%s_vhost_%s_node_%s_messages_persistent", Name: "persistent"},
410 },
411 }
412 queueMessagesRateChartTmpl = collectorapi.Chart{
413 ID: "queue_%s_vhost_%s_node_%s_message_stats",
414 Title: "Queue messages rate",
415 Units: "messages/s",
416 Fam: "queue messages",
417 Ctx: "rabbitmq.queue_messages_rate",
418 Type: collectorapi.Stacked,
419 Priority: prioQueueMessagesRate,
420 Dims: collectorapi.Dims{
421 {ID: "queue_%s_vhost_%s_node_%s_message_stats_ack", Name: "ack", Algo: collectorapi.Incremental},
422 {ID: "queue_%s_vhost_%s_node_%s_message_stats_confirm", Name: "confirm", Algo: collectorapi.Incremental},
423 {ID: "queue_%s_vhost_%s_node_%s_message_stats_deliver", Name: "deliver", Algo: collectorapi.Incremental},
424 {ID: "queue_%s_vhost_%s_node_%s_message_stats_get", Name: "get", Algo: collectorapi.Incremental},
425 {ID: "queue_%s_vhost_%s_node_%s_message_stats_get_no_ack", Name: "get_no_ack", Algo: collectorapi.Incremental},
426 {ID: "queue_%s_vhost_%s_node_%s_message_stats_publish", Name: "publish", Algo: collectorapi.Incremental},
427 {ID: "queue_%s_vhost_%s_node_%s_message_stats_redeliver", Name: "redeliver", Algo: collectorapi.Incremental},
428 {ID: "queue_%s_vhost_%s_node_%s_message_stats_return_unroutable", Name: "return_unroutable", Algo: collectorapi.Incremental},
429 },
430 }
431 )
432
433 func (c *Collector) updateCharts() {
434 if !c.cache.overview.hasCharts {
435 c.cache.overview.hasCharts = true
436 c.addOverviewCharts()
437 }
438
439 maps.DeleteFunc(c.cache.nodes, func(_ string, node *nodeCacheItem) bool {
440 if !node.seen {
441 c.removeNodeCharts(node)
442 return true
443 }
444 if !node.hasCharts {
445 node.hasCharts = true
446 c.addNodeCharts(node)
447 }
448 maps.DeleteFunc(node.peers, func(_ string, peer *peerCacheItem) bool {
449 if !peer.seen {
450 c.removeNodeClusterPeerCharts(peer)
451 return true
452 }
453 if !peer.hasCharts {
454 peer.hasCharts = true
455 c.addNodeClusterPeerCharts(peer)
456 }
457 return false
458 })
459 return false
460 })
461
462 maps.DeleteFunc(c.cache.vhosts, func(_ string, vhost *vhostCacheItem) bool {
463 if !vhost.seen {
464 c.removeVhostCharts(vhost)
465 return true
466 }
467 if !vhost.hasCharts {
468 vhost.hasCharts = true
469 c.addVhostCharts(vhost)
470 }
471 return false
472 })
473
474 maps.DeleteFunc(c.cache.queues, func(_ string, queue *queueCacheItem) bool {
475 if !queue.seen {
476 c.removeQueueCharts(queue)
477 return true
478 }
479 if !queue.hasCharts {
480 queue.hasCharts = true
481 c.addQueueCharts(queue)
482 }
483 return false
484 })
485 }
486
487 func (c *Collector) addOverviewCharts() {
488 charts := overviewCharts.Copy()
489
490 for _, chart := range *charts {
491 chart.Labels = []collectorapi.Label{
492 {Key: "cluster_id", Value: c.clusterId},
493 {Key: "cluster_name", Value: c.clusterName},
494 }
495 }
496
497 if err := c.Charts().Add(*charts...); err != nil {
498 c.Warningf("failed to add overview charts: %v", err)
499 }
500 }
501
502 func (c *Collector) addNodeCharts(node *nodeCacheItem) {
503 charts := nodeChartsTmpl.Copy()
504
505 for _, chart := range *charts {
506 chart.ID = cleanChartId(fmt.Sprintf(chart.ID, node.name))
507 chart.Labels = []collectorapi.Label{
508 {Key: "cluster_id", Value: c.clusterId},
509 {Key: "cluster_name", Value: c.clusterName},
510 {Key: "node", Value: node.name},
511 }
512 for _, dim := range chart.Dims {
513 dim.ID = fmt.Sprintf(dim.ID, node.name)
514 }
515 }
516
517 if err := c.Charts().Add(*charts...); err != nil {
518 c.Warningf("failed to add node charts: %v", err)
519 }
520 }
521
522 func (c *Collector) removeNodeCharts(node *nodeCacheItem) {
523 px := fmt.Sprintf("node_%s_", node.name)
524 c.removeCharts(px)
525 }
526
527 func (c *Collector) addNodeClusterPeerCharts(peer *peerCacheItem) {
528 charts := nodeClusterPeerChartsTmpl.Copy()
529
530 for _, chart := range *charts {
531 chart.ID = cleanChartId(fmt.Sprintf(chart.ID, peer.node, peer.name))
532 chart.Labels = []collectorapi.Label{
533 {Key: "cluster_id", Value: c.clusterId},
534 {Key: "cluster_name", Value: c.clusterName},
535 {Key: "node", Value: peer.node},
536 {Key: "peer", Value: peer.name},
537 }
538 for _, dim := range chart.Dims {
539 dim.ID = fmt.Sprintf(dim.ID, peer.node, peer.name)
540 }
541 }
542
543 if err := c.Charts().Add(*charts...); err != nil {
544 c.Warningf("failed to add node cluster peer charts: %v", err)
545 }
546
547 }
548
549 func (c *Collector) removeNodeClusterPeerCharts(peer *peerCacheItem) {
550 px := fmt.Sprintf("node_%s_peer_%s_", peer.node, peer.name)
551 c.removeCharts(px)
552 }
553
554 func (c *Collector) addVhostCharts(vhost *vhostCacheItem) {
555 charts := vhostChartsTmpl.Copy()
556
557 for _, chart := range *charts {
558 chart.ID = cleanChartId(fmt.Sprintf(chart.ID, vhost.name))
559 chart.Labels = []collectorapi.Label{
560 {Key: "cluster_id", Value: c.clusterId},
561 {Key: "cluster_name", Value: c.clusterName},
562 {Key: "vhost", Value: vhost.name},
563 }
564 for _, dim := range chart.Dims {
565 dim.ID = fmt.Sprintf(dim.ID, vhost.name)
566 }
567 }
568
569 if err := c.Charts().Add(*charts...); err != nil {
570 c.Warningf("failed to add vhost charts: %v", err)
571 }
572 }
573
574 func (c *Collector) removeVhostCharts(vhost *vhostCacheItem) {
575 px := fmt.Sprintf("vhost_%s_", vhost.name)
576 c.removeCharts(px)
577 }
578
579 func (c *Collector) addQueueCharts(q *queueCacheItem) {
580 charts := queueChartsTmpl.Copy()
581
582 for _, chart := range *charts {
583 chart.ID = fmt.Sprintf(chart.ID, q.name, q.vhost, q.node)
584 chart.ID = cleanChartId(chart.ID)
585 chart.Labels = []collectorapi.Label{
586 {Key: "cluster_id", Value: c.clusterId},
587 {Key: "cluster_name", Value: c.clusterName},
588 {Key: "node", Value: q.node},
589 {Key: "queue", Value: q.name},
590 {Key: "vhost", Value: q.vhost},
591 {Key: "type", Value: q.typ},
592 }
593 for _, dim := range chart.Dims {
594 dim.ID = fmt.Sprintf(dim.ID, q.name, q.vhost, q.node)
595 }
596 }
597
598 if err := c.Charts().Add(*charts...); err != nil {
599 c.Warning(err)
600 }
601 }
602
603 func (c *Collector) removeQueueCharts(q *queueCacheItem) {
604 px := fmt.Sprintf("queue_%s_vhost_%s_node_%s_", q.name, q.vhost, q.node)
605 c.removeCharts(px)
606 }
607
608 func (c *Collector) removeCharts(prefix string) {
609 prefix = cleanChartId(prefix)
610 for _, chart := range *c.Charts() {
611 if strings.HasPrefix(chart.ID, prefix) {
612 chart.MarkRemove()
613 chart.MarkNotCreated()
614 }
615 }
616 }
617
618 func cleanChartId(id string) string {
619 r := strings.NewReplacer(" ", "_", ".", "_")
620 return r.Replace(id)
621 }