Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 137724 | Differences between
and this patch

Collapse All | Expand All

(-)ejabberd-1.1.1/src/mod_statsdx.erl (+738 lines)
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.

Return to bug 137724