| 1 |
#!/usr/bin/perl |
|---|
| 2 |
#/* |
|---|
| 3 |
# * Copyright (C) 2005-2006 Roland Arendes <roland@arendes.de> |
|---|
| 4 |
# * |
|---|
| 5 |
# * This program is free software; you can redistribute it and/or modify |
|---|
| 6 |
# * it under the terms of the GNU General Public License as published by |
|---|
| 7 |
# * the Free Software Foundation; either version 2 of the License, or |
|---|
| 8 |
# * (at your option) any later version. |
|---|
| 9 |
# * |
|---|
| 10 |
# * This program is distributed in the hope that it will be useful, |
|---|
| 11 |
# * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 |
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 |
# * GNU General Public License for more details. |
|---|
| 14 |
# * |
|---|
| 15 |
# * You should have received a copy of the GNU General Public License |
|---|
| 16 |
# * along with this program; if not, write to the Free Software |
|---|
| 17 |
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 18 |
# * |
|---|
| 19 |
# * Credits go to Jonathan Middleton <jjm@ixtab.org.uk> and |
|---|
| 20 |
# * Paul Slootman <paul@debian.org>, for writing logtail (part of Logcheck) |
|---|
| 21 |
# */ |
|---|
| 22 |
|
|---|
| 23 |
use warnings; |
|---|
| 24 |
use RRDs; |
|---|
| 25 |
|
|---|
| 26 |
####### |
|---|
| 27 |
|
|---|
| 28 |
my $logfile = $ENV{HOME}."/.hydranode/statistics.log"; # defaultvalue for the logfile |
|---|
| 29 |
my $offsetfile= $ENV{HOME}."/.hydranode/.hnanalyze.offset"; # remembers our position in the logfile |
|---|
| 30 |
my $datafile = $ENV{HOME}."/.hydranode/hnanalyze.rrd"; # where the RRD (compiled logdata) is saved |
|---|
| 31 |
my $outputdir = $ENV{HOME}."/public_html"; # where the png's are saved |
|---|
| 32 |
my $dst = "MAX"; # change to AVERAGE if you don't want the peaks in the graphs |
|---|
| 33 |
# you need to remove the RRD and the offsetfile for that change, |
|---|
| 34 |
# it needs to be recreated. |
|---|
| 35 |
my $entries = 1; # needs to be 1 |
|---|
| 36 |
my $size = 0; |
|---|
| 37 |
my $end = 0; |
|---|
| 38 |
|
|---|
| 39 |
####### |
|---|
| 40 |
|
|---|
| 41 |
open(LOGFILE,'<',$logfile) || die "can't open $logfile: $!"; |
|---|
| 42 |
opendir(DIR, $outputdir) || die "can't open $outputdir for HTML output: $!"; closedir(DIR); |
|---|
| 43 |
|
|---|
| 44 |
my ($inode, $ino, $offset) = (0, 0, 0); |
|---|
| 45 |
unless (not $offsetfile) { |
|---|
| 46 |
if (open(OFFSET, $offsetfile)) { |
|---|
| 47 |
$_ = <OFFSET>; |
|---|
| 48 |
unless (! defined $_) { |
|---|
| 49 |
chomp $_; |
|---|
| 50 |
$inode = $_; |
|---|
| 51 |
$_ = <OFFSET>; |
|---|
| 52 |
unless (! defined $_) { |
|---|
| 53 |
chomp $_; |
|---|
| 54 |
$offset = $_; |
|---|
| 55 |
} |
|---|
| 56 |
} |
|---|
| 57 |
} |
|---|
| 58 |
|
|---|
| 59 |
unless ((undef,$ino,undef,undef,undef,undef,undef,$size) = stat $logfile) { |
|---|
| 60 |
print "Cannot get $logfile file size.\n", $logfile; |
|---|
| 61 |
exit 65; |
|---|
| 62 |
} |
|---|
| 63 |
|
|---|
| 64 |
if ($inode == $ino) { |
|---|
| 65 |
exit 0 if $offset == $size; # short cut |
|---|
| 66 |
if ($offset > $size) { |
|---|
| 67 |
$offset = 0; |
|---|
| 68 |
printf "WARNING - logfile is smaller than last time checked!\n"; |
|---|
| 69 |
printf "Restarting logfile from the beginning.\n" |
|---|
| 70 |
} |
|---|
| 71 |
} |
|---|
| 72 |
if ($inode != $ino || $offset > $size) { |
|---|
| 73 |
$offset = 0; |
|---|
| 74 |
} |
|---|
| 75 |
seek(LOGFILE, $offset, 0); |
|---|
| 76 |
} |
|---|
| 77 |
|
|---|
| 78 |
$_ = <LOGFILE>; |
|---|
| 79 |
if (m/^(\d{10})\d\d\d \[ED2KStatistics\] (\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)/) { |
|---|
| 80 |
($start,$srcs,$qlen,$up,$down,$conns,$upc,$downc,$uploadslots,$downloadslots)=($1, $2, $3, $4, $5, $6, $7, $8, $9, $10); |
|---|
| 81 |
} elsif (m/^(\d{10})\d\d\d \[ED2KStatistics\] (\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)/) { |
|---|
| 82 |
# Old, pre r2219 revision |
|---|
| 83 |
($start,$srcs,$qlen,$up,$down,$conns,$upc,$downc)=($1, $2, $3, $4, $5, $6, $7, $8); |
|---|
| 84 |
$uploadslots = "U"; $downloadslots = "U"; |
|---|
| 85 |
} else { |
|---|
| 86 |
printf "Looks like we have a problem the the logfile $logfile. The first line doesn't look like the right format.\n\n"; |
|---|
| 87 |
printf "If you recently updated your revisions, please consider removing the following files:\n"; |
|---|
| 88 |
printf " $offsetfile\n"; |
|---|
| 89 |
printf " $datafile\n"; |
|---|
| 90 |
printf " $logfile\n"; |
|---|
| 91 |
printf "\n"; |
|---|
| 92 |
exit 10; |
|---|
| 93 |
} |
|---|
| 94 |
|
|---|
| 95 |
if (! -e "$datafile") { # only create a new,empty rrd file if we're missing it |
|---|
| 96 |
seek(LOGFILE, 0, 0); # seek back to the beginning of the log (if we moved in it before) |
|---|
| 97 |
printf "+ creating rra databases\n"; |
|---|
| 98 |
RRDs::create( |
|---|
| 99 |
$datafile, "--step=10", |
|---|
| 100 |
"--start=".($start-30), |
|---|
| 101 |
"DS:up:GAUGE:10:U:500000", |
|---|
| 102 |
"DS:down:GAUGE:10:U:500000", |
|---|
| 103 |
"DS:conns:GAUGE:10:U:50000", |
|---|
| 104 |
"DS:srcs:GAUGE:10:U:500000", |
|---|
| 105 |
"DS:qlen:GAUGE:10:U:500000", |
|---|
| 106 |
"DS:upc:GAUGE:10:U:500000", |
|---|
| 107 |
"DS:downc:GAUGE:10:U:500000", |
|---|
| 108 |
"DS:ups:GAUGE:10:U:1000", |
|---|
| 109 |
"DS:dos:GAUGE:10:U:1000", |
|---|
| 110 |
"RRA:$dst:0.5:1:8600", |
|---|
| 111 |
"RRA:$dst:0.5:6:8600", |
|---|
| 112 |
"RRA:$dst:0.5:24:8600", |
|---|
| 113 |
"RRA:$dst:0.5:288:8600" |
|---|
| 114 |
) or die "Cannot create rrd ($RRDs::error, $datafile)"; |
|---|
| 115 |
} |
|---|
| 116 |
|
|---|
| 117 |
printf "+ inserting data into rrd\n"; |
|---|
| 118 |
if ($offset > 0) { |
|---|
| 119 |
printf "continuing: ".localtime($start)."\n"; |
|---|
| 120 |
} else { |
|---|
| 121 |
printf " start: ".localtime($start)."\n"; |
|---|
| 122 |
} |
|---|
| 123 |
|
|---|
| 124 |
# we need to catch the first line we used above for getting a start value, too |
|---|
| 125 |
RRDs::update($datafile, "$start:$up:$down:$conns:$srcs:$qlen:$upc:$downc:$uploadslots:$downloadslots") or printf STDERR "Cannot update rrd ($!, $datafile),logline:\n$_\n"; |
|---|
| 126 |
|
|---|
| 127 |
while (<LOGFILE>) { |
|---|
| 128 |
if (m/^(\d{10})\d\d\d \[ED2KStatistics\] (\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)/) { |
|---|
| 129 |
($timestamp,$srcs,$qlen,$up,$down,$conns,$upc,$downc,$uploadslots,$downloadslots)=($1, $2, $3, $4, $5, $6, $7, $8, $9, $10); |
|---|
| 130 |
$entries++; |
|---|
| 131 |
RRDs::update($datafile, "$timestamp:$up:$down:$conns:$srcs:$qlen:$upc:$downc:$uploadslots:$downloadslots") or printf STDERR "Cannot update rrd ($!, $datafile)\n"; |
|---|
| 132 |
} elsif (m/^(\d{10})\d\d\d \[ED2KStatistics\] (\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)/) { |
|---|
| 133 |
# old, pre r2219 logfile data |
|---|
| 134 |
($timestamp,$srcs,$qlen,$up,$down,$conns,$upc,$downc)=($1, $2, $3, $4, $5, $6, $7, $8); |
|---|
| 135 |
$entries++; |
|---|
| 136 |
RRDs::update($datafile, "$timestamp:$up:$down:$conns:$srcs:$qlen:$upc:$downc:U:U") or printf STDERR "Cannot update rrd ($!, $datafile)\n"; |
|---|
| 137 |
} else { |
|---|
| 138 |
printf STDERR "Huh? Got a line which is unknown to me:\n$_\n"; |
|---|
| 139 |
} |
|---|
| 140 |
|
|---|
| 141 |
} |
|---|
| 142 |
|
|---|
| 143 |
if ($entries > 1) { # entries is 1 if we got only one line to read and skipped the above while loop. |
|---|
| 144 |
$end = $timestamp; |
|---|
| 145 |
} else { |
|---|
| 146 |
$end = $start; # no new log data, fixes warning messages |
|---|
| 147 |
} |
|---|
| 148 |
|
|---|
| 149 |
printf " end: ".localtime($end)." ($entries entries)\n"; |
|---|
| 150 |
$size = tell LOGFILE; |
|---|
| 151 |
close(LOGFILE); |
|---|
| 152 |
|
|---|
| 153 |
|
|---|
| 154 |
# Disable output buffering at this point to enable the printing of belows dots without delay |
|---|
| 155 |
$| = 1; |
|---|
| 156 |
printf "+ creating graphs "; |
|---|
| 157 |
|
|---|
| 158 |
@timeperiods = (2*3600,12*3600,24*3600,3*24*3600,7*24*3600,30*24*3600,12*30*24*3600); |
|---|
| 159 |
|
|---|
| 160 |
foreach $timespan (@timeperiods) { |
|---|
| 161 |
|
|---|
| 162 |
RRDs::graph($outputdir."/hn-traffic-$timespan.png", |
|---|
| 163 |
"--imgformat=PNG", "--vertical-label=traffic", "--start=".($end-$timespan), "--end=".$end, |
|---|
| 164 |
"--lower-limit=0", "--width=900", "--height=200", "--step=10", "--base=1024","--lazy", |
|---|
| 165 |
"DEF:u=$datafile:up:$dst", |
|---|
| 166 |
"DEF:down=$datafile:down:$dst", |
|---|
| 167 |
"DEF:uc=$datafile:upc:$dst", |
|---|
| 168 |
"DEF:downc=$datafile:downc:$dst", |
|---|
| 169 |
"CDEF:up=u,-1,*", |
|---|
| 170 |
"CDEF:upc=uc,-1,*", |
|---|
| 171 |
"AREA:upc#1859B8:Upload Control ", |
|---|
| 172 |
"GPRINT:uc:LAST:Current\\: %6.2lf %s", |
|---|
| 173 |
"GPRINT:uc:AVERAGE:Average\\: %6.2lf %s", |
|---|
| 174 |
"GPRINT:uc:MAX:Maximum\\: %6.2lf %s\\n", |
|---|
| 175 |
"STACK:up#87B1EE:Upload Data ", |
|---|
| 176 |
"GPRINT:u:LAST:Current\\: %6.2lf %s", |
|---|
| 177 |
"GPRINT:u:AVERAGE:Average\\: %6.2lf %s", |
|---|
| 178 |
"GPRINT:u:MAX:Maximum\\: %6.2lf %s\\n", |
|---|
| 179 |
"AREA:downc#948412:Download Control ", |
|---|
| 180 |
"GPRINT:downc:LAST:Current\\: %6.2lf %s", |
|---|
| 181 |
"GPRINT:downc:AVERAGE:Average\\: %6.2lf %s", |
|---|
| 182 |
"GPRINT:downc:MAX:Maximum\\: %6.2lf %s\\n", |
|---|
| 183 |
"STACK:down#E1CA1B:Download Data ", |
|---|
| 184 |
"GPRINT:down:LAST:Current\\: %6.2lf %s", |
|---|
| 185 |
"GPRINT:down:AVERAGE:Average\\: %6.2lf %s", |
|---|
| 186 |
"GPRINT:down:MAX:Maximum\\: %6.2lf %s\\n") |
|---|
| 187 |
or die "graph failed ($RRDs::error): traffic: $timespan\n"; |
|---|
| 188 |
printf "."; |
|---|
| 189 |
|
|---|
| 190 |
RRDs::graph($outputdir."/hn-sources-$timespan.png", |
|---|
| 191 |
"--imgformat=PNG", "--vertical-label=sources", "--start=".($end-$timespan), "--end=".$end, |
|---|
| 192 |
"--lower-limit=0", "--width=900","--height=200","--lazy", |
|---|
| 193 |
"DEF:nsrc=$datafile:srcs:$dst", |
|---|
| 194 |
"DEF:qlen=$datafile:qlen:$dst", |
|---|
| 195 |
"DEF:conns=$datafile:conns:$dst", |
|---|
| 196 |
"AREA:qlen#7EE600:Queue Length ", |
|---|
| 197 |
"GPRINT:qlen:LAST: Current\\: %6.2lf %s", |
|---|
| 198 |
"GPRINT:qlen:AVERAGE:Average\\: %6.2lf %s", |
|---|
| 199 |
"GPRINT:qlen:MAX:Maximum\\: %6.2lf %s\\n", |
|---|
| 200 |
"LINE2:nsrc#FF5700:Sources ", |
|---|
| 201 |
"GPRINT:nsrc:LAST: Current\\: %6.2lf %s", |
|---|
| 202 |
"GPRINT:nsrc:AVERAGE:Average\\: %6.2lf %s", |
|---|
| 203 |
"GPRINT:nsrc:MAX:Maximum\\: %6.2lf %s\\n") |
|---|
| 204 |
or die "graph failed ($RRDs::error): sources: $timespan\n"; |
|---|
| 205 |
printf "."; |
|---|
| 206 |
|
|---|
| 207 |
RRDs::graph($outputdir."/hn-slots-$timespan.png", |
|---|
| 208 |
"--imgformat=PNG", "--vertical-label=slots", "--start=".($end-$timespan), "--end=".$end, |
|---|
| 209 |
"--lower-limit=0", "--width=900", "--height=200", "--step=10", "--lazy", |
|---|
| 210 |
"DEF:ups=$datafile:ups:$dst", |
|---|
| 211 |
"CDEF:upsc=ups,-1,*", |
|---|
| 212 |
"DEF:dos=$datafile:dos:$dst", |
|---|
| 213 |
"DEF:conns=$datafile:conns:$dst", |
|---|
| 214 |
"AREA:upsc#cc3300:Upload Slots ", |
|---|
| 215 |
"GPRINT:ups:LAST:Current\\: %6.2lf %s", |
|---|
| 216 |
"GPRINT:ups:AVERAGE:Average\\: %6.2lf %s", |
|---|
| 217 |
"GPRINT:ups:MAX:Maximum\\: %6.2lf %s\\n", |
|---|
| 218 |
"AREA:dos#3366ff:Download Slots ", |
|---|
| 219 |
"GPRINT:dos:LAST:Current\\: %6.2lf %s", |
|---|
| 220 |
"GPRINT:dos:AVERAGE:Average\\: %6.2lf %s", |
|---|
| 221 |
"GPRINT:dos:MAX:Maximum\\: %6.2lf %s\\n", |
|---|
| 222 |
"LINE1:conns#404040:Connections ", |
|---|
| 223 |
"GPRINT:conns:LAST: Current\\: %6.2lf %s", |
|---|
| 224 |
"GPRINT:conns:AVERAGE:Average\\: %6.2lf %s", |
|---|
| 225 |
"GPRINT:conns:MAX:Maximum\\: %6.2lf %s\\n") |
|---|
| 226 |
or die "graph failed ($RRDs::error): slots: $timespan\n"; |
|---|
| 227 |
printf "."; |
|---|
| 228 |
} |
|---|
| 229 |
printf "\n"; |
|---|
| 230 |
|
|---|
| 231 |
# saving session data |
|---|
| 232 |
|
|---|
| 233 |
unless (open(OFFSET, ">$offsetfile")) { |
|---|
| 234 |
print "File $offsetfile cannot be created. Check your permissions.\n"; |
|---|
| 235 |
exit 73; |
|---|
| 236 |
} |
|---|
| 237 |
print OFFSET "$ino\n$size\n"; |
|---|
| 238 |
close OFFSET; |
|---|