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