Skip to content

Commit f8d014c

Browse files
author
Claes Wikstrom
committed
Merge branch 'stats' of git://github.com/oliv3/yaws into stats
2 parents 2747a01 + edfca30 commit f8d014c

12 files changed

+445
-20
lines changed

include/yaws.hrl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
%% flags for sconfs
106106
-define(SC_ACCESS_LOG, 1).
107107
-define(SC_ADD_PORT, 2).
108+
-define(SC_STATISTICS, 4).
108109
-define(SC_TILDE_EXPAND, 8).
109110
-define(SC_DIR_LISTINGS, 16).
110111
-define(SC_DEFLATE, 32).
@@ -117,6 +118,8 @@
117118
(((SC)#sconf.flags band ?SC_ACCESS_LOG) /= 0)).
118119
-define(sc_has_add_port(SC),
119120
(((SC)#sconf.flags band ?SC_ADD_PORT) /= 0)).
121+
-define(sc_has_statistics(SC),
122+
(((SC)#sconf.flags band ?SC_STATISTICS) /= 0)).
120123
-define(sc_has_tilde_expand(SC),
121124
(((SC)#sconf.flags band ?SC_TILDE_EXPAND) /= 0)).
122125
-define(sc_has_dir_listings(SC),
@@ -133,8 +136,10 @@
133136
SC#sconf{flags = yaws:flag(SC#sconf.flags, ?SC_ACCESS_LOG, Bool)}).
134137
-define(sc_set_add_port(SC, Bool),
135138
SC#sconf{flags = yaws:flag(SC#sconf.flags, ?SC_ADD_PORT, Bool)}).
139+
-define(sc_set_statistics(SC, Bool),
140+
SC#sconf{flags = yaws:flag(SC#sconf.flags, ?SC_STATISTICS, Bool)}).
136141
-define(sc_set_ssl(SC, Bool),
137-
SC#sconf{flags = yaws:flag(SC#sconf.flags , ?SC_SSL, Bool)}).
142+
SC#sconf{flags = yaws:flag(SC#sconf.flags, ?SC_SSL, Bool)}).
138143
-define(sc_set_tilde_expand(SC, Bool),
139144
SC#sconf{flags = yaws:flag(SC#sconf.flags, ?SC_TILDE_EXPAND, Bool)}).
140145
-define(sc_set_dir_listings(SC, Bool),
@@ -178,7 +183,7 @@
178183
revproxy = [],
179184
soptions = [],
180185
extra_cgi_vars = [],
181-
186+
stats, %% raw traffic statistics
182187
%% [{Extension:string(), Mod:atom()]
183188
%% work in progress .....
184189
extension_mods = [{"ys", yaws_ext_handler_yaws}]

munin/README.munin

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Usage:
2+
3+
1. Copy the scripts to /usr/share/munin/plugins
4+
5+
2. To graph statistics for the server "SERVER":
6+
7+
# ln -s /usr/share/munin/plugins/yaws_hits_ /etc/munin/plugins/yaws_hits_SERVER
8+
# ln -s /usr/share/munin/plugins/yaws_sent_ /etc/munin/plugins/yaws_sent_SERVER
9+
10+
3. Change /etc/munin/plugin-conf.d/munin-node and add:
11+
12+
[yaws*]
13+
user root
14+
15+
4. Restart munin-node

munin/yaws_hits_

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/bin/bash
2+
3+
#
4+
# YAWS server hits
5+
#
6+
# Needs following minimal configuration in plugin-conf.d/munin-node:
7+
# [yaws*]
8+
# user root
9+
#
10+
# Magick markers
11+
#%# family=auto
12+
#%# capabilities=autoconf
13+
14+
15+
ID=`basename $0 | sed 's/^yaws_hits_//g'`
16+
TMPFILE=.yaws_hits_$ID
17+
STATS=`yaws --stats --id $ID | tail --lines=+2 > $TMPFILE`
18+
19+
if [ "$1" = "autoconf" ]; then
20+
if which yaws > /dev/null; then
21+
echo yes
22+
exit 0
23+
else
24+
echo no
25+
exit 1
26+
fi
27+
fi
28+
29+
if [ "$1" = "config" ]; then
30+
echo graph_title Hits for server $ID
31+
echo graph_vlabel Hits
32+
echo graph_category Yaws
33+
echo graph_args --base 1024 -l 0
34+
35+
while read line; do
36+
HOST=`echo $line | awk '{ print $1 }'`
37+
FIELD=`echo $HOST | sed 's/[\.:]/_/g'`
38+
39+
echo $FIELD.label $HOST
40+
echo $FIELD.draw LINE2
41+
echo $FIELD.type DERIVE
42+
echo $FIELD.min 0
43+
done < $TMPFILE
44+
45+
rm -f $TMPFILE
46+
47+
exit 0
48+
fi
49+
50+
while read line; do
51+
HOST=`echo $line | awk '{ print $1 }'`
52+
FIELD=`echo $HOST | sed 's/[\.:]/_/g'`
53+
HITS=`echo $line | awk '{ print $4 }'`
54+
55+
echo $FIELD.value $HITS
56+
done < $TMPFILE
57+
58+
rm -f $TMPFILE
59+
60+
exit 0

munin/yaws_sent_

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/bin/bash
2+
3+
#
4+
# YAWS server bytes sent
5+
#
6+
# Needs following minimal configuration in plugin-conf.d/munin-node:
7+
# [yaws*]
8+
# user root
9+
#
10+
# Magick markers
11+
#%# family=auto
12+
#%# capabilities=autoconf
13+
14+
ID=`basename $0 | sed 's/^yaws_sent_//g'`
15+
TMPFILE=.yaws_sent_$ID
16+
STATS=`yaws --stats --id $ID | tail --lines=+2 > $TMPFILE`
17+
18+
if [ "$1" = "autoconf" ]; then
19+
if which yaws > /dev/null; then
20+
echo yes
21+
exit 0
22+
else
23+
echo no
24+
exit 1
25+
fi
26+
fi
27+
28+
if [ "$1" = "config" ]; then
29+
echo graph_title Bytes sent by server $ID
30+
echo graph_vlabel Bytes
31+
echo graph_category Yaws
32+
echo graph_args --base 1024 -l 0
33+
34+
while read line; do
35+
HOST=`echo $line | awk '{ print $1 }'`
36+
FIELD=`echo $HOST | sed 's/[\.:]/_/g'`
37+
38+
echo $FIELD.label $HOST
39+
echo $FIELD.draw LINE2
40+
echo $FIELD.type DERIVE
41+
echo $FIELD.min 0
42+
done < $TMPFILE
43+
44+
rm -f $TMPFILE
45+
46+
exit 0
47+
fi
48+
49+
while read line; do
50+
HOST=`echo $line | awk '{ print $1 }'`
51+
FIELD=`echo $HOST | sed 's/[\.:]/_/g'`
52+
SENT=`echo $line | awk '{ print $5 }'`
53+
54+
echo $FIELD.value $SENT
55+
done < $TMPFILE
56+
57+
rm -f $TMPFILE
58+
59+
exit 0

scripts/yaws.conf.template

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ use_fdsrv = false
127127
listen = 0.0.0.0
128128
docroot = /tmp
129129
dir_listings = true
130+
statistics = true
130131
<auth>
131132
realm = foobar
132133
dir = /

scripts/yaws.template

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ help()
7474
echo " yaws --ctltrace traffic|http -- toggle trace of running daemon"
7575
echo " yaws --check YawsFile [IncDirs] -- test compile File "
7676
echo " yaws --wait-started[=secs] [--id ID] -- wait for daemon to be ready"
77+
echo " yaws --stats [--id ID] -- show daemon statistics"
7778
exit 1
7879
}
7980

@@ -195,6 +196,8 @@ while [ $# -gt 0 ]
195196
ex="$erl -noshell -pa ${yawsdir}${delim}ebin -s yaws_ctl ls";;
196197
-S|--status)
197198
ex="$erl -noshell -pa ${yawsdir}${delim}ebin -s yaws_ctl status";;
199+
--stats)
200+
ex="$erl -noshell -pa ${yawsdir}${delim}ebin -s yaws_ctl stats";;
198201
-load|--load)
199202
$erl -noshell -pa ${yawsdir}${delim}ebin -s yaws_ctl load $* ${id}
200203
exit 0;;

src/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ MODULES=yaws \
3939
authmod_gssapi \
4040
yaws_appmod_cgi \
4141
yaws_sendfile yaws_sendfile_compat \
42-
yaws_sup_restarts
42+
yaws_sup_restarts \
43+
yaws_stats
4344

4445

4546

src/yaws.erl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,15 @@ setup_sconf(DocRoot, D, SL) ->
277277
revproxy = lkup(revproxy, SL,
278278
D#sconf.revproxy),
279279
soptions = lkup(soptions, SL,
280-
D#sconf.soptions)}.
280+
D#sconf.soptions),
281+
stats = lkup(soptions, SL, D#sconf.stats)}.
281282

282283
set_sc_flags([{access_log, Bool}|T], Flags) ->
283284
set_sc_flags(T, flag(Flags, ?SC_ACCESS_LOG, Bool));
284285
set_sc_flags([{add_port, Bool}|T], Flags) ->
285286
set_sc_flags(T, flag(Flags, ?SC_ADD_PORT, Bool));
287+
set_sc_flags([{statistics, Bool}|T], Flags) ->
288+
set_sc_flags(T, flag(Flags, ?SC_STATISTICS, Bool));
286289
set_sc_flags([{tilde_expand, Bool}|T], Flags) ->
287290
set_sc_flags(T, flag(Flags, ?SC_TILDE_EXPAND, Bool));
288291
set_sc_flags([{dir_listings, Bool}|T], Flags) ->
@@ -1738,17 +1741,20 @@ gen_tcp_send(S, Data) ->
17381741
_SSL ->
17391742
ssl:send(S, Data)
17401743
end,
1744+
Size = iolist_size(Data),
17411745
case ?gc_has_debug((get(gc))) of
17421746
false ->
17431747
case Res of
17441748
ok ->
1749+
yaws_stats:sent(Size),
17451750
ok;
17461751
_Err ->
17471752
exit(normal) %% keep quiet
17481753
end;
17491754
true ->
17501755
case Res of
17511756
ok ->
1757+
yaws_stats:sent(Size),
17521758
?Debug("Sent ~p~n", [yaws_debug:nobin(Data)]),
17531759
ok;
17541760
Err ->

src/yaws_config.erl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -961,8 +961,19 @@ fload(FD, server, GC, C, Cs, Lno, Chars) ->
961961
_URL ->
962962
{error, "Can't revproxy to an URL with a path "}
963963
end;
964+
964965
['<', "extra_cgi_vars", "dir", '=', Dir, '>'] ->
965966
fload(FD, extra_cgi_vars, GC, C, Cs, Lno+1, Next, {Dir, []});
967+
968+
["statistics", '=', Bool] ->
969+
case is_bool(Bool) of
970+
{true, Val} ->
971+
C2 = ?sc_set_statistics(C, Val),
972+
fload(FD, server, GC, C2, Cs, Lno+1, Next);
973+
false ->
974+
{error, ?F("Expect true|false at line ~w", [Lno])}
975+
end;
976+
966977
[H|T] ->
967978
{error, ?F("Unexpected input ~p at line ~w", [[H|T], Lno])}
968979
end;

src/yaws_ctl.erl

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
-export([start/2, actl_trace/1]).
2020
-export([ls/1,hup/1,stop/1,status/1,load/1,
21-
check/1,trace/1, debug_dump/1]).
21+
check/1,trace/1, debug_dump/1, stats/1]).
2222
%% internal
2323
-export([run/1, aloop/3, handle_a/3]).
2424

@@ -174,6 +174,9 @@ handle_a(A, GC, Key) ->
174174
{debug_dump, Key} ->
175175
a_debug_dump(A),
176176
gen_tcp:close(A);
177+
{stats, Key} ->
178+
a_stats(A),
179+
gen_tcp:close(A);
177180
{Other, Key} ->
178181
gen_tcp:send(A, io_lib:format("Other: ~p~n", [Other])),
179182
gen_tcp:close(A);
@@ -265,6 +268,67 @@ a_debug_dump(Sock) ->
265268
yaws_debug:do_debug_dump(Sock).
266269

267270

271+
-define(IPV4_FMT, "~p.~p.~p.~p").
272+
-define(IPV6_FMT, "~2.16.0b~2.16.0b:~2.16.0b~2.16.0b:~2.16.0b~2.16.0b:~2.16.0b~2.16.0b").
273+
274+
format_ip(IP) ->
275+
case size(IP) of
276+
4 ->
277+
{A, B, C, D} = IP,
278+
io_lib:format(?IPV4_FMT,
279+
[A, B, C, D]);
280+
281+
8 ->
282+
{A, B, C, D, E, F, G, H} = IP,
283+
io_lib:format(?IPV6_FMT,
284+
[A, B, C, D, E, F, G, H])
285+
end.
286+
287+
a_stats(Sock) ->
288+
gen_tcp:send(Sock, a_stats()).
289+
a_stats() ->
290+
{ok, _GC, Servers0} = yaws_server:getconf(),
291+
Servers1 = lists:flatten(Servers0),
292+
%% io:format("~p~n", [Servers1]),
293+
Servers2 = parse(Servers1),
294+
295+
case Servers2 of
296+
[] ->
297+
f("No statistics available~n", []);
298+
299+
Servers2 ->
300+
Stats = fstats(Servers2),
301+
Header = f("Host IP Port Hits Sent~n", []),
302+
303+
Lines = lists:map(fun({Host, IP0, Port, {Hits, Sent}}) ->
304+
%% we don't use inet_parse:ntoa/1
305+
%% since it's not documented
306+
IP = format_ip(IP0),
307+
f("~s ~s ~p ~p ~p~n",
308+
[Host, IP, Port, Hits, Sent])
309+
end, Stats),
310+
[Header, Lines]
311+
end.
312+
313+
parse(V) ->
314+
parse(V, []).
315+
parse([], Acc) ->
316+
Acc;
317+
parse([#sconf{stats=undefined}|Tail], Acc) ->
318+
parse(Tail, Acc);
319+
parse([#sconf{listen=IP, port=Port, servername=Servername, stats=Stats}|Tail], Acc) ->
320+
Host = {Servername, IP, Port, Stats},
321+
parse(Tail, [Host|Acc]).
322+
323+
fstats(S) ->
324+
fstats(S, []).
325+
fstats([], Acc) ->
326+
lists:keysort(1, Acc);
327+
fstats([{IP, Port, Server, Stats}|Tail], Acc) ->
328+
S = {IP, Port, Server, yaws_stats:get(Stats)},
329+
fstats(Tail, [S|Acc]).
330+
331+
268332
a_load(A, Mods) ->
269333
case purge(Mods) of
270334
ok ->
@@ -477,11 +541,6 @@ trace([What, SID]) ->
477541
debug_dump([SID]) ->
478542
actl(SID, debug_dump).
479543

480-
481-
482-
483-
484-
485-
486-
544+
stats([SID]) ->
545+
actl(SID, stats).
487546

0 commit comments

Comments
 (0)