diff options
author | Tony Garnock-Jones <tonyg@lshift.net> | 2008-12-10 18:26:29 +0000 |
---|---|---|
committer | Tony Garnock-Jones <tonyg@lshift.net> | 2008-12-10 18:26:29 +0000 |
commit | 8d2afb32be56c6f68e55fa4b51299348c1c21827 (patch) | |
tree | eb0ec2a994781a961c1f53c4dd7839bcc42e45e9 | |
parent | 74fc138adb24802ba22746b0b9edc2b8fdaffaf5 (diff) | |
parent | 64f74551f65654220d20d5bcc4f6584f99a0111a (diff) | |
download | rabbitmq-server-8d2afb32be56c6f68e55fa4b51299348c1c21827.tar.gz |
merge default into bug19684
-rw-r--r-- | docs/rabbitmqctl.1.pod | 151 | ||||
-rw-r--r-- | src/rabbit_control.erl | 131 | ||||
-rw-r--r-- | src/rabbit_reader.erl | 2 | ||||
-rw-r--r-- | src/rabbit_tests.erl | 58 |
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; |