Individual channels.
This commit is contained in:
parent
6c9acdb12e
commit
a2abe0f24b
|
|
@ -1,6 +1,4 @@
|
|||
Before preview release:
|
||||
Write more management:
|
||||
Channel GET
|
||||
Finish basic documentation.
|
||||
Figure out supervision.
|
||||
Cross-browser testing.
|
||||
|
|
|
|||
|
|
@ -133,6 +133,14 @@ Content-Length: 0</pre>
|
|||
<td class="path"><a href="/api/channels">/api/channels</a></td>
|
||||
<td>A list of all open channels.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="path">/api/channels/<i>channel</i></td>
|
||||
<td>An individual channel.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X</td>
|
||||
<td></td>
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ function link_conn(name) {
|
|||
return link_to(name, '#/connections/' + esc(name))
|
||||
}
|
||||
|
||||
function link_channel(name) {
|
||||
return link_to(name, '#/channels/' + esc(name))
|
||||
}
|
||||
|
||||
function link_exchange(vhost, name) {
|
||||
var url = esc(vhost) + '/' + (name == '' ? 'amq.default' : esc(name));
|
||||
return link_to(fmt_exchange(name), '#/exchanges/' + url)
|
||||
|
|
@ -95,4 +99,28 @@ function link_user(name) {
|
|||
|
||||
function link_to(name, url) {
|
||||
return '<a href="' + url + '">' + name + '</a>';
|
||||
}
|
||||
|
||||
function message_rates(stats) {
|
||||
var res = "";
|
||||
if (keys(stats).length > 0) {
|
||||
var items = [['Publish', 'publish'], ['Deliver', 'deliver'],
|
||||
['Acknowledge', 'ack'], ['Get', 'get'],
|
||||
['Deliver (noack)', 'deliver_no_ack'],
|
||||
['Get (noack)', 'get_no_ack']];
|
||||
for (var i in items) {
|
||||
var name = items[i][0];
|
||||
var key = items[i][1] + '_details';
|
||||
if (key in stats) {
|
||||
res += '<div class="highlight">' + name;
|
||||
res += '<strong>' + Math.round(stats[key].rate) + '</strong>';
|
||||
res += 'msg/s</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
res = '<p>Currently idle</p>';
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
@ -28,6 +28,10 @@ function dispatcher() {
|
|||
});
|
||||
|
||||
path('#/channels', {'channels': '/channels'}, 'channels');
|
||||
this.get('#/channels/:name', function() {
|
||||
render({'channel': '/channels/' + esc(this.params['name'])}, 'channel',
|
||||
'#/channels');
|
||||
});
|
||||
|
||||
path('#/exchanges', {'exchanges': '/exchanges', 'vhosts': '/vhosts'}, 'exchanges');
|
||||
this.get('#/exchanges/:vhost/:name', function() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
<h1>Channel: <%= channel.name %></h1>
|
||||
|
||||
<div class="section">
|
||||
<h2>Message Rates</h2>
|
||||
<div>
|
||||
<%= message_rates(channel.message_stats) %>
|
||||
<span class="br"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Overview</h2>
|
||||
<div>
|
||||
<table class="facts">
|
||||
<tr><th>Connection</th><td><%= link_conn(channel.connection_details.name) %></td></tr>
|
||||
<tr><th>Virtual host</th><td><%= channel.vhost %></td></tr>
|
||||
<tr><th>Username</th><td><%= channel.user %></td></tr>
|
||||
<tr><th>Transactional</th><td><%= channel.transactional %></td></tr>
|
||||
<tr><th>Prefetch count</th><td><%= channel.prefetch_count %></td></tr>
|
||||
<tr><th>Acks uncommitted</th><td><%= channel.acks_uncommitted %></td></tr>
|
||||
<tr><th>Messages unacknowledged</th><td><%= channel.messages_unacknowledged %></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th colspan="4">Details</th>
|
||||
<th colspan="5">Details</th>
|
||||
<th colspan="6">Message rates</th>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
<th>Username</th>
|
||||
<th>Transactional</th>
|
||||
<th>Prefetch</th>
|
||||
<th>Messages unacked</th>
|
||||
<th>publish</th>
|
||||
<th>deliver</th>
|
||||
<th>get</th>
|
||||
|
|
@ -26,8 +27,7 @@
|
|||
<% for (var i = 0; i < channels.length; i++) { %>
|
||||
<tr<%= alt_rows(i)%>>
|
||||
<td>
|
||||
<%= link_conn(channels[i].connection_details.name) %>
|
||||
Channel <%= channels[i].number %>
|
||||
<%= link_channel(channels[i].name) %>
|
||||
</td>
|
||||
<td class="c"><%= link_vhost(channels[i].vhost) %></td>
|
||||
<td class="c"><%= link_user(channels[i].user) %></td>
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
<% } %>
|
||||
</td>
|
||||
<td class="c"><%= channels[i].prefetch_count %></td>
|
||||
<td class="c"><%= channels[i].messages_unacknowledged %></td>
|
||||
<td class="l"><%= fmt_rate(channels[i].message_stats, 'publish') %></td>
|
||||
<td class="l"><%= fmt_rate(channels[i].message_stats, 'deliver') %></td>
|
||||
<td class="l"><%= fmt_rate(channels[i].message_stats, 'get') %></td>
|
||||
|
|
@ -45,9 +46,6 @@
|
|||
<td class="l"><%= fmt_rate(channels[i].message_stats, 'get_no_ack') %></td>
|
||||
<td class="l">
|
||||
<%= fmt_rate(channels[i].message_stats, 'ack') %>
|
||||
<% if (channels[i].messages_unacknowledged > 0) { %>
|
||||
<sub>(<%= channels[i].messages_unacknowledged %> msgs unacked)</sub>
|
||||
<% } %>
|
||||
</td>
|
||||
</tr>
|
||||
<% } %>
|
||||
|
|
|
|||
|
|
@ -3,31 +3,7 @@
|
|||
<div class="section">
|
||||
<h2>Message Rates</h2>
|
||||
<div>
|
||||
<% if (keys(overview.message_stats).length > 0) {
|
||||
var items = [['Publish', 'publish'], ['Deliver', 'deliver'],
|
||||
['Acknowledge', 'ack'], ['Get', 'get'],
|
||||
['Deliver (noack)', 'deliver_no_ack'],
|
||||
['Get (noack)', 'get_no_ack']];
|
||||
for (var i in items) {
|
||||
var name = items[i][0];
|
||||
var key = items[i][1] + '_details';
|
||||
if (key in overview.message_stats) {
|
||||
%>
|
||||
<div class="highlight">
|
||||
<%= name %>
|
||||
<strong><%= Math.round(overview.message_stats[key].rate) %></strong>
|
||||
msg/s
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
%>
|
||||
<p>Currently idle</p>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
<%= message_rates(overview.message_stats) %>
|
||||
<span class="br"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ dispatcher() ->
|
|||
{["connections"], rabbit_mgmt_wm_connections, []},
|
||||
{["connections", connection], rabbit_mgmt_wm_connection, []},
|
||||
{["channels"], rabbit_mgmt_wm_channels, []},
|
||||
{["channels", channel], rabbit_mgmt_wm_channel, []},
|
||||
{["exchanges"], rabbit_mgmt_wm_exchanges, []},
|
||||
{["exchanges", vhost], rabbit_mgmt_wm_exchanges, []},
|
||||
{["exchanges", vhost, exchange], rabbit_mgmt_wm_exchange, []},
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
-export([start/0]).
|
||||
|
||||
-export([get_queues/1, get_connections/0, get_connection/1,
|
||||
get_overview/0, get_channels/0]).
|
||||
get_overview/0, get_channels/0, get_channel/1]).
|
||||
|
||||
-export([group_sum/2]).
|
||||
|
||||
|
|
@ -63,6 +63,9 @@ get_connection(Name) ->
|
|||
get_channels() ->
|
||||
gen_event:call(rabbit_event, ?MODULE, get_channels, infinity).
|
||||
|
||||
get_channel(Name) ->
|
||||
gen_event:call(rabbit_event, ?MODULE, {get_channel, Name}, infinity).
|
||||
|
||||
get_overview() ->
|
||||
gen_event:call(rabbit_event, ?MODULE, get_overview, infinity).
|
||||
|
||||
|
|
@ -101,10 +104,6 @@ name_to_id(Table, Name) ->
|
|||
result_or_error([]) -> error;
|
||||
result_or_error(S) -> S.
|
||||
|
||||
%% TODO until we do rates properly (i.e. looking at a time series)
|
||||
%% we have the problem that an object which stops emitting events will look
|
||||
%% like its rate has stayed up. This might make time series more important.
|
||||
|
||||
rates(Stats, Timestamp, OldStats, OldTimestamp, Keys) ->
|
||||
Stats ++ lists:filter(
|
||||
fun (unknown) -> false;
|
||||
|
|
@ -240,6 +239,17 @@ handle_call(get_channels, State = #state{tables = Tables}) ->
|
|||
{ok, augment_msg_stats(merge_fine_stats(Stats, [FineQ, FineX]), Tables),
|
||||
State};
|
||||
|
||||
handle_call({get_channel, Name}, State = #state{tables = Tables}) ->
|
||||
Table = orddict:fetch(channel_stats, Tables),
|
||||
Id = name_to_id(Table, Name),
|
||||
Chs = [lookup_element(Table, {Id, create})],
|
||||
%% TODO refactor this, and connection(s) above
|
||||
Stats = merge_created_stats(Chs, Table),
|
||||
FineQ = get_fine_stats(channel_queue_stats, [channel], Tables),
|
||||
FineX = get_fine_stats(channel_exchange_stats, [channel], Tables),
|
||||
[Res] = augment_msg_stats(merge_fine_stats(Stats, [FineQ, FineX]), Tables),
|
||||
{ok, result_or_error(Res), State};
|
||||
|
||||
handle_call(get_overview, State = #state{tables = Tables}) ->
|
||||
FineQ = extract_singleton_fine_stats(
|
||||
get_fine_stats(channel_queue_stats, [], Tables)),
|
||||
|
|
@ -281,9 +291,16 @@ handle_event(#event{type = connection_stats, props = Stats,
|
|||
handle_event(Event = #event{type = connection_closed}, State) ->
|
||||
handle_deleted(connection_stats, Event, State);
|
||||
|
||||
handle_event(#event{type = channel_created, props = Stats}, State) ->
|
||||
handle_event(#event{type = channel_created, props = Stats},
|
||||
State = #state{tables = Tables}) ->
|
||||
ConnTable = orddict:fetch(connection_stats, Tables),
|
||||
Conn = lookup_element(ConnTable, {id(pget(connection, Stats)), create}),
|
||||
Name = rabbit_mgmt_format:print(
|
||||
"~s:~w:~w",
|
||||
[pget(peer_address, Conn), pget(peer_port, Conn),
|
||||
pget(number, Stats)]),
|
||||
handle_created(
|
||||
channel_stats, Stats,
|
||||
channel_stats, [{name, Name}|Stats],
|
||||
[{fun rabbit_mgmt_format:pid/1, [pid, connection]}], State);
|
||||
|
||||
handle_event(#event{type = channel_stats, props = Stats, timestamp = Timestamp},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
%% The contents of this file are subject to the Mozilla Public License
|
||||
%% Version 1.1 (the "License"); you may not use this file except in
|
||||
%% compliance with the License. You may obtain a copy of the License at
|
||||
%% http://www.mozilla.org/MPL/
|
||||
%%
|
||||
%% Software distributed under the License is distributed on an "AS IS"
|
||||
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
%% License for the specific language governing rights and limitations
|
||||
%% under the License.
|
||||
%%
|
||||
%% The Original Code is RabbitMQ Management Console.
|
||||
%%
|
||||
%% The Initial Developers of the Original Code are Rabbit Technologies Ltd.
|
||||
%%
|
||||
%% Copyright (C) 2010 Rabbit Technologies Ltd.
|
||||
%%
|
||||
%% All Rights Reserved.
|
||||
%%
|
||||
%% Contributor(s): ______________________________________.
|
||||
%%
|
||||
-module(rabbit_mgmt_wm_channel).
|
||||
|
||||
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]).
|
||||
-export([resource_exists/2]).
|
||||
|
||||
-include("rabbit_mgmt.hrl").
|
||||
-include_lib("webmachine/include/webmachine.hrl").
|
||||
-include_lib("rabbit_common/include/rabbit.hrl").
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
init(_Config) -> {ok, #context{}}.
|
||||
|
||||
content_types_provided(ReqData, Context) ->
|
||||
{[{"application/json", to_json}], ReqData, Context}.
|
||||
|
||||
resource_exists(ReqData, Context) ->
|
||||
case channel(ReqData) of
|
||||
error -> {false, ReqData, Context};
|
||||
_Conn -> {true, ReqData, Context}
|
||||
end.
|
||||
|
||||
to_json(ReqData, Context) ->
|
||||
rabbit_mgmt_util:reply({struct, channel(ReqData)}, ReqData, Context).
|
||||
|
||||
is_authorized(ReqData, Context) ->
|
||||
rabbit_mgmt_util:is_authorized(ReqData, Context).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
channel(ReqData) ->
|
||||
rabbit_mgmt_db:get_channel(rabbit_mgmt_util:id(channel, ReqData)).
|
||||
|
|
@ -38,8 +38,7 @@ allowed_methods(ReqData, Context) ->
|
|||
{['HEAD', 'GET', 'DELETE'], ReqData, Context}.
|
||||
|
||||
resource_exists(ReqData, Context) ->
|
||||
case rabbit_mgmt_db:get_connection(
|
||||
rabbit_mgmt_util:id(connection, ReqData)) of
|
||||
case conn(ReqData) of
|
||||
error -> {false, ReqData, Context};
|
||||
_Conn -> {true, ReqData, Context}
|
||||
end.
|
||||
|
|
|
|||
Loading…
Reference in New Issue