Skip to content

Commit

Permalink
Add C2S TCP/TLS listener instrumentation metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
arcusfelis committed Jun 14, 2024
1 parent f5b57d4 commit 43fbd31
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 39 deletions.
18 changes: 14 additions & 4 deletions big_tests/tests/bosh_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ acks_test_cases() ->
%%--------------------------------------------------------------------

init_per_suite(Config) ->
instrument_helper:start(instrumentation_events()),
instrument_helper:start(instrumentation_events() ++ negative_instrumentation_events()),
Config1 = dynamic_modules:save_modules(host_type(), Config),
escalus:init_per_suite([{escalus_user_db, {module, escalus_ejabberd}} | Config1]).

Expand Down Expand Up @@ -173,9 +173,7 @@ required_bosh_opts(_Group) ->

create_and_terminate_session(Config) ->
MongooseMetrics = [{[global, data, xmpp, received, xml_stanza_size], changed},
{[global, data, xmpp, sent, xml_stanza_size], changed},
{[global, data, xmpp, received, c2s, tcp], 0},
{[global, data, xmpp, sent, c2s, tcp], 0}],
{[global, data, xmpp, sent, xml_stanza_size], changed}],
PreStoryData = escalus_mongooseim:pre_story([{mongoose_metrics, MongooseMetrics}]),
NamedSpecs = escalus_config:get_config(escalus_users, Config),
CarolSpec = proplists:get_value(?config(user, Config), NamedSpecs),
Expand All @@ -200,6 +198,9 @@ create_and_terminate_session(Config) ->
[instrument_helper:assert(Event, Label, fun(#{byte_size := BS}) -> BS > 0 end)
|| {Event, Label} <- instrumentation_events()],

%% Verify C2S listener is not used
instrument_helper:assert_not_emitted(negative_instrumentation_events(), true),

escalus_mongooseim:post_story(PreStoryData),

%% Assert the session was terminated.
Expand Down Expand Up @@ -953,3 +954,12 @@ wait_for_zero_bosh_sessions() ->

instrumentation_events() ->
instrument_helper:declared_events(mod_bosh, []).

negative_instrumentation_events() ->
[{Name, #{}} || Name <- negative_instrumentation_events_names()].

negative_instrumentation_events_names() ->
[c2s_tcp_data_sent,
c2s_tcp_data_received,
c2s_tls_data_sent,
c2s_tls_data_received].
17 changes: 11 additions & 6 deletions big_tests/tests/connect_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ suite() ->
%%--------------------------------------------------------------------

init_per_suite(Config) ->
instrument_helper:start(instrumentation_events()),
Config0 = escalus:init_per_suite([{escalus_user_db, {module, escalus_ejabberd, []}} | Config]),
C2SPort = ct:get_config({hosts, mim, c2s_port}),
[C2SListener] = mongoose_helper:get_listeners(mim(), #{port => C2SPort, module => mongoose_c2s_listener}),
Expand All @@ -140,6 +141,7 @@ init_per_suite(Config) ->
escalus:create_users(Config1, escalus:get_users([?SECURE_USER, alice])).

end_per_suite(Config) ->
instrument_helper:stop(),
escalus_fresh:clean(),
escalus:delete_users(Config, escalus:get_users([?SECURE_USER, alice])),
restore_c2s_listener(Config),
Expand Down Expand Up @@ -400,14 +402,14 @@ starttls_should_fail_when_disabled(Config) ->

metrics_test(Config) ->
MongooseMetrics = [{[global, data, xmpp, received, xml_stanza_size], changed},
{[global, data, xmpp, sent, xml_stanza_size], changed},
{[global, data, xmpp, received, c2s, tls], changed},
{[global, data, xmpp, sent, c2s, tls], changed},
%% TCP traffic before starttls
{[global, data, xmpp, received, c2s, tcp], changed},
{[global, data, xmpp, sent, c2s, tcp], changed}],
{[global, data, xmpp, sent, xml_stanza_size], changed}],
PreStoryData = escalus_mongooseim:pre_story([{mongoose_metrics, MongooseMetrics}]),
tls_authenticate(Config),

% Assert that correct events have been executed
[instrument_helper:assert(Event, Label, fun(#{byte_size := BS}) -> BS > 0 end)
|| {Event, Label} <- instrumentation_events()],

escalus_mongooseim:post_story(PreStoryData).

tls_authenticate(Config) ->
Expand Down Expand Up @@ -815,3 +817,6 @@ proxy_info() ->
dest_address => {192, 168, 0, 1},
dest_port => 443
}.

instrumentation_events() ->
instrument_helper:declared_events(mongoose_c2s_listener, [#{}]).
13 changes: 13 additions & 0 deletions big_tests/tests/instrument_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
-export([declared_events/1, declared_events/2,
start/1, stop/0,
assert/3, assert/4,
assert_not_emitted/2, assert_not_emitted/3,
wait_for/2, wait_for_new/2,
lookup/2, take/2]).

Expand Down Expand Up @@ -74,6 +75,18 @@ assert(EventName, Labels, MeasurementsList, CheckF) ->
event_tested(EventName, Labels)
end.

assert_not_emitted(EventName, Labels, MarkAsTested) ->
case lookup(EventName, Labels) of
[] ->
event_tested(EventName, Labels);
Events ->
ct:fail("Measurements emitted but should not ~p", [Events])
end.

assert_not_emitted(Events, MarkAsTested) ->
[assert_not_emitted(Event, Label, MarkAsTested)
|| {Event, Label} <- Events].

%% @doc Remove previous events, and wait for a new one. Use for probes only.
-spec wait_for_new(event_name(), labels()) -> [measurements()].
wait_for_new(EventName, Labels) ->
Expand Down
26 changes: 20 additions & 6 deletions big_tests/tests/mim_c2s_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ groups() ->
%% Init & teardown
%%--------------------------------------------------------------------
init_per_suite(Config) ->
instrument_helper:start(instrumentation_events()),
HostType = domain_helper:host_type(),
Config1 = dynamic_modules:save_modules(HostType, Config),
dynamic_modules:ensure_stopped(HostType, [mod_presence]),
Expand All @@ -53,6 +54,7 @@ init_per_suite(Config) ->
escalus:init_per_suite([{escalus_overrides, EscalusOverrides} | Config1 ]).

end_per_suite(Config) ->
instrument_helper:stop(),
dynamic_modules:restore_modules(Config),
mongoose_helper:restore_config(Config),
escalus:end_per_suite(Config).
Expand Down Expand Up @@ -118,17 +120,18 @@ two_users_can_log_and_chat(Config) ->
HostTypePrefix = domain_helper:make_metrics_prefix(HostType),
MongooseMetrics = [{[global, data, xmpp, received, xml_stanza_size], changed},
{[global, data, xmpp, sent, xml_stanza_size], changed},
{[global, data, xmpp, received, c2s, tcp], changed},
{[global, data, xmpp, sent, c2s, tcp], changed},
{[HostTypePrefix, data, xmpp, c2s, message, processing_time], changed},
{[global, data, xmpp, received, c2s, tls], 0},
{[global, data, xmpp, sent, c2s, tls], 0}],
{[HostTypePrefix, data, xmpp, c2s, message, processing_time], changed}],
escalus:fresh_story([{mongoose_metrics, MongooseMetrics} | Config],
[{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
escalus_client:send(Alice, escalus_stanza:chat_to(Bob, <<"Hi!">>)),
escalus:assert(is_chat_message, [<<"Hi!">>], escalus_client:wait_for_stanza(Bob)),
escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi!">>)),
escalus:assert(is_chat_message, [<<"Hi!">>], escalus_client:wait_for_stanza(Alice))
escalus:assert(is_chat_message, [<<"Hi!">>], escalus_client:wait_for_stanza(Alice)),

% Assert that correct events have been executed
[instrument_helper:assert(Event, Label, fun(#{byte_size := BS}) -> BS > 0 end)
|| {Event, Label} <- tcp_instrumentation_events()],
instrument_helper:assert_not_emitted(tls_instrumentation_events(), true)
end).

too_big_stanza_is_rejected(Config) ->
Expand Down Expand Up @@ -236,3 +239,14 @@ escalus_start(Cfg, FlatCDs) ->
Clients = lists:reverse(RClients),
[ escalus_assert:has_no_stanzas(Client) || Client <- Clients ],
Clients.

instrumentation_events() ->
instrument_helper:declared_events(mongoose_c2s_listener, [#{}]).

tcp_instrumentation_events() ->
[{c2s_tcp_data_sent, #{}},
{c2s_tcp_data_received, #{}}].

tls_instrumentation_events() ->
[{c2s_tls_data_sent, #{}},
{c2s_tls_data_received, #{}}].
18 changes: 14 additions & 4 deletions big_tests/tests/websockets_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ suite() ->
%%--------------------------------------------------------------------

init_per_suite(Config) ->
instrument_helper:start(instrumentation_events()),
instrument_helper:start(instrumentation_events() ++ negative_instrumentation_events()),
Config1 = escalus:init_per_suite(Config),
Config2 = setup_listeners(Config1),
escalus:create_users(Config2, escalus:get_users([alice, geralt, geralt_s, carol])).
Expand Down Expand Up @@ -102,9 +102,7 @@ update_handler(Handler) ->

metrics_test(Config) ->
MongooseMetrics = [{[global, data, xmpp, received, xml_stanza_size], changed},
{[global, data, xmpp, sent, xml_stanza_size], changed},
{[global, data, xmpp, received, c2s, tcp], 0},
{[global, data, xmpp, sent, c2s, tcp], 0}],
{[global, data, xmpp, sent, xml_stanza_size], changed}],
escalus:story([{mongoose_metrics, MongooseMetrics} | Config],
[{geralt, 1}, {geralt_s, 1}],
fun(Geralt, GeraltS) ->
Expand All @@ -118,6 +116,9 @@ metrics_test(Config) ->
% Assert that correct events have been executed
[instrument_helper:assert(Event, Label, fun(#{byte_size := BS}) -> BS > 0 end)
|| {Event, Label} <- instrumentation_events()],

%% Verify C2S listener is not used
instrument_helper:assert_not_emitted(negative_instrumentation_events(), true),
ok
end).

Expand Down Expand Up @@ -170,3 +171,12 @@ escape_attrs(Config) ->

instrumentation_events() ->
instrument_helper:declared_events(mod_websockets, []).

negative_instrumentation_events() ->
[{Name, #{}} || Name <- negative_instrumentation_events_names()].

negative_instrumentation_events_names() ->
[c2s_tcp_data_sent,
c2s_tcp_data_received,
c2s_tls_data_sent,
c2s_tls_data_received].
16 changes: 8 additions & 8 deletions doc/operation-and-maintenance/MongooseIM-metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,14 @@ Metrics specific to an extension, e.g. Message Archive Management, are described
| ----------- | ---- | ----------- |
| `[global, data, xmpp, received, xml_stanza_size]` | histogram | A size (in bytes) of a received stanza after decryption. |
| `[global, data, xmpp, sent, xml_stanza_size]` | histogram | A size (in bytes) of a sent stanza before encryption. |
| `[global, data, xmpp, received, c2s, tcp]` | spiral | A size (in bytes) of unencrypted data received from a client via TCP channel. |
| `[global, data, xmpp, sent, c2s, tcp]` | spiral | A size (in bytes) of unencrypted data sent to a client via TCP channel. |
| `[global, data, xmpp, received, c2s, tls]` | spiral | A size (in bytes) of a data received from a client via TLS channel after decryption. |
| `[global, data, xmpp, sent, c2s, tls]` | spiral | A size (in bytes) of a data sent to a client via TLS channel before encryption. |
| `[global, data, xmpp, received, c2s, bosh]` | spiral | A size (in bytes) of a data received from a client via BOSH connection. |
| `[global, data, xmpp, sent, c2s, bosh]` | spiral | A size (in bytes) of a data sent to a client via BOSH connection. |
| `[global, data, xmpp, received, c2s, websocket]` | spiral | A size (in bytes) of a data received from a client via WebSocket connection. |
| `[global, data, xmpp, sent, c2s, websocket]` | spiral | A size (in bytes) of a data sent to a client via WebSocket connection. |
| `[global, c2s_tcp_data_received, byte_size]` | spiral | A size (in bytes) of unencrypted data received from a client via TCP channel. |
| `[global, c2s_tcp_data_sent, byte_size]` | spiral | A size (in bytes) of unencrypted data sent to a client via TCP channel. |
| `[global, c2s_tls_data_received, byte_size]` | spiral | A size (in bytes) of a data received from a client via TLS channel after decryption. |
| `[global, c2s_tls_data_sent, byte_size]` | spiral | A size (in bytes) of a data sent to a client via TLS channel before encryption. |
| `[global, mod_bosh_data_received, byte_size]` | spiral | A size (in bytes) of a data received from a client via BOSH connection. |
| `[global, mod_bosh_data_sent, byte_size]` | spiral | A size (in bytes) of a data sent to a client via BOSH connection. |
| `[global, mod_websocket_data_received, byte_size]` | spiral | A size (in bytes) of a data received from a client via WebSocket connection. |
| `[global, mod_websocket_data_sent, byte_size]` | spiral | A size (in bytes) of a data sent to a client via WebSocket connection. |
| `[global, data, xmpp, received, s2s]` | spiral | A size (in bytes) of a data received via TCP and TLS (after decryption) Server-to-Server connections. |
| `[global, data, xmpp, sent, s2s]` | spiral | A size (in bytes) of a data sent via TCP and TLS (before encryption) Server-to-Server connections. |
| `[global, data, xmpp, received, component]` | spiral | A size (in bytes) of a data received from XMPP component. |
Expand Down
14 changes: 13 additions & 1 deletion src/c2s/mongoose_c2s_listener.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
-include("mongoose.hrl").

-behaviour(mongoose_listener).
-export([start_listener/1]).
-export([start_listener/1,
instrumentation/1]).

-behaviour(ranch_protocol).
-export([start_link/3]).
Expand All @@ -18,6 +19,17 @@
-type options() :: #{module := module(),
atom() => any()}.

-spec instrumentation(options()) -> [mongoose_instrument:spec()].
instrumentation(_Opts) ->
[{c2s_tcp_data_sent, #{},
#{metrics => #{byte_size => spiral}}},
{c2s_tls_data_sent, #{},
#{metrics => #{byte_size => spiral}}},
{c2s_tcp_data_received, #{},
#{metrics => #{byte_size => spiral}}},
{c2s_tls_data_received, #{},
#{metrics => #{byte_size => spiral}}}].

%% mongoose_listener
-spec start_listener(options()) -> ok.
start_listener(Opts) ->
Expand Down
12 changes: 6 additions & 6 deletions src/c2s/mongoose_c2s_ranch.erl
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,16 @@ socket_handle_data(#state{transport = fast_tls, socket = TlsSocket}, {tcp, _, Da
case fast_tls:recv_data(TlsSocket, Data) of
{ok, DecryptedData} ->
DataSize = byte_size(DecryptedData),
mongoose_metrics:update(global, [data, xmpp, received, c2s, tls], DataSize),
mongoose_instrument:execute(c2s_tls_data_received, #{}, #{byte_size => DataSize}),

Check warning on line 80 in src/c2s/mongoose_c2s_ranch.erl

View check run for this annotation

Codecov / codecov/patch

src/c2s/mongoose_c2s_ranch.erl#L80

Added line #L80 was not covered by tests
DecryptedData;
{error, Reason} ->
{error, Reason}
end;
socket_handle_data(#state{transport = just_tls}, {ssl, _, Data}) ->
mongoose_metrics:update(global, [data, xmpp, received, c2s, tls], byte_size(Data)),
mongoose_instrument:execute(c2s_tls_data_received, #{}, #{byte_size => byte_size(Data)}),

Check warning on line 86 in src/c2s/mongoose_c2s_ranch.erl

View check run for this annotation

Codecov / codecov/patch

src/c2s/mongoose_c2s_ranch.erl#L86

Added line #L86 was not covered by tests
Data;
socket_handle_data(#state{transport = ranch_tcp, socket = Socket}, {tcp, Socket, Data}) ->
mongoose_metrics:update(global, [data, xmpp, received, c2s, tcp], byte_size(Data)),
mongoose_instrument:execute(c2s_tcp_data_received, #{}, #{byte_size => byte_size(Data)}),
Data.

-spec socket_activate(state()) -> ok.
Expand Down Expand Up @@ -118,13 +118,13 @@ socket_send_xml(#state{transport = Transport, socket = Socket}, XML) ->

-spec send(transport(), ranch_transport:socket(), iodata()) -> ok | {error, term()}.
send(fast_tls, Socket, Data) ->
mongoose_metrics:update(global, [data, xmpp, sent, c2s, tls], iolist_size(Data)),
mongoose_instrument:execute(c2s_tls_data_sent, #{}, #{byte_size => iolist_size(Data)}),

Check warning on line 121 in src/c2s/mongoose_c2s_ranch.erl

View check run for this annotation

Codecov / codecov/patch

src/c2s/mongoose_c2s_ranch.erl#L121

Added line #L121 was not covered by tests
fast_tls:send(Socket, Data);
send(just_tls, Socket, Data) ->
mongoose_metrics:update(global, [data, xmpp, sent, c2s, tls], iolist_size(Data)),
mongoose_instrument:execute(c2s_tls_data_sent, #{}, #{byte_size => iolist_size(Data)}),

Check warning on line 124 in src/c2s/mongoose_c2s_ranch.erl

View check run for this annotation

Codecov / codecov/patch

src/c2s/mongoose_c2s_ranch.erl#L124

Added line #L124 was not covered by tests
just_tls:send(Socket, Data);
send(ranch_tcp, Socket, Data) ->
mongoose_metrics:update(global, [data, xmpp, sent, c2s, tcp], iolist_size(Data)),
mongoose_instrument:execute(c2s_tcp_data_sent, #{}, #{byte_size => iolist_size(Data)}),
ranch_tcp:send(Socket, Data).

-spec get_peer_certificate(state(), mongoose_listener:options()) ->
Expand Down
4 changes: 0 additions & 4 deletions src/metrics/mongoose_metrics_definitions.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,8 @@
]).

-define(GLOBAL_SPIRALS, [
[data, xmpp, received, c2s, tcp],
[data, xmpp, received, c2s, tls],
[data, xmpp, received, s2s],
[data, xmpp, received, component],
[data, xmpp, sent, c2s, tcp],
[data, xmpp, sent, c2s, tls],
[data, xmpp, sent, s2s],
[data, xmpp, sent, component]
]).
Expand Down

0 comments on commit 43fbd31

Please sign in to comment.