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