summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Garnock-Jones <tonyg@lshift.net>2008-12-10 18:26:29 +0000
committerTony Garnock-Jones <tonyg@lshift.net>2008-12-10 18:26:29 +0000
commit8d2afb32be56c6f68e55fa4b51299348c1c21827 (patch)
treeeb0ec2a994781a961c1f53c4dd7839bcc42e45e9
parent74fc138adb24802ba22746b0b9edc2b8fdaffaf5 (diff)
parent64f74551f65654220d20d5bcc4f6584f99a0111a (diff)
downloadrabbitmq-server-8d2afb32be56c6f68e55fa4b51299348c1c21827.tar.gz
merge default into bug19684
-rw-r--r--docs/rabbitmqctl.1.pod151
-rw-r--r--src/rabbit_control.erl131
-rw-r--r--src/rabbit_reader.erl2
-rw-r--r--src/rabbit_tests.erl58
4 files changed, 339 insertions, 3 deletions
diff --git a/docs/rabbitmqctl.1.pod b/docs/rabbitmqctl.1.pod
index 34a51d1b..85fd0023 100644
--- a/docs/rabbitmqctl.1.pod
+++ b/docs/rabbitmqctl.1.pod
@@ -25,7 +25,11 @@ B<-n> I<node>
RABBITMQ_NODENAME has been set to some non-default value at broker
startup time). The output of hostname -s is usually the correct
suffix to use after the "@" sign. See rabbitmq-server(1) for
- details of configur- ing the RabbitMQ broker.
+ details of configuring the RabbitMQ broker.
+
+B<-q>
+ quiet output mode is selected with the B<-q> flag. Informational
+ messages are suppressed when quiet mode is in effect.
=head1 COMMANDS
@@ -119,6 +123,151 @@ list_user_vhost I<username>
list all the virtual hosts to which the user named I<username> has
been granted access.
+=head2 SERVER STATUS
+
+list_queues [-p I<vhostpath>] [I<queueinfoitem> ...]
+ list queue information by virtual host. If no I<queueinfoitem>s
+ are specified then then name and number of messages is displayed
+ for each queue.
+
+=head3 Queue information items
+
+=over 4
+
+name
+ URL-encoded name of the queue
+
+durable
+ whether the queue survives server restarts
+
+auto_delete
+ whether the queue will be deleted when no longer used
+
+arguments
+ queue arguments
+
+pid
+ Erlang process identifier associated with the queue
+
+messages_ready
+ number of ready messages
+
+messages_unacknowledged
+ number of unacknowledged messages
+
+messages_uncommitted
+ number of uncommitted messages
+
+messages
+ sum of ready, unacknowledged and uncommitted messages
+
+acks_uncommitted
+ number of uncommitted acknowledgements
+
+consumers
+ number of consumers
+
+transactions
+ number of transactions
+
+memory
+ bytes of memory consumed by the Erlang process for the queue,
+ including stack, heap and internal structures
+
+=back
+
+list_exchanges [-p I<vhostpath>] [I<exchangeinfoitem> ...]
+ list exchange information by virtual host. If no
+ I<exchangeinfoitem>s are specified then name and type is displayed
+ for each exchange.
+
+=head3 Exchange information items
+
+=over 4
+
+name
+ URL-encoded name of the exchange
+
+type
+ echange type (B<direct>, B<topic> or B<fanout>)
+
+durable
+ whether the exchange survives server restarts
+
+auto_delete
+ whether the exchange is deleted when no longer used
+
+arguments
+ exchange arguments
+
+=back
+
+list_bindings [-p I<vhostpath>]
+ list bindings by virtual host. Each line contains exchange name,
+ routing key and queue name (all URL encoded) and arguments.
+
+list_connections [I<connectioninfoitem> ...]
+ list connection information. If no I<connectioninfoitem>s are
+ specified then the user, peer address and peer port are displayed.
+
+=head3 Connection information items
+
+=over 4
+
+pid
+ Erlang process id associated with the connection
+
+address
+ server IP number
+
+port
+ server port
+
+peer_address
+ peer address
+
+peer_port
+ peer port
+
+state
+ connection state (B<pre-init>, B<starting>, B<tuning>, B<opening>,
+ B<running>, B<closing>, B<closed>)
+
+channels
+ number of channels using the connection
+
+user
+ username associated with the connection
+
+vhost
+ URL-encoded virtual host
+
+timeout
+ connection timeout
+
+frame_max
+ maximum frame size (bytes)
+
+recv_oct
+ octets received
+
+recv_cnt
+ packets received
+
+send_oct
+ octets sent
+
+send_cnt
+ packets sent
+
+send_pend
+ send queue size
+
+The list_queues, list_exchanges and list_bindings commands accept an
+optional virtual host parameter for which to display results, defaulting
+to I<"/">. The default can be overridden with the B<-p> flag. Result
+columns for these commands and list_connections are tab-separated.
+
=head1 EXAMPLES
Create a user named foo with (initial) password bar at the Erlang node
diff --git a/src/rabbit_control.erl b/src/rabbit_control.erl
index 5d50ed56..17df1979 100644
--- a/src/rabbit_control.erl
+++ b/src/rabbit_control.erl
@@ -119,6 +119,11 @@ Available commands:
list_user_vhosts <UserName>
list_vhost_users <VHostPath>
+ list_queues [-p <VHostPath>] [<QueueInfoItem> ...]
+ list_exchanges [-p <VHostPath>] [<ExchangeInfoItem> ...]
+ list_bindings [-p <VHostPath>]
+ list_connections [<ConnectionInfoItem> ...]
+
Quiet output mode is selected with the \"-q\" flag. Informational messages
are suppressed when quiet mode is in effect.
@@ -129,6 +134,25 @@ usually be rabbit@server (unless RABBITMQ_NODENAME has been set to
some non-default value at broker startup time). The output of hostname
-s is usually the correct suffix to use after the \"@\" sign.
+The list_queues, list_exchanges and list_bindings commands accept an optional
+virtual host parameter for which to display results. The default value is \"/\".
+
+<QueueInfoItem> must be a member of the list [name, durable, auto_delete,
+arguments, pid, messages_ready, messages_unacknowledged, messages_uncommitted,
+messages, acks_uncommitted, consumers, transactions, memory]. The default is
+ to display name and (number of) messages.
+
+<ExchangeInfoItem> must be a member of the list [name, type, durable,
+auto_delete, arguments]. The default is to display name and type.
+
+The output format for \"list_bindings\" is a list of rows containing
+exchange name, routing key, queue name and arguments, in that order.
+
+<ConnectioInfoItem> must be a member of the list [pid, address, port,
+peer_address, peer_port, state, channels, user, vhost, timeout, frame_max,
+recv_oct, recv_cnt, send_oct, send_cnt, send_pend]. The default is to display
+user, peer_address and peer_port.
+
"),
halt(1).
@@ -213,7 +237,85 @@ action(list_user_vhosts, Node, Args = [_Username], Inform) ->
action(list_vhost_users, Node, Args = [_VHostPath], Inform) ->
Inform("Listing users for vhosts ~p", Args),
- display_list(call(Node, {rabbit_access_control, list_vhost_users, Args})).
+ display_list(call(Node, {rabbit_access_control, list_vhost_users, Args}));
+
+action(list_queues, Node, Args, Inform) ->
+ Inform("Listing queues", []),
+ {VHostArg, RemainingArgs} = parse_vhost_flag(Args),
+ ArgAtoms = default_if_empty(RemainingArgs, [name, messages]),
+ display_info_list(rpc_call(Node, rabbit_amqqueue, info_all,
+ [VHostArg, ArgAtoms]),
+ ArgAtoms);
+
+action(list_exchanges, Node, Args, Inform) ->
+ Inform("Listing exchanges", []),
+ {VHostArg, RemainingArgs} = parse_vhost_flag(Args),
+ ArgAtoms = default_if_empty(RemainingArgs, [name, type]),
+ display_info_list(rpc_call(Node, rabbit_exchange, info_all,
+ [VHostArg, ArgAtoms]),
+ ArgAtoms);
+
+action(list_bindings, Node, Args, Inform) ->
+ Inform("Listing bindings", []),
+ {VHostArg, _} = parse_vhost_flag(Args),
+ InfoKeys = [exchange_name, routing_key, queue_name, args],
+ display_info_list(
+ [lists:zip(InfoKeys, tuple_to_list(X)) ||
+ X <- rpc_call(Node, rabbit_exchange, list_bindings, [VHostArg])],
+ InfoKeys),
+ ok;
+
+action(list_connections, Node, Args, Inform) ->
+ Inform("Listing connections", []),
+ ArgAtoms = default_if_empty(Args, [user, peer_address, peer_port]),
+ display_info_list(rpc_call(Node, rabbit_networking, connection_info_all,
+ [ArgAtoms]),
+ ArgAtoms).
+
+parse_vhost_flag(Args) when is_list(Args) ->
+ case Args of
+ ["-p", VHost | RemainingArgs] ->
+ {list_to_binary(VHost), RemainingArgs};
+ RemainingArgs ->
+ {<<"/">>, RemainingArgs}
+ end.
+
+default_if_empty(List, Default) when is_list(List) ->
+ if List == [] ->
+ Default;
+ true ->
+ [list_to_atom(X) || X <- List]
+ end.
+
+display_info_list(Results, InfoItemKeys) when is_list(Results) ->
+ lists:foreach(
+ fun (Result) ->
+ io:fwrite(
+ lists:flatten(
+ rabbit_misc:intersperse(
+ "\t",
+ [format_info_item(Result, X) || X <- InfoItemKeys]))),
+ io:nl()
+ end,
+ Results),
+ ok;
+
+display_info_list(Other, _) ->
+ Other.
+
+format_info_item(Items, Key) ->
+ {value, Info = {Key, Value}} = lists:keysearch(Key, 1, Items),
+ case Info of
+ {_, #resource{name = Name}} ->
+ url_encode(Name);
+ {Key, IpAddress} when Key =:= address; Key =:= peer_address
+ andalso is_tuple(IpAddress) ->
+ inet_parse:ntoa(IpAddress);
+ _ when is_binary(Value) ->
+ url_encode(Value);
+ _ ->
+ io_lib:format("~w", [Value])
+ end.
display_list(L) when is_list(L) ->
lists:foreach(fun (I) ->
@@ -228,3 +330,30 @@ call(Node, {Mod, Fun, Args}) ->
rpc_call(Node, Mod, Fun, Args) ->
rpc:call(Node, Mod, Fun, Args, ?RPC_TIMEOUT).
+
+%% url_encode is lifted from ibrowse, modified to preserve some characters
+url_encode(Bin) when binary(Bin) ->
+ url_encode_char(lists:reverse(binary_to_list(Bin)), []).
+
+url_encode_char([X | T], Acc) when X >= $a, X =< $z ->
+ url_encode_char(T, [X | Acc]);
+url_encode_char([X | T], Acc) when X >= $A, X =< $Z ->
+ url_encode_char(T, [X | Acc]);
+url_encode_char([X | T], Acc) when X >= $0, X =< $9 ->
+ url_encode_char(T, [X | Acc]);
+url_encode_char([X | T], Acc)
+ when X == $-; X == $_; X == $.; X == $~;
+ X == $!; X == $*; X == $'; X == $(;
+ X == $); X == $;; X == $:; X == $@;
+ X == $&; X == $=; X == $+; X == $$;
+ X == $,; X == $/; X == $?; X == $%;
+ X == $#; X == $[; X == $] ->
+ url_encode_char(T, [X | Acc]);
+url_encode_char([X | T], Acc) ->
+ url_encode_char(T, [$%, d2h(X bsr 4), d2h(X band 16#0f) | Acc]);
+url_encode_char([], Acc) ->
+ Acc.
+
+d2h(N) when N<10 -> N+$0;
+d2h(N) -> N+$a-10.
+
diff --git a/src/rabbit_reader.erl b/src/rabbit_reader.erl
index 10c6e0ca..3f8d7cac 100644
--- a/src/rabbit_reader.erl
+++ b/src/rabbit_reader.erl
@@ -686,6 +686,8 @@ i(channels, #v1{}) ->
length(all_channels());
i(user, #v1{connection = #connection{user = #user{username = Username}}}) ->
Username;
+i(user, #v1{connection = #connection{user = none}}) ->
+ none;
i(vhost, #v1{connection = #connection{vhost = VHost}}) ->
VHost;
i(timeout, #v1{connection = #connection{timeout_sec = Timeout}}) ->
diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl
index 3bba661a..1853a855 100644
--- a/src/rabbit_tests.erl
+++ b/src/rabbit_tests.erl
@@ -35,6 +35,7 @@
-import(lists).
+-include("rabbit.hrl").
-include_lib("kernel/include/file.hrl").
test_content_prop_roundtrip(Datum, Binary) ->
@@ -51,6 +52,7 @@ all_tests() ->
passed = test_log_management_during_startup(),
passed = test_cluster_management(),
passed = test_user_management(),
+ passed = test_server_status(),
passed.
test_parsing() ->
@@ -494,12 +496,57 @@ test_user_management() ->
passed.
+test_server_status() ->
+
+ %% create a queue so we have something to list
+ Q = #amqqueue{} = rabbit_amqqueue:declare(
+ rabbit_misc:r(<<"/">>, queue, <<"foo">>),
+ false, false, []),
+
+ %% list queues
+ ok = info_action(
+ list_queues,
+ [name, durable, auto_delete, arguments, pid,
+ messages_ready, messages_unacknowledged, messages_uncommitted,
+ messages, acks_uncommitted, consumers, transactions, memory],
+ true),
+
+ %% list exchanges
+ ok = info_action(
+ list_exchanges,
+ [name, type, durable, auto_delete, arguments],
+ true),
+
+ %% list bindings
+ ok = control_action(list_bindings, []),
+
+ %% cleanup
+ {ok, _} = rabbit_amqqueue:delete(Q, false, false),
+
+ %% list connections
+ [#listener{host = H, port = P} | _] = rabbit_networking:active_listeners(),
+ {ok, C} = gen_tcp:connect(H, P, []),
+ timer:sleep(100),
+ ok = info_action(
+ list_connections,
+ [pid, address, port, peer_address, peer_port, state,
+ channels, user, vhost, timeout, frame_max,
+ recv_oct, recv_cnt, send_oct, send_cnt, send_pend],
+ false),
+ ok = gen_tcp:close(C),
+
+ passed.
+
%---------------------------------------------------------------------
control_action(Command, Args) -> control_action(Command, node(), Args).
control_action(Command, Node, Args) ->
- case catch rabbit_control:action(Command, Node, Args, fun io:format/2) of
+ case catch rabbit_control:action(
+ Command, Node, Args,
+ fun (Format, Args1) ->
+ io:format(Format ++ " ...~n", Args1)
+ end) of
ok ->
io:format("done.~n"),
ok;
@@ -508,6 +555,15 @@ control_action(Command, Node, Args) ->
Other
end.
+info_action(Command, Args, CheckVHost) ->
+ ok = control_action(Command, []),
+ if CheckVHost -> ok = control_action(Command, ["-p", "/"]);
+ true -> ok
+ end,
+ ok = control_action(Command, lists:map(fun atom_to_list/1, Args)),
+ {bad_argument, dummy} = control_action(Command, ["dummy"]),
+ ok.
+
empty_files(Files) ->
[case file:read_file_info(File) of
{ok, FInfo} -> FInfo#file_info.size == 0;