diff --git a/deps/rabbitmq_management/priv/www/doc/stats.html b/deps/rabbitmq_management/priv/www/doc/stats.html index 6df64004f5..bd6a42c603 100644 --- a/deps/rabbitmq_management/priv/www/doc/stats.html +++ b/deps/rabbitmq_management/priv/www/doc/stats.html @@ -532,6 +532,82 @@ List of network partitions this node is seeing. + + persister_read_avg_time + + Average wall time (milliseconds) for each disk read operation in + the last statistics interval. + + + + persister_read_bytes + + Total number of bytes read from disk by the persister. + + + + persister_read_count + + Total number of read operations by the persister. + + + + persister_reopen_count + + Total number of times the persister has needed to recycle + file handles between queues. In an ideal world this number + will be zero; if the number is large, performance might be + improved by increasing the number of file handles available + to RabbitMQ. + + + + persister_seek_avg_time + + Average wall time (milliseconds) for each seek operation in + the last statistics interval. + + + + + persister_seek_count + + Total number of seek operations by the persister. + + + + persister_sync_avg_time + + Average wall time (milliseconds) for each fsync() operation in + the last statistics interval. + + + + + persister_sync_count + + Total number of fsync() operations by the persister. + + + + persister_write_avg_time + + Average wall time (milliseconds) for each disk write operation in + the last statistics interval. + + + + persister_write_bytes + + Total number of bytes written to disk by the persister. + + + + persister_write_count + + Total number of write operations by the persister. + + proc_total diff --git a/deps/rabbitmq_management/priv/www/js/charts.js b/deps/rabbitmq_management/priv/www/js/charts.js index 6fa177d6c0..afe7cee6a2 100644 --- a/deps/rabbitmq_management/priv/www/js/charts.js +++ b/deps/rabbitmq_management/priv/www/js/charts.js @@ -12,22 +12,22 @@ function message_rates(id, stats) { ['Get', 'get'], ['Deliver (noack)', 'deliver_no_ack'], ['Get (noack)', 'get_no_ack'], ['Return', 'return_unroutable']]; - return rates_chart_or_text(id, stats, items, fmt_rate, fmt_rate_large, fmt_rate_axis, true, 'Message rates', 'message-rates'); + return rates_chart_or_text(id, stats, items, fmt_rate, fmt_rate_axis, true, 'Message rates', 'message-rates'); } function queue_lengths(id, stats) { var items = [['Ready', 'messages_ready'], ['Unacked', 'messages_unacknowledged'], ['Total', 'messages']]; - return rates_chart_or_text(id, stats, items, fmt_msgs, fmt_msgs_large, fmt_num_axis, false, 'Queued messages', 'queued-messages'); + return rates_chart_or_text(id, stats, items, fmt_num_thousands, fmt_plain_axis, false, 'Queued messages', 'queued-messages'); } function data_rates(id, stats) { var items = [['From client', 'recv_oct'], ['To client', 'send_oct']]; - return rates_chart_or_text(id, stats, items, fmt_rate_bytes, fmt_rate_bytes_large, fmt_rate_bytes_axis, true, 'Data rates'); + return rates_chart_or_text(id, stats, items, fmt_rate_bytes, fmt_rate_bytes_axis, true, 'Data rates'); } -function rates_chart_or_text(id, stats, items, chart_fmt, text_fmt, axis_fmt, chart_rates, +function rates_chart_or_text(id, stats, items, fmt, axis_fmt, chart_rates, heading, heading_help) { var mode = get_pref('rate-mode-' + id); var range = get_pref('chart-range'); @@ -37,10 +37,10 @@ function rates_chart_or_text(id, stats, items, chart_fmt, text_fmt, axis_fmt, ch if (keys(stats).length > 0) { if (mode == 'chart') { res = rates_chart( - id, id, items, stats, chart_fmt, axis_fmt, 'full', chart_rates); + id, id, items, stats, fmt, axis_fmt, 'full', chart_rates); } else { - res = rates_text(items, stats, mode, text_fmt); + res = rates_text(items, stats, mode, fmt, chart_rates); } if (res == "") res = '

Waiting for data...

'; } @@ -79,7 +79,7 @@ function node_stat_count(used_key, limit_key, stats, thresholds) { var limit = stats[limit_key]; if (typeof used == 'number') { return node_stat(used_key, 'Used', limit_key, 'available', stats, - fmt_num_obj, fmt_num_axis, + fmt_plain, fmt_plain_axis, fmt_color(used / limit, thresholds)); } else { return used; @@ -91,19 +91,20 @@ function node_stat_count_bar(used_key, limit_key, stats, thresholds) { var limit = stats[limit_key]; if (typeof used == 'number') { return node_stat_bar(used_key, limit_key, 'available', stats, - fmt_num_axis, fmt_color(used / limit, thresholds)); + fmt_plain_axis, + fmt_color(used / limit, thresholds)); } else { return used; } } -function node_stat(used_key, used_name, limit_key, suffix, stats, rate_fmt, +function node_stat(used_key, used_name, limit_key, suffix, stats, fmt, axis_fmt, colour, help, invert) { if (get_pref('rate-mode-node-stats') == 'chart') { var items = [[used_name, used_key], ['Limit', limit_key]]; add_fake_limit_details(used_key, limit_key, stats); return rates_chart('node-stats', 'node-stats-' + used_key, items, stats, - rate_fmt, axis_fmt, 'node', false); + fmt, axis_fmt, 'node', false); } else { return node_stat_bar(used_key, limit_key, suffix, stats, axis_fmt, colour, help, invert); @@ -156,7 +157,7 @@ function node_stats_prefs() { return chart_h3('node-stats', 'Node statistics'); } -function rates_chart(type_id, id, items, stats, rate_fmt, axis_fmt, type, +function rates_chart(type_id, id, items, stats, fmt, axis_fmt, type, chart_rates) { function show(key) { return get_pref('chart-line-' + id + key) === 'true'; @@ -177,9 +178,11 @@ function rates_chart(type_id, id, items, stats, rate_fmt, axis_fmt, type, chart_data[id]['data'][name] = stats[key_details]; chart_data[id]['data'][name].ix = ix; } + var value = chart_rates ? pick_rate(fmt, stats, key) : + pick_abs(fmt, stats, key); legend.push({name: name, key: key, - value: rate_fmt(stats, key), + value: value, show: show(key)}); ix++; } @@ -201,7 +204,7 @@ function rates_chart(type_id, id, items, stats, rate_fmt, axis_fmt, type, return legend.length > 0 ? html : ''; } -function rates_text(items, stats, mode, rate_fmt) { +function rates_text(items, stats, mode, fmt, chart_rates) { var res = ''; for (var i in items) { var name = items[i][0]; @@ -209,9 +212,10 @@ function rates_text(items, stats, mode, rate_fmt) { var key_details = key + '_details'; if (key_details in stats) { var details = stats[key_details]; - res += '
' + name; - res += rate_fmt(stats, key, mode); - res += '
'; + res += '
' + name + ''; + res += chart_rates ? pick_rate(fmt, stats, key, mode) : + pick_abs(fmt, stats, key, mode); + res += '
'; } } return res == '' ? '' : '
' + res + '
'; diff --git a/deps/rabbitmq_management/priv/www/js/formatters.js b/deps/rabbitmq_management/priv/www/js/formatters.js index b076a73afe..8528f4b2c5 100644 --- a/deps/rabbitmq_management/priv/www/js/formatters.js +++ b/deps/rabbitmq_management/priv/www/js/formatters.js @@ -12,11 +12,6 @@ function fmt_string(str, unknown) { return fmt_escape_html("" + str); } -function fmt_bytes(bytes) { - if (bytes == undefined) return UNKNOWN_REPR; - return fmt_si_prefix(bytes, bytes, 1024, false) + 'B'; -} - function fmt_si_prefix(num0, max0, thousand, allow_fractions) { if (num == 0) return 0; @@ -228,71 +223,51 @@ function fmt_percent(num) { } } -function fmt_rate(obj, name, mode) { - var raw = fmt_rate0(obj, name, mode, fmt_rate_num); - return raw == '' ? '' : (raw + '/s'); -} - -function fmt_rate_bytes(obj, name, mode) { - var raw = fmt_rate0(obj, name, mode, fmt_bytes); - return raw == '' ? '' : (raw + '/s' + - '(' + fmt_bytes(obj[name]) + ' total)'); -} - -function fmt_bytes_obj(obj, name, mode) { - return fmt_bytes(obj[name]); -} - -function fmt_num_obj(obj, name, mode) { - return obj[name]; -} - -function fmt_rate_large(obj, name, mode) { - return '' + fmt_rate0(obj, name, mode, fmt_rate_num) + - 'msg/s'; -} - -function fmt_rate_bytes_large(obj, name, mode) { - return '' + fmt_rate0(obj, name, mode, fmt_bytes) + '/s' + - '(' + fmt_bytes(obj[name]) + ' total)'; -} - -function fmt_rate0(obj, name, mode, fmt) { +function pick_rate(fmt, obj, name, mode) { if (obj == undefined || obj[name] == undefined || obj[name + '_details'] == undefined) return ''; var details = obj[name + '_details']; return fmt(mode == 'avg' ? details.avg_rate : details.rate); } -function fmt_msgs(obj, name, mode) { - return fmt_msgs0(obj, name, mode) + ' msg'; -} - -function fmt_msgs_large(obj, name, mode) { - return '' + fmt_msgs0(obj, name, mode) + '' + - fmt_rate0(obj, name, mode, fmt_msgs_rate); -} - -function fmt_msgs0(obj, name, mode) { +function pick_abs(fmt, obj, name, mode) { if (obj == undefined || obj[name] == undefined || obj[name + '_details'] == undefined) return ''; var details = obj[name + '_details']; - return mode == 'avg' ? fmt_rate_num(details.avg) : - fmt_num_thousands(obj[name]); + return fmt(mode == 'avg' ? details.avg : obj[name]); } -function fmt_msgs_rate(num) { - if (num > 0) return '+' + fmt_rate_num(num) + ' msg/s'; - else if (num < 0) return '-' + fmt_rate_num(-num) + ' msg/s'; - else return ' '; +function fmt_detail_rate(obj, name, mode) { + return pick_rate(fmt_rate, name, mode); +} + +function fmt_detail_rate_bytes(obj, name, mode) { + return pick_rate(fmt_rate_bytes, name, mode); +} + +// --------------------------------------------------------------------- + +// These are pluggable for charts etc + +function fmt_plain(num) { + return num; +} + +function fmt_plain_axis(num, max) { + return fmt_si_prefix(num, max, 1000, true); +} + +function fmt_rate(num) { + return fmt_rate_num(num) + '/s'; } function fmt_rate_axis(num, max) { - return fmt_si_prefix(num, max, 1000, true) + '/s'; + return fmt_plain_axis(num, max) + '/s'; } -function fmt_num_axis(num, max) { - return fmt_si_prefix(num, max, 1000, true); +function fmt_bytes(bytes) { + if (bytes == undefined) return UNKNOWN_REPR; + return fmt_si_prefix(bytes, bytes, 1024, false) + 'B'; } function fmt_bytes_axis(num, max) { @@ -300,11 +275,20 @@ function fmt_bytes_axis(num, max) { return fmt_bytes(isNaN(num) ? 0 : num); } +function fmt_rate_bytes(num) { + return fmt_bytes(num) + '/s'; +} function fmt_rate_bytes_axis(num, max) { return fmt_bytes_axis(num, max) + '/s'; } +function fmt_ms(num) { + return fmt_rate_num(num) + 'ms'; +} + +// --------------------------------------------------------------------- + function fmt_maybe_vhost(name) { return vhosts_interesting ? ' in virtual host ' + fmt_escape_html(name) + '' diff --git a/deps/rabbitmq_management/priv/www/js/global.js b/deps/rabbitmq_management/priv/www/js/global.js index d60602ca42..a1612fb52f 100644 --- a/deps/rabbitmq_management/priv/www/js/global.js +++ b/deps/rabbitmq_management/priv/www/js/global.js @@ -137,6 +137,7 @@ var COLUMNS = // All these are to do with hiding UI elements if var rates_mode; // ...there are no fine stats var user_administrator; // ...user is not an admin +var user_policymaker; // ...user is not a policymaker var user_monitor; // ...user cannot monitor var nodes_interesting; // ...we are not in a cluster var vhosts_interesting; // ...there is only one vhost @@ -164,6 +165,7 @@ function setup_global_vars() { rates_mode = overview.rates_mode; user_tags = expand_user_tags(user.tags.split(",")); user_administrator = jQuery.inArray("administrator", user_tags) != -1; + user_policymaker = jQuery.inArray("policymaker", user_tags) != -1; user_monitor = jQuery.inArray("monitoring", user_tags) != -1; replace_content('login-details', '

User: ' + user.name + '

' + diff --git a/deps/rabbitmq_management/priv/www/js/help.js b/deps/rabbitmq_management/priv/www/js/help.js index 191246bf87..003df912b7 100644 --- a/deps/rabbitmq_management/priv/www/js/help.js +++ b/deps/rabbitmq_management/priv/www/js/help.js @@ -251,6 +251,28 @@ HELP = { 'plugins' : 'Note that only plugins which are both explicitly enabled and running are shown here.', + 'io-operations': + 'Rate of I/O operations. Only operations performed by the message \ + persister are shown here (e.g. metadata changes in Mnesia or writes \ + to the log files are not shown).\ +
\ +
Read
\ +
Rate at which data is read from the disk.
\ +
Write
\ +
Rate at which data is written to the disk.
\ +
Seek
\ +
Rate at which the broker switches position while reading or \ + writing to disk.
\ +
Sync
\ +
Rate at which the broker invokes fsync() to ensure \ + data is flushed to disk.
\ +
Reopen
\ +
Rate at which the broker recycles file handles in order to support \ + more queues than it has file handles. If this operation is occurring \ + frequently you may get a performance boost from increasing the number \ + of file handles available.
\ +
', + 'foo': 'foo' // No comma. }; diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/channels-list.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/channels-list.ejs index 96442b9167..591a7c04b2 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/channels-list.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/channels-list.ejs @@ -167,22 +167,22 @@ <% } %> <% if (rates_mode != 'none') { %> <% if (show_column('channels', 'rate-publish')) { %> - <%= fmt_rate(channel.message_stats, 'publish') %> + <%= fmt_detail_rate(channel.message_stats, 'publish') %> <% } %> <% if (show_column('channels', 'rate-confirm')) { %> - <%= fmt_rate(channel.message_stats, 'confirm') %> + <%= fmt_detail_rate(channel.message_stats, 'confirm') %> <% } %> <% if (show_column('channels', 'rate-return')) { %> - <%= fmt_rate(channel.message_stats, 'return_unroutable') %> + <%= fmt_detail_rate(channel.message_stats, 'return_unroutable') %> <% } %> <% if (show_column('channels', 'rate-deliver')) { %> - <%= fmt_rate(channel.message_stats, 'deliver_get') %> + <%= fmt_detail_rate(channel.message_stats, 'deliver_get') %> <% } %> <% if (show_column('channels', 'rate-redeliver')) { %> - <%= fmt_rate(channel.message_stats, 'redeliver') %> + <%= fmt_detail_rate(channel.message_stats, 'redeliver') %> <% } %> <% if (show_column('channels', 'rate-ack')) { %> - <%= fmt_rate(channel.message_stats, 'ack') %> + <%= fmt_detail_rate(channel.message_stats, 'ack') %> <% } %> <% } %> diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/connections.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/connections.ejs index af5120f814..317328185e 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/connections.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/connections.ejs @@ -115,10 +115,10 @@ <%= fmt_client_name(connection.client_properties) %> <% } %> <% if (show_column('connections', 'from_client')) { %> - <%= fmt_rate_bytes(connection, 'recv_oct') %> + <%= fmt_detail_rate_bytes(connection, 'recv_oct') %> <% } %> <% if (show_column('connections', 'to_client')) { %> - <%= fmt_rate_bytes(connection, 'send_oct') %> + <%= fmt_detail_rate_bytes(connection, 'send_oct') %> <% } %> <% if (show_column('connections', 'heartbeat')) { %> <%= fmt_time(connection.timeout, 's') %> diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs index a6d5c84554..58589d5d6f 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs @@ -64,10 +64,10 @@ <% } %> <% if (rates_mode != 'none') { %> <% if (show_column('exchanges', 'rate-in')) { %> - <%= fmt_rate(exchange.message_stats, 'publish_in') %> + <%= fmt_detail_rate(exchange.message_stats, 'publish_in') %> <% } %> <% if (show_column('exchanges', 'rate-out')) { %> - <%= fmt_rate(exchange.message_stats, 'publish_out') %> + <%= fmt_detail_rate(exchange.message_stats, 'publish_out') %> <% } %> <% } %> diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-deliveries.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-deliveries.ejs index c3ded25e60..ee9e6f6500 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-deliveries.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-deliveries.ejs @@ -20,8 +20,8 @@ <% } else { %> <%= link_queue(del.queue.vhost, del.queue.name) %> <% } %> - <%= fmt_rate(del.stats, 'deliver_get') %> - <%= fmt_rate(del.stats, 'ack') %> + <%= fmt_detail_rate(del.stats, 'deliver_get') %> + <%= fmt_detail_rate(del.stats, 'ack') %> <% } %> diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-publishes.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-publishes.ejs index 0137007a9d..4ea959ac52 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-publishes.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-publishes.ejs @@ -34,9 +34,9 @@ <% } else { %> <%= link_exchange(pub.exchange.vhost, pub.exchange.name) %> <% } %> - <%= fmt_rate(pub.stats, 'publish') %> + <%= fmt_detail_rate(pub.stats, 'publish') %> <% if (col_confirm) { %> - <%= fmt_rate(pub.stats, 'confirm') %> + <%= fmt_detail_rate(pub.stats, 'confirm') %> <% } %> <% } %> diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs index 7842eeb3c5..1ff7b6abc1 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs @@ -60,7 +60,7 @@
-

Statistics

+

Process Statistics

<% if (!node.running) { %>

Node not running

@@ -106,7 +106,7 @@ <% if (node.mem_limit != 'memory_monitoring_disabled') { %> <%= node_stat('mem_used', 'Used', 'mem_limit', 'high watermark', node, - fmt_bytes_obj, fmt_bytes_axis, + fmt_bytes, fmt_bytes_axis, node.mem_alarm ? 'red' : 'green', node.mem_alarm ? 'memory-alarm' : null) %> <% } else { %> @@ -121,7 +121,7 @@ <% if (node.disk_free_limit != 'disk_free_monitoring_disabled') { %> <%= node_stat('disk_free', 'Free', 'disk_free_limit', 'low watermark', node, - fmt_bytes_obj, fmt_bytes_axis, + fmt_bytes, fmt_bytes_axis, node.disk_free_alarm ? 'red' : 'green', node.disk_free_alarm ? 'disk_free-alarm' : null, true) %> @@ -137,6 +137,25 @@
+
+

I/O Statistics

+
+<% if (!node.running) { %> +

Node not running

+<% } else if (node.os_pid == undefined) { %> +

Node statistics not available

+<% } else { %> + <%= rates_chart_or_text('persister-stats-count', node, [['Read', 'persister_read_count'], ['Write', 'persister_write_count'], ['Seek', 'persister_seek_count'], ['Sync', 'persister_sync_count'], ['Reopen', 'persister_reopen_count']], fmt_rate, fmt_rate_axis, true, 'Operations', 'io-operations') %> + + <%= rates_chart_or_text('persister-stats-bytes', node, [['Read', 'persister_read_bytes'], ['Write', 'persister_write_bytes']], fmt_rate_bytes, fmt_rate_bytes_axis, true, 'Data rates') %> + + <%= rates_chart_or_text('persister-stats-time', node, [['Read', 'persister_read_avg_time'], ['Write', 'persister_write_avg_time'], ['Seek', 'persister_seek_avg_time'], ['Sync', 'persister_sync_avg_time']], fmt_ms, fmt_ms, false, 'Average time per operation') %> + +<% } %> +
+
+ +

Memory details

diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs index 272440a061..b43be0c62e 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs @@ -245,6 +245,51 @@
+<% if (user_policymaker) { %> +
+

Move messages

+
+ <% if (NAVIGATION['Admin'][0]['Shovel Management'] == undefined) { %> +

To move messages, the shovel plugin must be enabled, try:

+
$ rabbitmq-plugins enable rabbitmq_shovel rabbitmq_shovel_management
+ <% } else { %> +

+ The shovel plugin can be used to move messages from this queue + to another one. The form below will create a temporary shovel to + move messages to another queue on the same virtual host, with + default settings. +

+

+ For more options see the shovel + interface. +

+
+ + + + + + + + + + + + + + + + + + +
Destination queue:
+ +
+ <% } %> +
+
+<% } %> +

Delete / purge

diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/queues.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/queues.ejs index 3dc65c8e56..3f3b3472cf 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/queues.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/queues.ejs @@ -160,16 +160,16 @@ <% } %> <% if (rates_mode != 'none') { %> <% if (show_column('queues', 'rate-incoming')) { %> - <%= fmt_rate(queue.message_stats, 'publish') %> + <%= fmt_detail_rate(queue.message_stats, 'publish') %> <% } %> <% if (show_column('queues', 'rate-deliver')) { %> - <%= fmt_rate(queue.message_stats, 'deliver_get') %> + <%= fmt_detail_rate(queue.message_stats, 'deliver_get') %> <% } %> <% if (show_column('queues', 'rate-redeliver')) { %> - <%= fmt_rate(queue.message_stats, 'redeliver') %> + <%= fmt_detail_rate(queue.message_stats, 'redeliver') %> <% } %> <% if (show_column('queues', 'rate-ack')) { %> - <%= fmt_rate(queue.message_stats, 'ack') %> + <%= fmt_detail_rate(queue.message_stats, 'ack') %> <% } %> <% } %> diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/vhosts.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/vhosts.ejs index 285af23edd..a6cbe9faf5 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/vhosts.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/vhosts.ejs @@ -64,17 +64,17 @@ <%= fmt_num_thousands(vhost.messages) %> <% } %> <% if (show_column('vhosts', 'from_client')) { %> - <%= fmt_rate_bytes(vhost, 'recv_oct') %> + <%= fmt_detail_rate_bytes(vhost, 'recv_oct') %> <% } %> <% if (show_column('vhosts', 'to_client')) { %> - <%= fmt_rate_bytes(vhost, 'send_oct') %> + <%= fmt_detail_rate_bytes(vhost, 'send_oct') %> <% } %> <% if (rates_mode != 'none') { %> <% if (show_column('vhosts', 'rate-publish')) { %> - <%= fmt_rate(vhost.message_stats, 'publish') %> + <%= fmt_detail_rate(vhost.message_stats, 'publish') %> <% } %> <% if (show_column('vhosts', 'rate-deliver')) { %> - <%= fmt_rate(vhost.message_stats, 'deliver_get') %> + <%= fmt_detail_rate(vhost.message_stats, 'deliver_get') %> <% } %> <% } %> diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_db.erl b/deps/rabbitmq_management/src/rabbit_mgmt_db.erl index 61696883e0..8dd1c4ae1e 100644 --- a/deps/rabbitmq_management/src/rabbit_mgmt_db.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_db.erl @@ -159,7 +159,19 @@ [messages, messages_ready, messages_unacknowledged]). -define(COARSE_NODE_STATS, - [mem_used, fd_used, sockets_used, proc_used, disk_free]). + [mem_used, fd_used, sockets_used, proc_used, disk_free, + persister_read_count, persister_read_bytes, persister_read_avg_time, + persister_write_count, persister_write_bytes, persister_write_avg_time, + persister_sync_count, persister_sync_avg_time, + persister_seek_count, persister_seek_avg_time, + persister_reopen_count]). + +%% Normally 0 and no history means "has never happened, don't +%% report". But for these things we do want to report even at 0 with +%% no history. +-define(ALWAYS_REPORT_STATS, + [persister_read_avg_time, persister_write_avg_time, + persister_sync_avg_time | ?COARSE_QUEUE_STATS]). -define(COARSE_CONN_STATS, [recv_oct, send_oct]). @@ -572,8 +584,10 @@ handle_event(#event{type = consumer_deleted, props = Props}, State) -> %% TODO: we don't clear up after dead nodes here - this is a very tiny %% leak every time a node is permanently removed from the cluster. Do %% we care? -handle_event(#event{type = node_stats, props = Stats, timestamp = Timestamp}, +handle_event(#event{type = node_stats, props = Stats0, timestamp = Timestamp}, State) -> + Stats = proplists:delete(persister_stats, Stats0) ++ + pget(persister_stats, Stats0), handle_stats(node_stats, Stats, Timestamp, [], ?COARSE_NODE_STATS, State); handle_event(_Event, State) -> @@ -965,7 +979,7 @@ format_detail_id(#resource{name = Name, virtual_host = Vhost, kind = Kind}, format_samples(Ranges, ManyStats, #state{interval = Interval}) -> lists:append( [case rabbit_mgmt_stats:is_blank(Stats) andalso - not lists:member(K, ?COARSE_QUEUE_STATS) of + not lists:member(K, ?ALWAYS_REPORT_STATS) of true -> []; false -> {Details, Counter} = rabbit_mgmt_stats:format( pick_range(K, Ranges), @@ -1095,7 +1109,7 @@ gc_batch(State = #state{aggregated_stats = ETS}) -> gc_batch(0, _Policies, State) -> State; gc_batch(Rows, Policies, State = #state{aggregated_stats = ETS, - gc_next_key = Key0}) -> + gc_next_key = Key0}) -> Key = case Key0 of undefined -> ets:first(ETS); _ -> ets:next(ETS, Key0) diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_format.erl b/deps/rabbitmq_management/src/rabbit_mgmt_format.erl index de19e62668..2613dcc1da 100644 --- a/deps/rabbitmq_management/src/rabbit_mgmt_format.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_format.erl @@ -157,9 +157,8 @@ internal_user(User) -> {tags, tags(User#internal_user.tags)}]. user(User) -> - [{name, User#user.username}, - {tags, tags(User#user.tags)}, - {auth_backend, User#user.auth_backend}]. + [{name, User#user.username}, + {tags, tags(User#user.tags)}]. tags(Tags) -> list_to_binary(string:join([atom_to_list(T) || T <- Tags], ",")). diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_util.erl b/deps/rabbitmq_management/src/rabbit_mgmt_util.erl index 0cadb66b29..ba6cd257a7 100644 --- a/deps/rabbitmq_management/src/rabbit_mgmt_util.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_util.erl @@ -28,7 +28,7 @@ -export([with_channel/4, with_channel/5]). -export([props_to_method/2, props_to_method/4]). -export([all_or_one_vhost/2, http_to_amqp/5, reply/3, filter_vhost/3]). --export([filter_conn_ch_list/3, filter_user/2, list_login_vhosts/1]). +-export([filter_conn_ch_list/3, filter_user/2, list_login_vhosts/2]). -export([with_decode/5, decode/1, decode/2, redirect/2, set_resp_header/3, args/1]). -export([reply_list/3, reply_list/4, sort_list/2, destination_type/1]). @@ -77,7 +77,7 @@ user_matches_vhost(ReqData, User) -> case vhost(ReqData) of not_found -> true; none -> true; - V -> lists:member(V, list_login_vhosts(User)) + V -> lists:member(V, list_login_vhosts(User, peersock(ReqData))) end. %% Used for connections / channels. A normal user can only see / delete @@ -143,12 +143,15 @@ is_authorized(ReqData, Context, Username, Password, ErrorMsg, Fun) -> not_authorised(<<"Login failed">>, ReqData, Context) end. -%% We can't use wrq:peer/1 because that trusts X-Forwarded-For. peer(ReqData) -> - WMState = ReqData#wm_reqdata.wm_state, - {ok, {IP,_Port}} = peername(WMState#wm_reqstate.socket), + {ok, {IP,_Port}} = peername(peersock(ReqData)), IP. +%% We can't use wrq:peer/1 because that trusts X-Forwarded-For. +peersock(ReqData) -> + WMState = ReqData#wm_reqdata.wm_state, + WMState#wm_reqstate.socket. + %% Like the one in rabbit_net, but we and webmachine have a different %% way of wrapping peername(Sock) when is_port(Sock) -> inet:peername(Sock); @@ -452,6 +455,8 @@ with_channel(VHost, ReqData, end; {error, {auth_failure, Msg}} -> not_authorised(Msg, ReqData, Context); + {error, access_refused} -> + not_authorised(<<"Access refused.">>, ReqData, Context); {error, {nodedown, N}} -> bad_request( list_to_binary( @@ -470,8 +475,8 @@ all_or_one_vhost(ReqData, Fun) -> VHost -> Fun(VHost) end. -filter_vhost(List, _ReqData, Context) -> - VHosts = list_login_vhosts(Context#context.user), +filter_vhost(List, ReqData, Context) -> + VHosts = list_login_vhosts(Context#context.user, peersock(ReqData)), [I || I <- List, lists:member(pget(vhost, I), VHosts)]. filter_user(List, _ReqData, #context{user = User}) -> @@ -533,12 +538,12 @@ intersects(A, B) -> lists:any(fun(I) -> lists:member(I, B) end, A). list_visible_vhosts(User = #user{tags = Tags}) -> case is_monitor(Tags) of true -> rabbit_vhost:list(); - false -> list_login_vhosts(User) + false -> list_login_vhosts(User, undefined) end. -list_login_vhosts(User) -> +list_login_vhosts(User, Sock) -> [V || V <- rabbit_vhost:list(), - case catch rabbit_access_control:check_vhost_access(User, V) of + case catch rabbit_access_control:check_vhost_access(User, V, Sock) of ok -> true; _ -> false end].