| 1 |
#!/usr/bin/perl -w |
|---|
| 2 |
|
|---|
| 3 |
# lightygraph -- a lighttpd statistics rrdtool frontend |
|---|
| 4 |
# copyright (c) 2008 Joe Nahmias <joe@nahmias.net> |
|---|
| 5 |
# based on mailgraph by David Schweikert <dws@ee.ethz.ch> |
|---|
| 6 |
# released under the GNU General Public License |
|---|
| 7 |
|
|---|
| 8 |
use RRDs; |
|---|
| 9 |
use POSIX qw(uname); |
|---|
| 10 |
|
|---|
| 11 |
my $VERSION = "0.50"; |
|---|
| 12 |
|
|---|
| 13 |
my $host = (POSIX::uname())[1]; |
|---|
| 14 |
my $scriptname = 'lightygraph'; |
|---|
| 15 |
my $xpoints = 600; |
|---|
| 16 |
my $ypoints = 350; |
|---|
| 17 |
my $rrd = '/var/www/lighttpd.rrd'; # path to where the RRD database is |
|---|
| 18 |
my $tmp_dir = '/var/cache/lighttpd'; # temporary directory where to store the images |
|---|
| 19 |
|
|---|
| 20 |
my @graphs = ( |
|---|
| 21 |
{ title => 'Last 4 Hours', seconds => 60 * 60 * 4 , }, |
|---|
| 22 |
{ title => 'Daily Graphs', seconds => 60 * 60 * 24 , }, |
|---|
| 23 |
{ title => 'Monthly Graphs', seconds => 60 * 60 * 24 * 30, }, |
|---|
| 24 |
); |
|---|
| 25 |
|
|---|
| 26 |
my %color = ( # rrggbb in hex |
|---|
| 27 |
areamin => 'ffffff', |
|---|
| 28 |
instack => 'f00000', |
|---|
| 29 |
minmax => 'a0a0a0', |
|---|
| 30 |
incoming => 'efb71d', |
|---|
| 31 |
outstack => '00f000', |
|---|
| 32 |
outgoing => 'a0a735', |
|---|
| 33 |
reqstack => '00f000', |
|---|
| 34 |
requests => '00a735', |
|---|
| 35 |
); |
|---|
| 36 |
|
|---|
| 37 |
sub rrd_graph(@) |
|---|
| 38 |
{ |
|---|
| 39 |
my ($range, $file, $ypoints, @rrdargs) = @_; |
|---|
| 40 |
# choose carefully the end otherwise rrd will maybe pick the wrong RRA: |
|---|
| 41 |
my $date = localtime(time); |
|---|
| 42 |
$date =~ s|:|\\:|g unless $RRDs::VERSION < 1.199908; |
|---|
| 43 |
|
|---|
| 44 |
my ($graphret,$xs,$ys) = RRDs::graph($file, |
|---|
| 45 |
'--imgformat', 'PNG', |
|---|
| 46 |
'--width', $xpoints, |
|---|
| 47 |
'--height', $ypoints, |
|---|
| 48 |
'--start', "-$range", |
|---|
| 49 |
'--lazy', |
|---|
| 50 |
|
|---|
| 51 |
@rrdargs, |
|---|
| 52 |
|
|---|
| 53 |
'COMMENT:['.$date.']\r', |
|---|
| 54 |
); |
|---|
| 55 |
|
|---|
| 56 |
my $ERR=RRDs::error; |
|---|
| 57 |
die "ERROR: $ERR\n" if $ERR; |
|---|
| 58 |
} |
|---|
| 59 |
|
|---|
| 60 |
sub graph_traffic($$) |
|---|
| 61 |
{ |
|---|
| 62 |
my ($range, $file) = @_; |
|---|
| 63 |
rrd_graph($range, $file, $ypoints, |
|---|
| 64 |
|
|---|
| 65 |
"-v bytes", |
|---|
| 66 |
"-t TrafficWebserver", |
|---|
| 67 |
"DEF:binraw=$rrd:InOctets:AVERAGE", |
|---|
| 68 |
"DEF:binmaxraw=$rrd:InOctets:MAX", |
|---|
| 69 |
"DEF:binminraw=$rrd:InOctets:MIN", |
|---|
| 70 |
"DEF:bout=$rrd:OutOctets:AVERAGE", |
|---|
| 71 |
"DEF:boutmax=$rrd:OutOctets:MAX", |
|---|
| 72 |
"DEF:boutmin=$rrd:OutOctets:MIN", |
|---|
| 73 |
"CDEF:bin=binraw,-1,*", |
|---|
| 74 |
"CDEF:binmax=binmaxraw,-1,*", |
|---|
| 75 |
"CDEF:binmin=binminraw,-1,*", |
|---|
| 76 |
"CDEF:binminmax=binmaxraw,binminraw,-", |
|---|
| 77 |
"CDEF:boutminmax=boutmax,boutmin,-", |
|---|
| 78 |
"AREA:binmin#$color{areamin}:", |
|---|
| 79 |
"STACK:binmax#$color{instack}:", |
|---|
| 80 |
"LINE1:binmin#$color{minmax}:", |
|---|
| 81 |
"LINE1:binmax#$color{minmax}:", |
|---|
| 82 |
"LINE2:bin#$color{incoming}:incoming", |
|---|
| 83 |
"GPRINT:bin:MIN:%.2lf", |
|---|
| 84 |
"GPRINT:bin:AVERAGE:%.2lf", |
|---|
| 85 |
"GPRINT:bin:MAX:%.2lf", |
|---|
| 86 |
"AREA:boutmin#$color{areamin}:", |
|---|
| 87 |
"STACK:boutminmax#$color{outstack}:", |
|---|
| 88 |
"LINE1:boutmin#$color{minmax}:", |
|---|
| 89 |
"LINE1:boutmax#$color{minmax}:", |
|---|
| 90 |
"LINE2:bout#$color{outgoing}:outgoing", |
|---|
| 91 |
"GPRINT:bout:MIN:%.2lf", |
|---|
| 92 |
"GPRINT:bout:AVERAGE:%.2lf", |
|---|
| 93 |
"GPRINT:bout:MAX:%.2lf", |
|---|
| 94 |
); |
|---|
| 95 |
} |
|---|
| 96 |
|
|---|
| 97 |
sub graph_requests($$) |
|---|
| 98 |
{ |
|---|
| 99 |
my ($range, $file) = @_; |
|---|
| 100 |
rrd_graph($range, $file, $ypoints, |
|---|
| 101 |
"-v req", |
|---|
| 102 |
"-t RequestsperSecond", |
|---|
| 103 |
"-u 1", |
|---|
| 104 |
"DEF:req=$rrd:Requests:AVERAGE", |
|---|
| 105 |
"DEF:reqmax=$rrd:Requests:MAX", |
|---|
| 106 |
"DEF:reqmin=$rrd:Requests:MIN", |
|---|
| 107 |
"CDEF:reqminmax=reqmax,reqmin,-", |
|---|
| 108 |
"AREA:reqmin#$color{areamin}:", |
|---|
| 109 |
"STACK:reqminmax#$color{reqstack}:", |
|---|
| 110 |
"LINE1:reqmin#$color{minmax}:", |
|---|
| 111 |
"LINE1:reqmax#$color{minmax}:", |
|---|
| 112 |
"LINE2:req#$color{requests}:requests", |
|---|
| 113 |
); |
|---|
| 114 |
} |
|---|
| 115 |
|
|---|
| 116 |
sub print_html() |
|---|
| 117 |
{ |
|---|
| 118 |
print "Content-Type: text/html\n\n"; |
|---|
| 119 |
|
|---|
| 120 |
print <<HEADER; |
|---|
| 121 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> |
|---|
| 122 |
<HTML> |
|---|
| 123 |
<HEAD> |
|---|
| 124 |
<TITLE>Webserver Statistics for $host</TITLE> |
|---|
| 125 |
<META HTTP-EQUIV="Refresh" CONTENT="300"> |
|---|
| 126 |
<META HTTP-EQUIV="Pragma" CONTENT="no-cache"> |
|---|
| 127 |
</HEAD> |
|---|
| 128 |
<BODY BGCOLOR="#FFFFFF"> |
|---|
| 129 |
HEADER |
|---|
| 130 |
|
|---|
| 131 |
print "<H1>WebServer Statistics for $host</H1>\n"; |
|---|
| 132 |
for my $n (0..$#graphs) { |
|---|
| 133 |
print '<div style="background: #dddddd; width: 632px">'; |
|---|
| 134 |
print "<H2>$graphs[$n]{title}</H2>\n"; |
|---|
| 135 |
print "</div>\n"; |
|---|
| 136 |
print "<P><IMG BORDER=\"0\" SRC=\"$scriptname.cgi?${n}-t\" ALT=\"$scriptname\">\n"; |
|---|
| 137 |
print "<P><IMG BORDER=\"0\" SRC=\"$scriptname.cgi?${n}-r\" ALT=\"$scriptname\">\n"; |
|---|
| 138 |
} |
|---|
| 139 |
|
|---|
| 140 |
print "</BODY></HTML>\n"; |
|---|
| 141 |
} |
|---|
| 142 |
|
|---|
| 143 |
sub send_image($) |
|---|
| 144 |
{ |
|---|
| 145 |
my ($file)= @_; |
|---|
| 146 |
|
|---|
| 147 |
-r $file or do { |
|---|
| 148 |
print "Content-type: text/plain\n\nERROR: can't find $file\n"; |
|---|
| 149 |
exit 1; |
|---|
| 150 |
}; |
|---|
| 151 |
|
|---|
| 152 |
print "Content-type: image/png\n"; |
|---|
| 153 |
print "Content-length: ".((stat($file))[7])."\n"; |
|---|
| 154 |
print "\n"; |
|---|
| 155 |
open(IMG, $file) or die; |
|---|
| 156 |
my $data; |
|---|
| 157 |
print $data while read(IMG, $data, 16384)>0; |
|---|
| 158 |
} |
|---|
| 159 |
|
|---|
| 160 |
sub main() |
|---|
| 161 |
{ |
|---|
| 162 |
my $uri = $ENV{REQUEST_URI} || ''; |
|---|
| 163 |
$uri =~ s/\/[^\/]+$//; |
|---|
| 164 |
$uri =~ s/\//,/g; |
|---|
| 165 |
$uri =~ s/(\~|\%7E)/tilde,/g; |
|---|
| 166 |
mkdir $tmp_dir, 0777 unless -d $tmp_dir; |
|---|
| 167 |
|
|---|
| 168 |
my $img = $ENV{QUERY_STRING}; |
|---|
| 169 |
if(defined $img and $img =~ /\S/) { |
|---|
| 170 |
if($img =~ /^(\d+)-t$/) { |
|---|
| 171 |
my $file = "$tmp_dir/${scriptname}_traffic_$1.png"; |
|---|
| 172 |
graph_traffic($graphs[$1]{seconds}, $file); |
|---|
| 173 |
send_image($file); |
|---|
| 174 |
} |
|---|
| 175 |
elsif($img =~ /^(\d+)-r$/) { |
|---|
| 176 |
my $file = "$tmp_dir/${scriptname}_requests_$1.png"; |
|---|
| 177 |
graph_requests($graphs[$1]{seconds}, $file); |
|---|
| 178 |
send_image($file); |
|---|
| 179 |
} |
|---|
| 180 |
else { |
|---|
| 181 |
die "ERROR: invalid argument\n"; |
|---|
| 182 |
} |
|---|
| 183 |
} |
|---|
| 184 |
else { |
|---|
| 185 |
print_html; |
|---|
| 186 |
} |
|---|
| 187 |
} |
|---|
| 188 |
|
|---|
| 189 |
main; |
|---|