Line 0
Link Here
|
|
|
1 |
%%%---------------------------------------------------------------------- |
2 |
%%% File : mod_statsdx.erl |
3 |
%%% Author : Badlop <badlop@ono.com> |
4 |
%%% Purpose : Calculates and gathers statistics actively |
5 |
%%% Created : |
6 |
%%% Id : 0.2.3 |
7 |
%%%---------------------------------------------------------------------- |
8 |
|
9 |
%%% INSTALL: |
10 |
%%% 1 Copy this file to ejabberd/src/mod_statsdx.erl |
11 |
%%% 2 Recompile ejabberd |
12 |
%%% 3 Add to ejabberd.cfg, 'modules' section the basic configuration: |
13 |
%%% {mod_statsdx, []}, |
14 |
|
15 |
%%% CONFIGURE: |
16 |
%%% hooks: Set to 'false' to remove hooks and related statistics if you don't need them (default: true) |
17 |
|
18 |
%%% EXAMPLE CONFIGURATION: |
19 |
%%% {mod_statsdx, [{hooks, false}]}, |
20 |
|
21 |
%%% FEATURE REQUESTS: |
22 |
%%% - fix the problem with plain/ssl/tlsusers, it crashes ejabberd |
23 |
%%% - traffic: send bytes per second, received bps |
24 |
%%% - connections to a transport |
25 |
%%% - traffic: send presence per second, received mps |
26 |
%%% - Number of SASL c2s connections |
27 |
%%% - improve to work in distributed server |
28 |
|
29 |
-module(mod_statsdx). |
30 |
-author(''). |
31 |
-vsn(''). |
32 |
|
33 |
-behaviour(gen_mod). |
34 |
|
35 |
-export([start/2, loop/0, stop/1, get/2, |
36 |
remove_user/2, user_send_packet/3, user_receive_packet/4, |
37 |
user_login/1, user_logout/4]). |
38 |
|
39 |
-include("ejabberd.hrl"). |
40 |
-include("jlib.hrl"). |
41 |
-include("mod_roster.hrl"). |
42 |
|
43 |
-define(PROCNAME, ejabberd_mod_statsdx). |
44 |
-define(T(Text), translate:translate("Lang", Text)). |
45 |
|
46 |
%% ------------------- |
47 |
%% Module control |
48 |
%% ------------------- |
49 |
|
50 |
start(Host, Opts) -> |
51 |
Hooks = gen_mod:get_opt(hooks, Opts, true), |
52 |
% Default value for the counters |
53 |
CD = case Hooks of |
54 |
true -> 0; |
55 |
false -> "disabled" |
56 |
end, |
57 |
case whereis(?PROCNAME) of |
58 |
undefined -> |
59 |
application:start(os_mon), |
60 |
ets:new(stats, [named_table, public]), |
61 |
ets:insert(stats, {{user_login, server}, CD}), |
62 |
ets:insert(stats, {{user_logout, server}, CD}), |
63 |
ets:insert(stats, {{remove_user, server}, CD}), |
64 |
lists:foreach( |
65 |
fun(E) -> ets:insert(stats, {{client, server, E}, CD}) end, |
66 |
list_elem(clients, id) |
67 |
), |
68 |
lists:foreach( |
69 |
fun(E) -> ets:insert(stats, {{os, server, E}, CD}) end, |
70 |
list_elem(oss, id) |
71 |
), |
72 |
register(?PROCNAME, spawn(?MODULE, loop, [])); |
73 |
_ -> |
74 |
ok |
75 |
end, |
76 |
ets:insert(stats, {{user_login, Host}, CD}), |
77 |
ets:insert(stats, {{user_logout, Host}, CD}), |
78 |
ets:insert(stats, {{remove_user, Host}, CD}), |
79 |
ets:insert(stats, {{send, Host, iq, in}, CD}), |
80 |
ets:insert(stats, {{send, Host, iq, out}, CD}), |
81 |
ets:insert(stats, {{send, Host, message, in}, CD}), |
82 |
ets:insert(stats, {{send, Host, message, out}, CD}), |
83 |
ets:insert(stats, {{send, Host, presence, in}, CD}), |
84 |
ets:insert(stats, {{send, Host, presence, out}, CD}), |
85 |
ets:insert(stats, {{recv, Host, iq, in}, CD}), |
86 |
ets:insert(stats, {{recv, Host, iq, out}, CD}), |
87 |
ets:insert(stats, {{recv, Host, message, in}, CD}), |
88 |
ets:insert(stats, {{recv, Host, message, out}, CD}), |
89 |
ets:insert(stats, {{recv, Host, presence, in}, CD}), |
90 |
ets:insert(stats, {{recv, Host, presence, out}, CD}), |
91 |
lists:foreach( |
92 |
fun(E) -> ets:insert(stats, {{client, Host, E}, CD}) end, |
93 |
list_elem(clients, id) |
94 |
), |
95 |
lists:foreach( |
96 |
fun(E) -> ets:insert(stats, {{os, Host, E}, CD}) end, |
97 |
list_elem(oss, id) |
98 |
), |
99 |
case Hooks of |
100 |
true -> |
101 |
ejabberd_hooks:add(user_send_packet, Host, ?MODULE, user_send_packet, 90), |
102 |
ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, user_receive_packet, 90), |
103 |
ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 90), |
104 |
ejabberd_hooks:add(user_available_hook, Host, ?MODULE, user_login, 90), |
105 |
ejabberd_hooks:add(unset_presence_hook, Host, ?MODULE, user_logout, 90); |
106 |
false -> |
107 |
ok |
108 |
end. |
109 |
|
110 |
loop() -> |
111 |
receive |
112 |
stop -> ok |
113 |
end. |
114 |
|
115 |
stop(Host) -> |
116 |
ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, user_send_packet, 60), |
117 |
ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, user_receive_packet, 60), |
118 |
ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 60), |
119 |
ets:delete(stats), |
120 |
case whereis(?PROCNAME) of |
121 |
undefined -> ok; |
122 |
_ -> |
123 |
?PROCNAME ! stop |
124 |
end. |
125 |
|
126 |
|
127 |
remove_user(_User, Server) -> |
128 |
ets:update_counter(stats, {remove_user, Server}, 1), |
129 |
ets:update_counter(stats, {remove_user, server}, 1). |
130 |
|
131 |
user_send_packet(FromJID, ToJID, NewEl) -> |
132 |
Host = FromJID#jid.lserver, |
133 |
HostTo = ToJID#jid.lserver, |
134 |
{xmlelement, Type, _, _} = NewEl, |
135 |
Type2 = case Type of |
136 |
"iq" -> iq; |
137 |
"message" -> message; |
138 |
"presence" -> presence |
139 |
end, |
140 |
Dest = case is_host(HostTo, Host) of |
141 |
true -> in; |
142 |
false -> out |
143 |
end, |
144 |
ets:update_counter(stats, {send, Host, Type2, Dest}, 1), |
145 |
|
146 |
% Registrarse para tramitar Host/mod_stats2file |
147 |
case list_to_atom(ToJID#jid.lresource) of |
148 |
?MODULE -> received_response(FromJID, ToJID, NewEl); |
149 |
_ -> ok |
150 |
end. |
151 |
|
152 |
user_receive_packet(_JID, From, To, FixedPacket) -> |
153 |
HostFrom = From#jid.lserver, |
154 |
Host = To#jid.lserver, |
155 |
{xmlelement, Type, _, _} = FixedPacket, |
156 |
Type2 = case Type of |
157 |
"iq" -> iq; |
158 |
"message" -> message; |
159 |
"presence" -> presence |
160 |
end, |
161 |
Dest = case is_host(HostFrom, Host) of |
162 |
true -> in; |
163 |
false -> out |
164 |
end, |
165 |
ets:update_counter(stats, {recv, Host, Type2, Dest}, 1). |
166 |
|
167 |
|
168 |
%% ------------------- |
169 |
%% get(* |
170 |
%% ------------------- |
171 |
|
172 |
%gett(Arg) -> get(node(), [Arg, title]). |
173 |
getl(Args) -> get(node(), [Args]). |
174 |
getl(Args, Host) -> get(node(), [Args, Host]). |
175 |
|
176 |
%get(_Node, ["", title]) -> ""; |
177 |
|
178 |
get(global, A) -> get(node(), A); |
179 |
|
180 |
get(_, [{"reductions", _}, title]) -> "Reductions (per minute)"; |
181 |
get(_, [{"reductions", I}]) -> calc_avg(element(2, statistics(reductions)), I); %+++ |
182 |
|
183 |
get(_, ["cpu_avg1", title]) -> "Average system load (1 min)"; |
184 |
get(N, ["cpu_avg1"]) -> rpc:call(N, cpu_sup, avg1, [])/256; |
185 |
get(_, ["cpu_avg5", title]) -> "Average system load (5 min)"; |
186 |
get(N, ["cpu_avg5"]) -> rpc:call(N, cpu_sup, avg1, [])/256; |
187 |
get(_, ["cpu_avg15", title]) -> "Average system load (15 min)"; |
188 |
get(N, ["cpu_avg15"]) -> rpc:call(N, cpu_sup, avg15, [])/256; |
189 |
get(_, ["cpu_nprocs", title]) -> "Number of UNIX processes running on this machine"; |
190 |
get(N, ["cpu_nprocs"]) -> rpc:call(N, cpu_sup, nprocs, []); |
191 |
get(_, ["cpu_util", title]) -> "CPU utilization"; |
192 |
get(N, ["cpu_util"]) -> rpc:call(N, cpu_sup, util, []); |
193 |
|
194 |
get(_, [{"cpu_util_user", _}, title]) -> "CPU utilization - user"; |
195 |
get(_, [{"cpu_util_nice_user", _}, title]) -> "CPU utilization - nice_user"; |
196 |
get(_, [{"cpu_util_kernel", _}, title]) -> "CPU utilization - kernel"; |
197 |
get(_, [{"cpu_util_wait", _}, title]) -> "CPU utilization - wait"; |
198 |
get(_, [{"cpu_util_idle", _}, title]) -> "CPU utilization - idle"; |
199 |
get(_, [{"cpu_util_user", U}]) -> [{user, Us}, _, _] = element(2, U), Us; |
200 |
get(_, [{"cpu_util_nice_user", U}]) -> [_, {nice_user, NU}, _] = element(2, U), NU; |
201 |
get(_, [{"cpu_util_kernel", U}]) -> [_, _, {kernel, K}] = element(2, U), K; |
202 |
get(_, [{"cpu_util_wait", U}]) -> |
203 |
case element(3, U) of |
204 |
[{wait, W}, {idle, _}] -> W; % Solaris |
205 |
[{idle, _}] -> 0 |
206 |
end; |
207 |
get(_, [{"cpu_util_idle", U}]) -> |
208 |
case element(3, U) of |
209 |
[{wait, _}, {idle, I}] -> I; % Solaris |
210 |
[{idle, I}] -> I |
211 |
end; |
212 |
|
213 |
get(_, [{"client", Id}, title]) -> atom_to_list(Id); |
214 |
get(_, [{"client", Id}, Host]) -> [{_, C}] = ets:lookup(stats, {client, Host, Id}), C; |
215 |
get(_, ["client", title]) -> "Client"; |
216 |
get(N, ["client", Host]) -> |
217 |
lists:map( |
218 |
fun(Id) -> |
219 |
[Id_string] = io_lib:format("~p", [Id]), |
220 |
{Id_string, get(N, [{"client", Id}, Host])} |
221 |
end, |
222 |
lists:usort(list_elem(clients, id)) |
223 |
); |
224 |
|
225 |
get(_, [{"os", Id}, title]) -> atom_to_list(Id); |
226 |
get(_, [{"os", Id}, list]) -> lists:usort(list_elem(oss, Id)); |
227 |
get(_, [{"os", Id}, Host]) -> [{_, C}] = ets:lookup(stats, {os, Host, Id}), C; |
228 |
get(_, ["os", title]) -> "Operating System"; |
229 |
get(N, ["os", Host]) -> |
230 |
lists:map( |
231 |
fun(Id) -> |
232 |
[Id_string] = io_lib:format("~p", [Id]), |
233 |
{Id_string, get(N, [{"os", Id}, Host])} |
234 |
end, |
235 |
lists:usort(list_elem(oss, id)) |
236 |
); |
237 |
|
238 |
get(_, [{"memsup_system", _}, title]) -> "Memory physical (bytes)"; |
239 |
get(_, [{"memsup_system", M}]) -> [_, _, {system_total_memory, R}] = M, R; |
240 |
get(_, [{"memsup_free", _}, title]) -> "Memory free (bytes)"; |
241 |
get(_, [{"memsup_free", M}]) -> [_, {free_memory, R}, _] = M, R; |
242 |
|
243 |
get(_, [{"user_login", _}, title]) -> "Logins (per minute)"; |
244 |
get(_, [{"user_login", I}, Host]) -> get_stat({user_login, Host}, I); |
245 |
get(_, [{"user_logout", _}, title]) -> "Logouts (per minute)"; |
246 |
get(_, [{"user_logout", I}, Host]) -> get_stat({user_logout, Host}, I); |
247 |
get(_, [{"remove_user", _}, title]) -> "Accounts deleted (per minute)"; |
248 |
get(_, [{"remove_user", I}, Host]) -> get_stat({remove_user, Host}, I); |
249 |
get(_, [{Table, Type, Dest, _}, title]) -> filename:flatten([Table, Type, Dest]); |
250 |
get(_, [{Table, Type, Dest, I}, Host]) -> get_stat({Table, Host, Type, Dest}, I); |
251 |
|
252 |
get(_, ["localtime", title]) -> "Local time"; |
253 |
get(N, ["localtime"]) -> |
254 |
localtime_to_string(rpc:call(N, erlang, localtime, [])); |
255 |
|
256 |
get(_, ["vhost", title]) -> "Virtual host"; |
257 |
get(_, ["vhost", Host]) -> Host; |
258 |
|
259 |
get(_, ["totalerlproc", title]) -> "Total Erlang processes running"; |
260 |
get(N, ["totalerlproc"]) -> rpc:call(N, erlang, system_info, [process_count]); |
261 |
get(_, ["operatingsystem", title]) -> "Operating System"; |
262 |
get(N, ["operatingsystem"]) -> {rpc:call(N, os, type, []), rpc:call(N, os, version, [])}; |
263 |
get(_, ["erlangmachine", title]) -> "Erlang machine"; |
264 |
get(N, ["erlangmachine"]) -> rpc:call(N, erlang, system_info, [system_version]); |
265 |
get(_, ["erlangmachinetarget", title]) -> "Erlang machine target"; |
266 |
get(N, ["erlangmachinetarget"]) -> rpc:call(N, erlang, system_info, [system_architecture]); |
267 |
get(_, ["maxprocallowed", title]) -> "Maximum processes allowed"; |
268 |
get(N, ["maxprocallowed"]) -> rpc:call(N, erlang, system_info, [process_limit]); |
269 |
get(_, ["procqueue", title]) -> "Number of processes on the running queue"; |
270 |
get(N, ["procqueue"]) -> rpc:call(N, erlang, statistics, [run_queue]); |
271 |
get(_, ["uptimehuman", title]) -> "Uptime"; |
272 |
get(N, ["uptimehuman"]) -> |
273 |
io_lib:format("~w days ~w hours ~w minutes ~p seconds", ms_to_time(get(N, ["uptime"]))); |
274 |
get(_, ["lastrestart", title]) -> "Last restart"; |
275 |
get(N, ["lastrestart"]) -> |
276 |
Now = calendar:datetime_to_gregorian_seconds(rpc:call(N, erlang, localtime, [])), |
277 |
UptimeMS = get(N, ["uptime"]), |
278 |
Last_restartS = trunc(Now - (UptimeMS/1000)), |
279 |
Last_restart = calendar:gregorian_seconds_to_datetime(Last_restartS), |
280 |
localtime_to_string(Last_restart); |
281 |
|
282 |
get(_, ["plainusers", title]) -> "Plain users"; |
283 |
get(_, ["plainusers"]) -> {R, _, _} = get_connectiontype(), R; |
284 |
get(_, ["tlsusers", title]) -> "TLS users"; |
285 |
get(_, ["tlsusers"]) -> {_, R, _} = get_connectiontype(), R; |
286 |
get(_, ["sslusers", title]) -> "SSL users"; |
287 |
get(_, ["sslusers"]) -> {_, _, R} = get_connectiontype(), R; |
288 |
get(_, ["registeredusers", title]) -> "Registered users"; |
289 |
get(N, ["registeredusers"]) -> rpc:call(N, mnesia, table_info, [passwd, size]); |
290 |
get(_, ["registeredusers", Host]) -> length(ejabberd_auth:get_vh_registered_users(Host)); |
291 |
get(_, ["authusers", title]) -> "Authenticated users"; |
292 |
get(N, ["authusers"]) -> rpc:call(N, mnesia, table_info, [session, size]); |
293 |
get(_, ["authusers", Host]) -> get_authusers(Host); |
294 |
get(_, ["onlineusers", title]) -> "Online users"; |
295 |
get(N, ["onlineusers"]) -> rpc:call(N, mnesia, table_info, [presence, size]); |
296 |
get(_, ["onlineusers", Host]) -> length(ejabberd_sm:get_vh_session_list(Host)); |
297 |
get(_, ["httppollusers", title]) -> "HTTP-Poll users (aprox)"; |
298 |
get(N, ["httppollusers"]) -> rpc:call(N, mnesia, table_info, [http_poll, size]); |
299 |
|
300 |
get(_, ["s2sconnections", title]) -> "Outgoing S2S connections"; |
301 |
get(_, ["s2sconnections"]) -> length(get_S2SConns()); |
302 |
get(_, ["s2sconnections", Host]) -> get_s2sconnections(Host); |
303 |
get(_, ["s2sservers", title]) -> "Outgoing S2S servers"; |
304 |
get(_, ["s2sservers"]) -> length(lists:usort([element(2, C) || C <- get_S2SConns()])); |
305 |
|
306 |
get(_, ["offlinemsg", title]) -> "Offline messages"; |
307 |
get(N, ["offlinemsg"]) -> rpc:call(N, mnesia, table_info, [offline_msg, size]); |
308 |
get(_, ["offlinemsg", Host]) -> get_offlinemsg(Host); |
309 |
get(_, ["totalrosteritems", title]) -> "Total roster items"; |
310 |
get(N, ["totalrosteritems"]) -> rpc:call(N, mnesia, table_info, [roster, size]); |
311 |
get(_, ["totalrosteritems", Host]) -> get_totalrosteritems(Host); |
312 |
|
313 |
get(_, ["meanitemsinroster", title]) -> "Mean items in roster"; |
314 |
get(_, ["meanitemsinroster"]) -> get_meanitemsinroster(); |
315 |
get(_, ["meanitemsinroster", Host]) -> get_meanitemsinroster(Host); |
316 |
|
317 |
get(_, ["totalmucrooms", title]) -> "Total MUC rooms"; |
318 |
get(_, ["totalmucrooms"]) -> ets:info(muc_online_room, size); |
319 |
get(_, ["totalmucrooms", Host]) -> get_totalmucrooms(Host); |
320 |
get(_, ["permmucrooms", title]) -> "Permanent MUC rooms"; |
321 |
get(N, ["permmucrooms"]) -> rpc:call(N, mnesia, table_info, [muc_room, size]); |
322 |
get(_, ["permmucrooms", Host]) -> get_permmucrooms(Host); |
323 |
get(_, ["regmucrooms", title]) -> "Users registered at MUC service"; |
324 |
get(N, ["regmucrooms"]) -> rpc:call(N, mnesia, table_info, [muc_registered, size]); |
325 |
get(_, ["regmucrooms", Host]) -> get_regmucrooms(Host); |
326 |
get(_, ["regpubsubnodes", title]) -> "Registered nodes at Pub/Sub"; |
327 |
get(N, ["regpubsubnodes"]) -> rpc:call(N, mnesia, table_info, [pubsub_node, size]); |
328 |
get(_, ["vcards", title]) -> "Total vCards published"; |
329 |
get(N, ["vcards"]) -> rpc:call(N, mnesia, table_info, [vcard, size]); |
330 |
get(_, ["vcards", Host]) -> get_vcards(Host); |
331 |
|
332 |
get(_, ["ircconns", title]) -> "IRC connections"; |
333 |
get(_, ["ircconns"]) -> ets:info(irc_connection, size); |
334 |
get(_, ["ircconns", Host]) -> get_irccons(Host); |
335 |
get(_, ["uptime", title]) -> "Uptime"; |
336 |
get(N, ["uptime"]) -> element(1, rpc:call(N, erlang, statistics, [wall_clock])); |
337 |
get(_, ["cputime", title]) -> "CPU Time"; |
338 |
get(N, ["cputime"]) -> element(1, rpc:call(N, erlang, statistics, [runtime])); |
339 |
|
340 |
get(_, ["languages", title]) -> "Languages"; |
341 |
get(_, ["languages", Server]) -> get_languages(Server); |
342 |
|
343 |
get(_, ["client_os", title]) -> "Client/OS"; |
344 |
get(_, ["client_os", Server]) -> get_client_os(Server); |
345 |
|
346 |
get(N, A) -> |
347 |
io:format(" ----- node: '~p', A: '~p'~n", [N, A]), |
348 |
"666". |
349 |
|
350 |
%% ------------------- |
351 |
%% get_* |
352 |
%% ------------------- |
353 |
|
354 |
get_S2SConns() -> ejabberd_s2s:dirty_get_connections(). |
355 |
|
356 |
get_tls_drv() -> |
357 |
R = lists:filter( |
358 |
fun(P) -> |
359 |
case erlang:port_info(P, name) of |
360 |
{name, "tls_drv"} -> true; |
361 |
_ -> false |
362 |
end |
363 |
end, erlang:ports()), |
364 |
length(R). |
365 |
|
366 |
get_connections(Port) -> |
367 |
R = lists:filter( |
368 |
fun(P) -> |
369 |
case inet:port(P) of |
370 |
{ok, Port} -> true; |
371 |
_ -> false |
372 |
end |
373 |
end, erlang:ports()), |
374 |
length(R). |
375 |
|
376 |
get_totalrosteritems(Host) -> |
377 |
F = fun() -> |
378 |
F2 = fun(R, {H, A}) -> |
379 |
{_LUser, LServer, _LJID} = R#roster.usj, |
380 |
A2 = case LServer of |
381 |
H -> A+1; |
382 |
_ -> A |
383 |
end, |
384 |
{H, A2} |
385 |
end, |
386 |
mnesia:foldl(F2, {Host, 0}, roster) |
387 |
end, |
388 |
{atomic, {Host, Res}} = mnesia:transaction(F), |
389 |
Res. |
390 |
|
391 |
% Copied from ejabberd_sm.erl |
392 |
-record(session, {sid, usr, us, priority}). |
393 |
|
394 |
get_authusers(Host) -> |
395 |
F = fun() -> |
396 |
F2 = fun(R, {H, A}) -> |
397 |
{_LUser, LServer, _LResource} = R#session.usr, |
398 |
A2 = case LServer of |
399 |
H -> A+1; |
400 |
_ -> A |
401 |
end, |
402 |
{H, A2} |
403 |
end, |
404 |
mnesia:foldl(F2, {Host, 0}, session) |
405 |
end, |
406 |
{atomic, {Host, Res}} = mnesia:transaction(F), |
407 |
Res. |
408 |
|
409 |
-record(offline_msg, {us, timestamp, expire, from, to, packet}). |
410 |
|
411 |
get_offlinemsg(Host) -> |
412 |
F = fun() -> |
413 |
F2 = fun(R, {H, A}) -> |
414 |
{_LUser, LServer} = R#offline_msg.us, |
415 |
A2 = case LServer of |
416 |
H -> A+1; |
417 |
_ -> A |
418 |
end, |
419 |
{H, A2} |
420 |
end, |
421 |
mnesia:foldl(F2, {Host, 0}, offline_msg) |
422 |
end, |
423 |
{atomic, {Host, Res}} = mnesia:transaction(F), |
424 |
Res. |
425 |
|
426 |
-record(vcard, {us, vcard}). |
427 |
|
428 |
get_vcards(Host) -> |
429 |
F = fun() -> |
430 |
F2 = fun(R, {H, A}) -> |
431 |
{_LUser, LServer} = R#vcard.us, |
432 |
A2 = case LServer of |
433 |
H -> A+1; |
434 |
_ -> A |
435 |
end, |
436 |
{H, A2} |
437 |
end, |
438 |
mnesia:foldl(F2, {Host, 0}, vcard) |
439 |
end, |
440 |
{atomic, {Host, Res}} = mnesia:transaction(F), |
441 |
Res. |
442 |
|
443 |
-record(s2s, {fromto, pid, key}). |
444 |
|
445 |
get_s2sconnections(Host) -> |
446 |
F = fun() -> |
447 |
F2 = fun(R, {H, A}) -> |
448 |
{MyServer, _Server} = R#s2s.fromto, |
449 |
A2 = case MyServer of |
450 |
H -> A+1; |
451 |
_ -> A |
452 |
end, |
453 |
{H, A2} |
454 |
end, |
455 |
mnesia:foldl(F2, {Host, 0}, s2s) |
456 |
end, |
457 |
{atomic, {Host, Res}} = mnesia:transaction(F), |
458 |
Res. |
459 |
|
460 |
-record(irc_connection, {jid_server_host, pid}). |
461 |
|
462 |
get_irccons(Host) -> |
463 |
F2 = fun(R, {H, A}) -> |
464 |
{From, _Server, _Host} = R#irc_connection.jid_server_host, |
465 |
A2 = case From#jid.lserver of |
466 |
H -> A+1; |
467 |
_ -> A |
468 |
end, |
469 |
{H, A2} |
470 |
end, |
471 |
{Host, Res} = ets:foldl(F2, {Host, 0}, irc_connection), |
472 |
Res. |
473 |
|
474 |
is_host(Host, Subhost) -> |
475 |
Pos = string:len(Host)-string:len(Subhost)+1, |
476 |
case string:rstr(Host, Subhost) of |
477 |
Pos -> true; |
478 |
_ -> false |
479 |
end. |
480 |
|
481 |
-record(muc_online_room, {name_host, pid}). |
482 |
|
483 |
get_totalmucrooms(Host) -> |
484 |
F2 = fun(R, {H, A}) -> |
485 |
{_Name, MUCHost} = R#muc_online_room.name_host, |
486 |
A2 = case is_host(MUCHost, H) of |
487 |
true -> A+1; |
488 |
false -> A |
489 |
end, |
490 |
{H, A2} |
491 |
end, |
492 |
{Host, Res} = ets:foldl(F2, {Host, 0}, muc_online_room), |
493 |
Res. |
494 |
|
495 |
-record(muc_room, {name_host, opts}). |
496 |
|
497 |
get_permmucrooms(Host) -> |
498 |
F = fun() -> |
499 |
F2 = fun(R, {H, A}) -> |
500 |
{_Name, MUCHost} = R#muc_room.name_host, |
501 |
A2 = case is_host(MUCHost, H) of |
502 |
true -> A+1; |
503 |
false -> A |
504 |
end, |
505 |
{H, A2} |
506 |
end, |
507 |
mnesia:foldl(F2, {Host, 0}, muc_room) |
508 |
end, |
509 |
{atomic, {Host, Res}} = mnesia:transaction(F), |
510 |
Res. |
511 |
|
512 |
-record(muc_registered, {us_host, nick}). |
513 |
|
514 |
get_regmucrooms(Host) -> |
515 |
F = fun() -> |
516 |
F2 = fun(R, {H, A}) -> |
517 |
{_User, MUCHost} = R#muc_registered.us_host, |
518 |
A2 = case is_host(MUCHost, H) of |
519 |
true -> A+1; |
520 |
false -> A |
521 |
end, |
522 |
{H, A2} |
523 |
end, |
524 |
mnesia:foldl(F2, {Host, 0}, muc_registered) |
525 |
end, |
526 |
{atomic, {Host, Res}} = mnesia:transaction(F), |
527 |
Res. |
528 |
|
529 |
get_stat(Stat, Ims) -> |
530 |
Res = ets:lookup(stats, Stat), |
531 |
ets:update_counter(stats, Stat, {2,1,0,0}), |
532 |
[{_, C}] = Res, |
533 |
calc_avg(C, Ims). |
534 |
%C. |
535 |
|
536 |
calc_avg(Count, TimeMS) -> |
537 |
TimeMIN = TimeMS/(1000*60), |
538 |
Count/TimeMIN. |
539 |
|
540 |
%% ------------------- |
541 |
%% utilities |
542 |
%% ------------------- |
543 |
|
544 |
get_connectiontype() -> |
545 |
C2 = get_connections(5222) -1, |
546 |
C3 = get_connections(5223) -1, |
547 |
NUplain = C2 + C3 - get_tls_drv(), |
548 |
NUtls = C2 - NUplain, |
549 |
NUssl = C3, |
550 |
{NUplain, NUtls, NUssl}. |
551 |
|
552 |
ms_to_time(T) -> |
553 |
DMS = 24*60*60*1000, |
554 |
HMS = 60*60*1000, |
555 |
MMS = 60*1000, |
556 |
SMS = 1000, |
557 |
D = trunc(T/DMS), |
558 |
H = trunc((T - (D*DMS)) / HMS), |
559 |
M = trunc((T - (D*DMS) - (H*HMS)) / MMS), |
560 |
S = trunc((T - (D*DMS) - (H*HMS) - (M*MMS)) / SMS), |
561 |
[D, H, M, S]. |
562 |
|
563 |
|
564 |
% Cuando un usuario conecta, pedirle iq:version a nombre de Host/mod_stats2file |
565 |
user_login(U) -> |
566 |
User = U#jid.luser, |
567 |
Host = U#jid.lserver, |
568 |
Resource = U#jid.lresource, |
569 |
ets:update_counter(stats, {user_login, server}, 1), |
570 |
ets:update_counter(stats, {user_login, Host}, 1), |
571 |
request_iqversion(User, Host, Resource). |
572 |
|
573 |
% cuando un usuario desconecta, buscar en la tabla su JID/USR y quitarlo |
574 |
user_logout(User, Host, Resource, _Status) -> |
575 |
ets:update_counter(stats, {user_logout, server}, 1), |
576 |
ets:update_counter(stats, {user_logout, Host}, 1), |
577 |
|
578 |
JID = jlib:make_jid(User, Host, Resource), |
579 |
case ets:lookup(stats, {session, JID}) of |
580 |
[{_, Client_id, OS_id, Lang}] -> |
581 |
ets:delete(stats, {session, JID}), |
582 |
ets:update_counter(stats, {client, Host, Client_id}, -1), |
583 |
ets:update_counter(stats, {client, server, Client_id}, -1), |
584 |
ets:update_counter(stats, {os, Host, OS_id}, -1), |
585 |
ets:update_counter(stats, {os, server, OS_id}, -1), |
586 |
update_counter_create(stats, {client_os, Host, Client_id, OS_id}, -1), |
587 |
update_counter_create(stats, {client_os, server, Client_id, OS_id}, -1), |
588 |
update_counter_create(stats, {lang, Host, Lang}, -1), |
589 |
update_counter_create(stats, {lang, server, Lang}, -1); |
590 |
[] -> |
591 |
ok |
592 |
end. |
593 |
|
594 |
request_iqversion(User, Host, Resource) -> |
595 |
From = jlib:make_jid("", Host, atom_to_list(?MODULE)), |
596 |
FromStr = jlib:jid_to_string(From), |
597 |
To = jlib:make_jid(User, Host, Resource), |
598 |
ToStr = jlib:jid_to_string(To), |
599 |
Packet = {xmlelement,"iq", |
600 |
[{"from",FromStr}, {"to",ToStr}, {"type","get"}, {"xml:lang","es"}], |
601 |
[{xmlcdata,"\n"}, {xmlcdata," "}, {xmlelement, "query", [{"xmlns","jabber:iq:version"}], []}, {xmlcdata,"\n"}]}, |
602 |
ejabberd_local:route(From, To, Packet). |
603 |
|
604 |
% cuando el virtualJID recibe una respuesta iqversion, |
605 |
% almacenar su JID/USR + client + OS en una tabla |
606 |
received_response(From, _To, {xmlelement, "iq", Attrs, Elc}) -> |
607 |
User = From#jid.luser, |
608 |
Host = From#jid.lserver, |
609 |
Resource = From#jid.lresource, |
610 |
|
611 |
"result" = xml:get_attr_s("type", Attrs), |
612 |
Lang = case xml:get_attr_s("xml:lang", Attrs) of |
613 |
[] -> "unknown"; |
614 |
L -> L |
615 |
end, |
616 |
update_counter_create(stats, {lang, Host, Lang}, 1), |
617 |
update_counter_create(stats, {lang, server, Lang}, 1), |
618 |
|
619 |
[El] = xml:remove_cdata(Elc), |
620 |
{xmlelement, _, Attrs2, _Els2} = El, |
621 |
?NS_VERSION = xml:get_attr_s("xmlns", Attrs2), |
622 |
|
623 |
Client = get_tag_cdata_subtag(El, "name"), |
624 |
%Version = get_tag_cdata_subtag(El, "version"), |
625 |
OS = get_tag_cdata_subtag(El, "os"), |
626 |
{Client_id, OS_id} = identify(Client, OS), |
627 |
|
628 |
ets:update_counter(stats, {client, Host, Client_id}, 1), |
629 |
ets:update_counter(stats, {client, server, Client_id}, 1), |
630 |
ets:update_counter(stats, {os, Host, OS_id}, 1), |
631 |
ets:update_counter(stats, {os, server, OS_id}, 1), |
632 |
update_counter_create(stats, {client_os, Host, Client_id, OS_id}, 1), |
633 |
update_counter_create(stats, {client_os, server, Client_id, OS_id}, 1), |
634 |
|
635 |
JID = jlib:make_jid(User, Host, Resource), |
636 |
ets:insert(stats, {{session, JID}, Client_id, OS_id, Lang}). |
637 |
|
638 |
update_counter_create(Table, Element, C) -> |
639 |
case ets:lookup(Table, Element) of |
640 |
[] -> ets:insert(Table, {Element, 1}); |
641 |
_ -> ets:update_counter(Table, Element, C) |
642 |
end. |
643 |
|
644 |
get_tag_cdata_subtag(E, T) -> |
645 |
E2 = xml:get_subtag(E, T), |
646 |
case E2 of |
647 |
false -> "unknown"; |
648 |
_ -> xml:get_tag_cdata(E2) |
649 |
end. |
650 |
|
651 |
list_elem(Type, id) -> |
652 |
{_, Ids} = lists:unzip(list_elem(Type, full)), |
653 |
Ids; |
654 |
list_elem(clients, full) -> |
655 |
[ |
656 |
{"gaim", gaim}, |
657 |
{"Gajim", gajim}, |
658 |
{"Tkabber", tkabber}, |
659 |
{"Psi", psi}, |
660 |
{"Pandion", pandion}, |
661 |
{"Kopete", kopete}, |
662 |
{"Exodus", exodus}, |
663 |
{"libgaim", libgaim}, |
664 |
{"JBother", jbother}, |
665 |
{"iChat", ichat}, |
666 |
{"Miranda", miranda}, |
667 |
{"Trillian", trillian}, |
668 |
{"JAJC", jajc}, |
669 |
{"Coccinella", coccinella}, |
670 |
{"Gabber", gabber}, |
671 |
{"BitlBee", bitlbee}, |
672 |
{"jabber.el", jabberel}, |
673 |
{"unknown", unknown} |
674 |
]; |
675 |
list_elem(oss, full) -> |
676 |
[ |
677 |
{"Linux", linux}, |
678 |
{"Win", windows}, |
679 |
{"Gentoo", linux}, |
680 |
{"Mac", mac}, |
681 |
{"BSD", bsd}, |
682 |
{"SunOS", linux}, |
683 |
{"Ubuntu", linux}, |
684 |
{"unknown", unknown} |
685 |
]. |
686 |
|
687 |
identify(Client, OS) -> |
688 |
Res = {try_match(Client, list_elem(clients, full)), try_match(OS, list_elem(oss, full))}, |
689 |
case Res of |
690 |
{libgaim, mac} -> {adium, mac}; |
691 |
_ -> Res |
692 |
end. |
693 |
|
694 |
try_match(_E, []) -> unknown; |
695 |
try_match(E, [{Str, Id} | L]) -> |
696 |
case string:str(E, Str) of |
697 |
0 -> try_match(E, L); |
698 |
_ -> Id |
699 |
end. |
700 |
|
701 |
get_client_os(Server) -> |
702 |
CO1 = ets:match(stats, {{client_os, Server, '$1', '$2'}, '$3'}), |
703 |
CO2 = lists:map( |
704 |
fun([Cl, Os, A3]) -> |
705 |
{lists:flatten([atom_to_list(Cl), "/", atom_to_list(Os)]), A3} |
706 |
end, |
707 |
CO1 |
708 |
), |
709 |
lists:keysort(1, CO2). |
710 |
|
711 |
get_languages(Server) -> |
712 |
L1 = ets:match(stats, {{lang, Server, '$1'}, '$2'}), |
713 |
L2 = lists:map( |
714 |
fun([La, C]) -> |
715 |
{La, C} |
716 |
end, |
717 |
L1 |
718 |
), |
719 |
lists:keysort(1, L2). |
720 |
|
721 |
get_meanitemsinroster() -> |
722 |
get_meanitemsinroster2(getl("totalrosteritems"), getl("registeredusers")). |
723 |
get_meanitemsinroster(Host) -> |
724 |
get_meanitemsinroster2(getl("totalrosteritems", Host), getl("registeredusers", Host)). |
725 |
get_meanitemsinroster2(Items, Users) -> |
726 |
case Users of |
727 |
0 -> 0; |
728 |
_ -> Items/Users |
729 |
end. |
730 |
|
731 |
localtime_to_string({{Y, Mo, D},{H, Mi, S}}) -> |
732 |
lists:concat([H, ":", Mi, ":", S, " ", D, "/", Mo, "/", Y]). |
733 |
|
734 |
% cuando toque mostrar estadisticas |
735 |
%get_iqversion() -> |
736 |
% contar en la tabla cuantos tienen cliente: *psi* |
737 |
%buscar en la tabla iqversion |
738 |
%ok. |