Browse Source

Add ranch:info/0 and ranch:procs/2

Provides detailed information about Ranch listeners
Loïc Hoguin 8 years ago
parent
commit
9db28a09e8
4 changed files with 186 additions and 1 deletions
  1. 23 0
      doc/src/guide/listeners.asciidoc
  2. 28 0
      doc/src/manual/ranch.asciidoc
  3. 59 0
      src/ranch.erl
  4. 76 1
      test/acceptor_SUITE.erl

+ 23 - 0
doc/src/guide/listeners.asciidoc

@@ -277,3 +277,26 @@ calling `ranch:get_protocol_options/1`.
 
 [source,erlang]
 Opts = ranch:get_protocol_options(tcp_echo).
+
+=== Obtain information about listeners
+
+Ranch provides two functions for retrieving information about the
+listeners, for reporting and diagnostic purposes.
+
+The `ranch:info/0` function will return detailed information
+about all listeners.
+
+.Retrieving detailed information
+[source,erlang]
+ranch:info().
+
+The `ranch:procs/2` function will return all acceptor or listener
+processes for a given listener.
+
+.Get all acceptor processes
+[source,erlang]
+ranch:procs(tcp_echo, acceptors).
+
+.Get all connection processes
+[source,erlang]
+ranch:procs(tcp_echo, connections).

+ 28 - 0
doc/src/manual/ranch.asciidoc

@@ -111,6 +111,34 @@ ProtoOpts = any():: Current protocol options.
 
 Return the protocol options set for the given listener.
 
+=== info() -> [{Ref, [{Key, Value}]}]
+
+Ref = ref():: Listener name.
+Key = atom():: Information key.
+Value = any():: Information value.
+
+Return detailed information about all Ranch listeners.
+
+The following keys are defined:
+
+pid:: Pid of the listener's top-level supervisor.
+ip:: Interface Ranch listens on.
+port:: Port number Ranch listens on.
+num_acceptors:: Number of acceptor processes.
+max_connections:: Maximum number of connections.
+active_connections:: Number of active connections.
+all_connections:: Number of connections, including those removed from the count.
+transport:: Transport module.
+transport_options:: Transport options.
+protocol:: Protocol module.
+protocol_options:: Protocol options.
+
+=== procs(Ref, acceptors | connections) -> [pid()]
+
+Ref = ref():: Listener name.
+
+Return all acceptor or connection processes for one listener.
+
 === remove_connection(Ref) -> ok
 
 Ref = ref():: Listener name.

+ 59 - 0
src/ranch.erl

@@ -25,6 +25,8 @@
 -export([set_max_connections/2]).
 -export([get_protocol_options/1]).
 -export([set_protocol_options/2]).
+-export([info/0]).
+-export([procs/2]).
 -export([filter_options/3]).
 -export([set_option_default/3]).
 -export([require/1]).
@@ -142,6 +144,63 @@ get_protocol_options(Ref) ->
 set_protocol_options(Ref, Opts) ->
 	ranch_server:set_protocol_options(Ref, Opts).
 
+-spec info() -> [{any(), [{atom(), any()}]}].
+info() ->
+	Children = supervisor:which_children(ranch_sup),
+	[{Ref, listener_info(Ref, Pid)}
+		|| {{ranch_listener_sup, Ref}, Pid, _, [_]} <- Children].
+
+listener_info(Ref, Pid) ->
+	[_, NumAcceptors, Transport, TransOpts, Protocol, _] = listener_start_args(Ref),
+	ConnsSup = ranch_server:get_connections_sup(Ref),
+	{IP, Port} = get_addr(Ref),
+	MaxConns = get_max_connections(Ref),
+	ProtoOpts = get_protocol_options(Ref),
+	[
+		{pid, Pid},
+		{ip, IP},
+		{port, Port},
+		{num_acceptors, NumAcceptors},
+		{max_connections, MaxConns},
+		{active_connections, ranch_conns_sup:active_connections(ConnsSup)},
+		{all_connections, proplists:get_value(active, supervisor:count_children(ConnsSup))},
+		{transport, Transport},
+		{transport_options, TransOpts},
+		{protocol, Protocol},
+		{protocol_options, ProtoOpts}
+	].
+
+listener_start_args(Ref) ->
+	case erlang:function_exported(supervisor, get_childspec, 2) of
+		true ->
+			%% Can't use map syntax before R18.
+			{ok, Map} = supervisor:get_childspec(ranch_sup, {ranch_listener_sup, Ref}),
+			{ranch_listener_sup, start_link, StartArgs} = maps:get(start, Map),
+			StartArgs;
+		false ->
+			%% Awful solution for compatibility with R16 and R17.
+			{status, _, _, [_, _, _, _, [_, _,
+				{data, [{_, {state, _, _, Children, _, _, _, _, _, _}}]}]]}
+				= sys:get_status(ranch_sup),
+			[StartArgs] = [StartArgs || {child, _, {ranch_listener_sup, ChildRef},
+				{ranch_listener_sup, start_link, StartArgs}, _, _, _, _}
+				<- Children, ChildRef =:= Ref],
+			StartArgs
+	end.
+
+-spec procs(ref(), acceptors | connections) -> [pid()].
+procs(Ref, acceptors) ->
+	procs1(Ref, ranch_acceptors_sup);
+procs(Ref, connections) ->
+	procs1(Ref, ranch_conns_sup).
+
+procs1(Ref, Sup) ->
+	{_, ListenerSup, _, _} = lists:keyfind({ranch_listener_sup, Ref}, 1,
+		supervisor:which_children(ranch_sup)),
+	{_, SupPid, _, _} = lists:keyfind(Sup, 1,
+		supervisor:which_children(ListenerSup)),
+	[Pid || {_, Pid, _, _} <- supervisor:which_children(SupPid)].
+
 -spec filter_options([inet | inet6 | {atom(), any()} | {raw, any(), any(), any()}],
 	[atom()], Acc) -> Acc when Acc :: [any()].
 filter_options(UserOptions, DisallowedKeys, DefaultOptions) ->

+ 76 - 1
test/acceptor_SUITE.erl

@@ -48,7 +48,8 @@ groups() ->
 		ssl_error_no_cert
 	]}, {misc, [
 		misc_bad_transport,
-		misc_bad_transport_options
+		misc_bad_transport_options,
+		misc_info
 	]}, {supervisor, [
 		connection_type_supervisor,
 		connection_type_supervisor_separate_from_connection,
@@ -74,6 +75,80 @@ misc_bad_transport_options(_) ->
 		ranch_tcp, [binary, {packet, 4}, <<"garbage">>, raw, backlog], echo_protocol, []),
 	ok.
 
+misc_info(_) ->
+	doc("Information about listeners."),
+	%% Open a listener with a few connections.
+	{ok, Pid1} = ranch:start_listener({misc_info, tcp}, 1, ranch_tcp, [],
+		remove_conn_and_wait_protocol, [{remove, true, 2500}]),
+	Port1 = ranch:get_port({misc_info, tcp}),
+	%% Open a few more listeners with different arguments.
+	{ok, Pid2} = ranch:start_listener({misc_info, act}, 2, ranch_tcp, [], active_echo_protocol, {}),
+	Port2 = ranch:get_port({misc_info, act}),
+	ranch:set_max_connections({misc_info, act}, infinity),
+	Opts = ct_helper:get_certs_from_ets(),
+	{ok, Pid3} = ranch:start_listener({misc_info, ssl}, 3, ranch_ssl, Opts, echo_protocol, [{}]),
+	Port3 = ranch:get_port({misc_info, ssl}),
+	%% Open 5 connections, 3 removed from the count.
+	{ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
+	{ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
+	{ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
+	receive after 250 -> ok end,
+	ranch:set_protocol_options({misc_info, tcp}, [{remove, false, 2500}]),
+	receive after 250 -> ok end,
+	{ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
+	{ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
+	%% Confirm the info returned by Ranch is correct.
+	[
+		{{misc_info, act}, [
+			{pid, Pid2},
+			{ip, {0,0,0,0}},
+			{port, Port2},
+			{num_acceptors, 2},
+			{max_connections, infinity}, %% Option was modified.
+			{active_connections, 0},
+			{all_connections, 0},
+			{transport, ranch_tcp},
+			{transport_options, []},
+			{protocol, active_echo_protocol},
+			{protocol_options, {}}
+		]},
+		{{misc_info, ssl}, [
+			{pid, Pid3},
+			{ip, {0,0,0,0}},
+			{port, Port3},
+			{num_acceptors, 3},
+			{max_connections, 1024},
+			{active_connections, 0},
+			{all_connections, 0},
+			{transport, ranch_ssl},
+			{transport_options, Opts},
+			{protocol, echo_protocol},
+			{protocol_options, [{}]}
+		]},
+		{{misc_info, tcp}, [
+			{pid, Pid1},
+			{ip, {0,0,0,0}},
+			{port, Port1},
+			{num_acceptors, 1},
+			{max_connections, 1024},
+			{active_connections, 2},
+			{all_connections, 5},
+			{transport, ranch_tcp},
+			{transport_options, []},
+			{protocol, remove_conn_and_wait_protocol},
+			{protocol_options, [{remove, false, 2500}]} %% Option was modified.
+		]}
+	] = lists:sort([L || L={{misc_info, _}, _} <- ranch:info()]),
+	%% Get acceptors.
+	[_] = ranch:procs({misc_info, tcp}, acceptors),
+	[_, _] = ranch:procs({misc_info, act}, acceptors),
+	[_, _, _] = ranch:procs({misc_info, ssl}, acceptors),
+	%% Get connections.
+	[_, _, _, _, _] = ranch:procs({misc_info, tcp}, connections),
+	[] = ranch:procs({misc_info, act}, connections),
+	[] = ranch:procs({misc_info, ssl}, connections),
+	ok.
+
 %% ssl.
 
 ssl_accept_error(_) ->