./ct_report/coverage/mongoose_system_metrics_collector.COVER.html

1 -module(mongoose_system_metrics_collector).
2
3 -include("mongoose.hrl").
4
5 -type report_struct() ::
6 #{
7 report_name := term(),
8 key := term(),
9 value := term()
10 }.
11
12 -export_type([report_struct/0]).
13
14 -export([collect/1]).
15
16 collect(PrevReport) ->
17 43 ReportResults = [ get_reports(RGetter) || RGetter <- report_getters()],
18 43 StanzasCount = get_xmpp_stanzas_count(PrevReport),
19 43 lists:flatten(ReportResults ++ StanzasCount).
20
21 -spec get_reports(fun(() -> [report_struct()])) -> [report_struct()].
22 get_reports(Fun) ->
23 559 Fun().
24
25 -spec report_getters() -> [fun(() -> [report_struct()])].
26 report_getters() ->
27 43 [
28 fun get_hosts_count/0,
29 fun get_domains_count/0,
30 fun get_modules/0,
31 fun get_number_of_custom_modules/0,
32 fun get_uptime/0,
33 fun get_cluster_size/0,
34 fun get_version/0,
35 fun get_components/0,
36 fun get_api/0,
37 fun get_transport_mechanisms/0,
38 fun get_tls_options/0,
39 fun get_outgoing_pools/0,
40 fun get_config_type/0
41 ].
42
43 get_hosts_count() ->
44 43 HostTypes = ?ALL_HOST_TYPES,
45 43 NumberOfHosts = length(HostTypes),
46 43 [#{report_name => hosts, key => count, value => NumberOfHosts}].
47
48 get_domains_count() ->
49 43 DomainsCount = mongoose_domain_core:domains_count(),
50 43 [#{report_name => domains, key => count, value => DomainsCount}].
51
52 get_modules() ->
53 43 HostTypes = ?ALL_HOST_TYPES,
54 43 AllModules = lists:flatten([gen_mod:loaded_modules(H) || H <- HostTypes]),
55 43 ModulesToReport = filter_behaviour_implementations(lists:usort(AllModules),
56 mongoose_module_metrics),
57 43 ModsWithOpts = [get_modules_metrics(Host, ModulesToReport) || Host <- HostTypes],
58 43 [report_module_with_opts(Mod, Opt) || {Mod, Opt} <- lists:flatten(ModsWithOpts)].
59
60 filter_behaviour_implementations(Modules, Behaviour) ->
61 129 lists:filter(
62 fun(M) ->
63 5164 try lists:keyfind([Behaviour], 2, M:module_info(attributes)) of
64 156 {behavior, _} -> true;
65 4807 {behaviour, _} -> true;
66 201 _ -> false
67 catch
68
:-(
_:_ -> false
69 end
70 end, Modules).
71
72 get_modules_metrics(Host, Modules) ->
73 242 lists:map(
74 fun(M) ->
75 3143 case erlang:function_exported(M, config_metrics, 1) of
76 731 true -> {M, M:config_metrics(Host)};
77 2412 false -> {M, [{none, none}]}
78 end
79 end, Modules).
80
81 report_module_with_opts(Module, Opts) ->
82 3143 lists:map(
83 fun({OptKey, OptValue}) ->
84 3143 #{report_name => Module, key => OptKey, value => OptValue}
85 end,Opts).
86
87 get_number_of_custom_modules() ->
88 43 HostTypes = ?ALL_HOST_TYPES,
89 43 AllModules = lists:flatten(
90 lists:map(fun gen_mod:loaded_modules/1, HostTypes)),
91 43 GenMods = filter_behaviour_implementations(AllModules, gen_mod),
92 43 GenModsSet = sets:from_list(GenMods),
93 43 MetricsModule = filter_behaviour_implementations(AllModules,
94 mongoose_module_metrics),
95 43 MetricsModuleSet = sets:from_list(MetricsModule),
96 43 CountCustomMods= sets:size(sets:subtract(GenModsSet, MetricsModuleSet)),
97 43 #{report_name => custom_modules, key => count, value => CountCustomMods}.
98
99 get_uptime() ->
100 43 {Uptime, _} = statistics(wall_clock),
101 43 UptimeSeconds = Uptime div 1000,
102 43 {D, {H, M, S}} = calendar:seconds_to_daystime(UptimeSeconds),
103 43 Formatted = io_lib:format("~4..0B-~2..0B:~2..0B:~2..0B", [D,H,M,S]),
104 43 [#{report_name => cluster, key => uptime, value => list_to_binary(Formatted)}].
105
106 get_cluster_size() ->
107 43 NodesNo = length(nodes()) + 1,
108 43 [#{report_name => cluster, key => number_of_nodes, value => NodesNo}].
109
110 get_version() ->
111 43 case lists:keyfind(mongooseim, 1, application:which_applications()) of
112 {_, _, Version} ->
113 43 #{report_name => cluster, key => mim_version, value => list_to_binary(Version)};
114 _ ->
115
:-(
[]
116 end.
117
118 get_components() ->
119 43 Domains = mongoose_router:get_all_domains() ++ ejabberd_router:dirty_get_all_components(all),
120 43 Components = [ejabberd_router:lookup_component(D, node()) || D <- Domains],
121 43 LenComponents = length(lists:flatten(Components)),
122 43 #{report_name => cluster, key => number_of_components, value => LenComponents}.
123
124 get_api() ->
125 43 ApiList = filter_unknown_api(get_http_handler_modules()),
126 43 [#{report_name => http_api, key => Api, value => enabled} || Api <- ApiList].
127
128 filter_unknown_api(ApiList) ->
129 43 AllowedToReport = [ mongoose_api, mongoose_client_api_rooms_messages,
130 mongoose_client_api_rooms_users, mongoose_client_api_rooms_config,
131 mongoose_client_api_rooms ,mongoose_client_api_contacts,
132 mongoose_client_api_messages, lasse_handler, mongoose_api_admin,
133 mod_bosh, mod_websockets, mod_revproxy],
134 43 [Api || Api <- ApiList, lists:member(Api, AllowedToReport)].
135
136 get_transport_mechanisms() ->
137 43 HTTP = [Mod || Mod <- get_http_handler_modules(),
138 688 Mod =:= mod_bosh orelse Mod =:= mod_websockets],
139 43 TCP = lists:usort([tcp || #{proto := tcp} <- get_listeners(ejabberd_c2s)]),
140 43 [#{report_name => transport_mechanism,
141 key => Transport,
142 43 value => enabled} || Transport <- HTTP ++ TCP].
143
144 get_http_handler_modules() ->
145 86 Listeners = get_listeners(ejabberd_cowboy),
146 86 Modules = lists:flatten([Modules || #{modules := Modules} <- Listeners]),
147 % Modules Option can have variable number of elements. To be more
148 % error-proof, extracting 3rd element instead of pattern matching.
149 86 lists:usort(lists:map(fun(Module) -> element(3, Module) end, Modules)).
150
151 get_listeners(Module) ->
152 172 Listeners = mongoose_config:get_opt(listen),
153 172 lists:filter(fun(#{module := Mod}) -> Mod =:= Module end, Listeners).
154
155 get_tls_options() ->
156 43 TLSOptions = lists:flatmap(fun extract_tls_options/1, get_listeners(ejabberd_c2s)),
157 43 [#{report_name => tls_option, key => TLSMode, value => TLSModule} ||
158 43 {TLSMode, TLSModule} <- lists:usort(TLSOptions)].
159
160 extract_tls_options(#{tls := Opts}) ->
161 44 Modes = [starttls, starttls_required, tls],
162 44 case [Opt || Opt <- Opts, lists:member(Opt, Modes)] of
163 [TLSMode] ->
164 44 TLSModule = proplists:get_value(tls_module, Opts, fast_tls),
165 44 [{TLSMode, TLSModule}];
166 _ ->
167
:-(
[]
168 end;
169 39 extract_tls_options(_) -> [].
170
171 get_outgoing_pools() ->
172 43 OutgoingPools = mongoose_config:get_opt(outgoing_pools, []),
173 43 [#{report_name => outgoing_pools,
174 key => type,
175 43 value => Type} || #{type := Type} <- OutgoingPools].
176
177 get_xmpp_stanzas_count(PrevReport) ->
178 43 StanzaTypes = [xmppMessageSent, xmppMessageReceived, xmppIqSent,
179 xmppIqReceived, xmppPresenceSent, xmppPresenceReceived],
180 43 NewCount = [count_stanzas(StanzaType) || StanzaType <- StanzaTypes],
181 43 StanzasCount = calculate_stanza_rate(PrevReport, NewCount),
182 43 [#{report_name => StanzaType,
183 key => Total,
184 43 value => Increment} || {StanzaType, Total, Increment} <- StanzasCount].
185
186 count_stanzas(StanzaType) ->
187 258 ExometerResults = exometer:get_values(['_', StanzaType]),
188 258 StanzaCount = lists:foldl(fun({ _, [{count,Count}, {one, _}]}, Sum) ->
189 1452 Count + Sum end, 0, ExometerResults),
190 258 {StanzaType, StanzaCount}.
191
192 calculate_stanza_rate([], NewCount) ->
193 21 [{Type, Count, Count} || {Type, Count} <- NewCount];
194 calculate_stanza_rate(PrevReport, NewCount) ->
195 22 ReportProplist = [{Name, Key} ||
196 22 #{report_name := Name, key := Key} <- PrevReport],
197 22 [{Type, Count,
198 case proplists:get_value(Type, ReportProplist) of
199
:-(
undefined -> Count;
200 132 Total -> Count-Total
201 22 end} || {Type, Count} <- NewCount].
202
203 get_config_type() ->
204 43 ConfigPath = mongoose_config:get_config_path(),
205 43 ConfigType = case filename:extension(ConfigPath) of
206 43 ".toml" -> toml;
207
:-(
".cfg" -> cfg;
208
:-(
_ -> unknown_config_type
209 end,
210 43 [#{report_name => cluster, key => config_type, value => ConfigType}].
Line Hits Source