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)
 | 
			
		||||
| 
						 | 
				
			
			@ -96,3 +100,27 @@ 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