@cryptotaxi247 / netdata-1 / commits / 52db45930

Add per queue charts in rabbitmq.chart.py (#10064)

zarak committed Oct 20, 2020 at 10:58 UTC 52db45930be11709df9ce945dd7940c99121ab5a
4 files changed +153
collectors/python.d.plugin/rabbitmq/README.md
+21
@@ -69,6 +69,27 @@ Per Vhost charts:
69 - redeliver
70 - return_unroutable
71
72 +2. Per Queue charts:
73 +
74 + 1. **Queued Messages**
75 +
76 + - messages
77 + - paged_out
78 + - persistent
79 + - ready
80 + - unacknowledged
81 +
82 + 2. **Queue Messages stats**
83 +
84 + - ack
85 + - confirm
86 + - deliver
87 + - get
88 + - get_no_ack
89 + - publish
90 + - redeliver
91 + - return_unroutable
92 +
93 ## Configuration
94
95 Edit the `python.d/rabbitmq.conf` configuration file using `edit-config` from the your agent's [config
collectors/python.d.plugin/rabbitmq/rabbitmq.chart.py
+116
@@ -9,6 +9,7 @@ from bases.FrameworkServices.UrlService import UrlService
9
10 API_NODE = 'api/nodes'
11 API_OVERVIEW = 'api/overview'
12 +API_QUEUES = 'api/queues'
13 API_VHOSTS = 'api/vhosts'
14
15 NODE_STATS = [
@@ -41,6 +42,22 @@ OVERVIEW_STATS = [
42 'churn_rates.queue_deleted_details.rate'
43 ]
44
45 +QUEUE_STATS = [
46 + 'messages',
47 + 'messages_paged_out',
48 + 'messages_persistent',
49 + 'messages_ready',
50 + 'messages_unacknowledged',
51 + 'message_stats.ack',
52 + 'message_stats.confirm',
53 + 'message_stats.deliver',
54 + 'message_stats.get',
55 + 'message_stats.get_no_ack',
56 + 'message_stats.publish',
57 + 'message_stats.redeliver',
58 + 'message_stats.return_unroutable',
59 +]
60 +
61 VHOST_MESSAGE_STATS = [
62 'message_stats.ack',
63 'message_stats.confirm',
@@ -180,6 +197,44 @@ def vhost_chart_template(name):
197
198 return order, charts
199
200 +def queue_chart_template(queue_id):
201 + vhost, name = queue_id
202 + order = [
203 + 'vhost_{0}_queue_{1}_queued_message'.format(vhost, name),
204 + 'vhost_{0}_queue_{1}_messages_stats'.format(vhost, name),
205 + ]
206 + family = 'vhost {0}'.format(vhost)
207 +
208 + charts = {
209 + order[0]: {
210 + 'options': [
211 + None, 'Queue "{0}" in "{1}" queued messages'.format(name, vhost), 'messages', family, 'rabbitmq.queue_messages', 'line'],
212 + 'lines': [
213 + ['vhost_{0}_queue_{1}_messages'.format(vhost, name), 'messages', 'absolute'],
214 + ['vhost_{0}_queue_{1}_messages_paged_out'.format(vhost, name), 'paged_out', 'absolute'],
215 + ['vhost_{0}_queue_{1}_messages_persistent'.format(vhost, name), 'persistent', 'absolute'],
216 + ['vhost_{0}_queue_{1}_messages_ready'.format(vhost, name), 'ready', 'absolute'],
217 + ['vhost_{0}_queue_{1}_messages_unacknowledged'.format(vhost, name), 'unack', 'absolute'],
218 + ]
219 + },
220 + order[1]: {
221 + 'options': [
222 + None, 'Queue "{0}" in "{1}" messages stats'.format(name, vhost), 'messages/s', family, 'rabbitmq.queue_messages_stats', 'line'],
223 + 'lines': [
224 + ['vhost_{0}_queue_{1}_message_stats_ack'.format(vhost, name), 'ack', 'incremental'],
225 + ['vhost_{0}_queue_{1}_message_stats_confirm'.format(vhost, name), 'confirm', 'incremental'],
226 + ['vhost_{0}_queue_{1}_message_stats_deliver'.format(vhost, name), 'deliver', 'incremental'],
227 + ['vhost_{0}_queue_{1}_message_stats_get'.format(vhost, name), 'get', 'incremental'],
228 + ['vhost_{0}_queue_{1}_message_stats_get_no_ack'.format(vhost, name), 'get_no_ack', 'incremental'],
229 + ['vhost_{0}_queue_{1}_message_stats_publish'.format(vhost, name), 'publish', 'incremental'],
230 + ['vhost_{0}_queue_{1}_message_stats_redeliver'.format(vhost, name), 'redeliver', 'incremental'],
231 + ['vhost_{0}_queue_{1}_message_stats_return_unroutable'.format(vhost, name), 'return_unroutable', 'incremental'],
232 + ]
233 + },
234 + }
235 +
236 + return order, charts
237 +
238
239 class VhostStatsBuilder:
240 def __init__(self):
@@ -199,6 +254,21 @@ class VhostStatsBuilder:
254 stats = fetch_data(raw_data=self.stats, metrics=VHOST_MESSAGE_STATS)
255 return dict(('vhost_{0}_{1}'.format(name, k), v) for k, v in stats.items())
256
257 +class QueueStatsBuilder:
258 + def __init__(self):
259 + self.stats = None
260 +
261 + def set(self, raw_stats):
262 + self.stats = raw_stats
263 +
264 + def id(self):
265 + return self.stats['vhost'], self.stats['name']
266 +
267 + def queue_stats(self):
268 + vhost, name = self.id()
269 + stats = fetch_data(raw_data=self.stats, metrics=QUEUE_STATS)
270 + return dict(('vhost_{0}_queue_{1}_{2}'.format(vhost, name, k), v) for k, v in stats.items())
271 +
272
273 class Service(UrlService):
274 def __init__(self, configuration=None, name=None):
@@ -213,6 +283,11 @@ class Service(UrlService):
283 self.node_name = str()
284 self.vhost = VhostStatsBuilder()
285 self.collected_vhosts = set()
286 + self.collect_queues_metrics = configuration.get('collect_queues_metrics', False)
287 + self.debug("collect_queues_metrics is {0}".format("enabled" if self.collect_queues_metrics else "disabled"))
288 + if self.collect_queues_metrics:
289 + self.queue = QueueStatsBuilder()
290 + self.collected_queues = set()
291
292 def _get_data(self):
293 data = dict()
@@ -233,6 +308,11 @@ class Service(UrlService):
308 if stats:
309 data.update(stats)
310
311 + if self.collect_queues_metrics:
312 + stats = self.get_queues_stats()
313 + if stats:
314 + data.update(stats)
315 +
316 return data or None
317
318 def get_overview_stats(self):
@@ -292,6 +372,31 @@ class Service(UrlService):
372 self.debug("number of vhosts: {0}, metrics: {1}".format(len(vhosts), len(data)))
373 return data
374
375 + def get_queues_stats(self):
376 + url = '{0}/{1}'.format(self.url, API_QUEUES)
377 + self.debug("doing http request to '{0}'".format(url))
378 + raw = self._get_raw_data(url)
379 + if not raw:
380 + return None
381 +
382 + data = dict()
383 + queues = loads(raw)
384 + charts_initialized = len(self.charts) > 0
385 +
386 + for queue in queues:
387 + self.queue.set(queue)
388 + if self.queue.id()[0] not in self.collected_vhosts:
389 + continue
390 +
391 + if charts_initialized and self.queue.id() not in self.collected_queues:
392 + self.collected_queues.add(self.queue.id())
393 + self.add_queue_charts(self.queue.id())
394 +
395 + data.update(self.queue.queue_stats())
396 +
397 + self.debug("number of queues: {0}, metrics: {1}".format(len(queues), len(data)))
398 + return data
399 +
400 def add_vhost_charts(self, vhost_name):
401 order, charts = vhost_chart_template(vhost_name)
402
@@ -303,6 +408,17 @@ class Service(UrlService):
408 for dimension in dimensions:
409 new_chart.add_dimension(dimension)
410
411 + def add_queue_charts(self, queue_id):
412 + order, charts = queue_chart_template(queue_id)
413 +
414 + for chart_name in order:
415 + params = [chart_name] + charts[chart_name]['options']
416 + dimensions = charts[chart_name]['lines']
417 +
418 + new_chart = self.charts.add_chart(params)
419 + for dimension in dimensions:
420 + new_chart.add_dimension(dimension)
421 +
422
423 def fetch_data(raw_data, metrics):
424 data = dict()
collectors/python.d.plugin/rabbitmq/rabbitmq.conf
+6
@@ -70,6 +70,12 @@
70 # user: 'username'
71 # pass: 'password'
72 #
73 +# Rabbitmq plugin can also collect stats per vhost per queues, which is disabled
74 +# by default. Please note that enabling this can induced a serious overhead on
75 +# both netdata and rabbitmq if a look of queues are configured and used.
76 +#
77 +# collect_queues_metrics: 'yes/no'
78 +#
79 # ----------------------------------------------------------------------
80 # AUTO-DETECTION JOBS
81 # only one of them will run (they have the same name)
web/gui/dashboard_info.js
+10
@@ -2539,6 +2539,16 @@ netdataDashboard.context = {
2539 colors: NETDATA.colors[3]
2540 },
2541
2542 + 'rabbitmq.queue_messages': {
2543 + info: 'Total amount of messages and their states in this queue.',
2544 + colors: NETDATA.colors[3]
2545 + },
2546 +
2547 + 'rabbitmq.queue_messages_stats': {
2548 + info: 'Overall messaging rates including acknowledgements, delieveries, redeliveries, and publishes.',
2549 + colors: NETDATA.colors[3]
2550 + },
2551 +
2552 // ------------------------------------------------------------------------
2553 // ntpd
2554