From 9db28a09e8f7695f67297fff7f7144bac2061cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Thu, 24 Nov 2016 20:19:28 +0100 Subject: Add ranch:info/0 and ranch:procs/2 Provides detailed information about Ranch listeners --- doc/src/guide/listeners.asciidoc | 23 ++++++++++++ doc/src/manual/ranch.asciidoc | 28 +++++++++++++++ src/ranch.erl | 59 ++++++++++++++++++++++++++++++ test/acceptor_SUITE.erl | 77 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 186 insertions(+), 1 deletion(-) 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(_) -> -- cgit v1.2.3