aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2016-11-24 20:19:28 +0100
committerLoïc Hoguin <[email protected]>2016-11-24 20:30:05 +0100
commit9db28a09e8f7695f67297fff7f7144bac2061cc2 (patch)
tree32ea82f0deed91f2980bd82f6ff59678565a633d
parent94b3770ccfd810d4980fbedb74e4127cf0656fc2 (diff)
downloadranch-9db28a09e8f7695f67297fff7f7144bac2061cc2.tar.gz
ranch-9db28a09e8f7695f67297fff7f7144bac2061cc2.tar.bz2
ranch-9db28a09e8f7695f67297fff7f7144bac2061cc2.zip
Add ranch:info/0 and ranch:procs/2
Provides detailed information about Ranch listeners
-rw-r--r--doc/src/guide/listeners.asciidoc23
-rw-r--r--doc/src/manual/ranch.asciidoc28
-rw-r--r--src/ranch.erl59
-rw-r--r--test/acceptor_SUITE.erl77
4 files changed, 186 insertions, 1 deletions
diff --git a/doc/src/guide/listeners.asciidoc b/doc/src/guide/listeners.asciidoc
index 7a5bdb2..1055b80 100644
--- a/doc/src/guide/listeners.asciidoc
+++ b/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).
diff --git a/doc/src/manual/ranch.asciidoc b/doc/src/manual/ranch.asciidoc
index 2e4f177..13380fd 100644
--- a/doc/src/manual/ranch.asciidoc
+++ b/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.
diff --git a/src/ranch.erl b/src/ranch.erl
index 24b87a5..9d2509a 100644
--- a/src/ranch.erl
+++ b/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) ->
diff --git a/test/acceptor_SUITE.erl b/test/acceptor_SUITE.erl
index a60f284..9635e4e 100644
--- a/test/acceptor_SUITE.erl
+++ b/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(_) ->