rrd/MyRRD.pm

1631 lines
52 KiB
Perl

#!/usr/bin/perl -w
package MyRRD;
use strict;
use Data::Dumper;
use LWP::UserAgent;
use IO::Socket::UNIX;
use JSON;
use Digest::MD5 qw(md5_hex);
sub new
{
my $this = shift;
my $rrd = shift;
my $img = shift;
# bless object
$this = ref $this if ref $this;
# instantiate
my $obj = bless {
_rrd => $rrd,
_img => $img,
_rrdtool => '/usr/bin/rrdtool',
}, $this;
return $obj;
}
sub networkInterface
{
my $this = shift;
my $iface = shift;
my $title = shift;
my $regexpiface = $iface;
$regexpiface =~ s/\./\\\./;
my $in = 0;
my $out = 0;
open IN, "</proc/net/dev";
while (<IN>)
{
if (my @expr = m/^\s*$regexpiface:\s*(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+(\d+)/)
{
$in = $expr[0] || 0;
$out = $expr[1] || 0;
last;
}
}
close (IN);
print "$iface trafic in, out: $in, $out\n";
my $filename = "$this->{_rrd}/nic-$iface.rrd";
if (! -e $filename)
{
print "creating rrd database for $iface interface...\n";
system "$this->{_rrdtool} create \"$filename\" -s 300 \\
DS:in:DERIVE:600:0:U \\
DS:out:DERIVE:600:0:U \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t in:out N:$in:$out";
$this->networkGraph($iface, 'day', $title);
$this->networkGraph($iface, 'week', $title);
$this->networkGraph($iface, 'month', $title);
$this->networkGraph($iface, 'year', $title);
}
sub networkGraph
{
my $this = shift;
my $iface = shift;
my $type = shift;
my $title = shift;
my $rrd_filename = "$this->{_rrd}/nic-$iface.rrd";
my $graph_filename = "$this->{_img}/nic-$iface-$type.png";
system "$this->{_rrdtool} graph \"$graph_filename\" \\
-s -1$type \\
-t 'Trafic sur $iface :: $title' \\
--lazy \\
--tabwidth 20 \\
-h 250 -w 1100 \\
--border 0 \\
-l 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"o/s\" \\
DEF:in=$rrd_filename:in:AVERAGE \\
DEF:out=$rrd_filename:out:AVERAGE \\
CDEF:out_neg=out,-1,* \\
VDEF:inmax=in,MAXIMUM \\
VDEF:inavg=in,AVERAGE \\
VDEF:inlast=in,LAST \\
VDEF:outmax=out,MAXIMUM \\
VDEF:outavg=out,AVERAGE \\
VDEF:outlast=out,LAST \\
AREA:in#A0E59C:\"Incoming\t\t\" \\
GPRINT:inmax:\"Max\\: %8.2lf %s\" \\
GPRINT:inavg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:inlast:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
AREA:out_neg#68A5D3:\"Outgoing\t\t\" \\
GPRINT:outmax:\"Max\\: %8.2lf %S\" \\
GPRINT:outavg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:outlast:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
HRULE:0#202020 \\
2>&1 > /dev/null";
}
sub prioMap
{
my $this = shift;
my $in = shift;
my $out = shift;
open IN, "/sbin/tc -s qdisc show dev $in 2> /dev/null | grep \"^ Sent\" |";
my @inqueues;
while (<IN>)
{
chomp;
/^ Sent (\d+) bytes.*$/;
my $bytes = $1 || 0;
push @inqueues, $bytes;
}
close IN;
shift @inqueues;
open OUT, "/sbin/tc -s qdisc show dev $out 2> /dev/null | grep \"^ Sent\" |";
my @outqueues;
while (<OUT>)
{
chomp;
/^ Sent (\d+) bytes.*$/;
my $bytes = $1 || 0;
push @outqueues, $bytes;
}
close OUT;
shift @outqueues;
print "tc1 in/out: $inqueues[0]/$outqueues[0] bytes\n";
print "tc2 in/out: $inqueues[1]/$outqueues[1] bytes\n";
print "tc3 in/out: $inqueues[2]/$outqueues[2] bytes\n";
print "tc4 in/out: $inqueues[3]/$outqueues[3] bytes\n";
my $filename = "$this->{_rrd}/tc-$in-$out.rrd";
if (! -e $filename)
{
print "creating rrd database for client tc-ppp0...\n";
system "$this->{_rrdtool} create \"$filename\" \\
-s 300 \\
DS:intc1:DERIVE:600:0:U \\
DS:intc2:DERIVE:600:0:U \\
DS:intc3:DERIVE:600:0:U \\
DS:intc4:DERIVE:600:0:U \\
DS:outtc1:DERIVE:600:0:U \\
DS:outtc2:DERIVE:600:0:U \\
DS:outtc3:DERIVE:600:0:U \\
DS:outtc4:DERIVE:600:0:U \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t intc1:intc2:intc3:intc4:outtc1:outtc2:outtc3:outtc4 \\
N:$inqueues[0]:$inqueues[1]:$inqueues[2]:$inqueues[3]:$outqueues[0]:$outqueues[1]:$outqueues[2]:$outqueues[3]";
$this->tcGraph("tc-$in-$out", 'day');
$this->tcGraph("tc-$in-$out", 'week');
$this->tcGraph("tc-$in-$out", 'month');
$this->tcGraph("tc-$in-$out", 'year');
}
sub tcGraph
{
my $this = shift;
my $name = shift;
my $type = shift;
system "$this->{_rrdtool} graph \"$this->{_img}/$name-$type.png\" \\
-s -1$type \\
-t \"Traffic shapping ADSL (ATM rate)\" \\
--lazy \\
--tabwidth 20 \\
-h 250 -w 1100 \\
--border 0 \\
-l 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"o/s\" \\
DEF:intc1=$this->{_rrd}/$name.rrd:intc1:AVERAGE \\
DEF:intc2=$this->{_rrd}/$name.rrd:intc2:AVERAGE \\
DEF:intc3=$this->{_rrd}/$name.rrd:intc3:AVERAGE \\
DEF:intc4=$this->{_rrd}/$name.rrd:intc4:AVERAGE \\
DEF:outtc1=$this->{_rrd}/$name.rrd:outtc1:AVERAGE \\
DEF:outtc2=$this->{_rrd}/$name.rrd:outtc2:AVERAGE \\
DEF:outtc3=$this->{_rrd}/$name.rrd:outtc3:AVERAGE \\
DEF:outtc4=$this->{_rrd}/$name.rrd:outtc4:AVERAGE \\
CDEF:outtc1_neg=outtc1,-1,* \\
CDEF:outtc2_neg=outtc2,-1,* \\
CDEF:outtc3_neg=outtc3,-1,* \\
CDEF:outtc4_neg=outtc4,-1,* \\
VDEF:intc1max=intc1,MAXIMUM \\
VDEF:intc1avg=intc1,AVERAGE \\
VDEF:intc1last=intc1,LAST \\
VDEF:intc2max=intc2,MAXIMUM \\
VDEF:intc2avg=intc2,AVERAGE \\
VDEF:intc2last=intc2,LAST \\
VDEF:intc3max=intc3,MAXIMUM \\
VDEF:intc3avg=intc3,AVERAGE \\
VDEF:intc3last=intc3,LAST \\
VDEF:intc4max=intc4,MAXIMUM \\
VDEF:intc4avg=intc4,AVERAGE \\
VDEF:intc4last=intc4,LAST \\
VDEF:outtc1max=outtc1,MAXIMUM \\
VDEF:outtc1avg=outtc1,AVERAGE \\
VDEF:outtc1last=outtc1,LAST \\
VDEF:outtc2max=outtc2,MAXIMUM \\
VDEF:outtc2avg=outtc2,AVERAGE \\
VDEF:outtc2last=outtc2,LAST \\
VDEF:outtc3max=outtc3,MAXIMUM \\
VDEF:outtc3avg=outtc3,AVERAGE \\
VDEF:outtc3last=outtc3,LAST \\
VDEF:outtc4max=outtc4,MAXIMUM \\
VDEF:outtc4avg=outtc4,AVERAGE \\
VDEF:outtc4last=outtc4,LAST \\
COMMENT:\"Incomming\\n\" \\
AREA:intc4#E3D85D:\"Low+Guest\t\" \\
GPRINT:intc4max:\"Max\\: %8.2lf %s\" \\
GPRINT:intc4avg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:intc4last:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
AREA:intc3#68A5D3:\"Defaut\t\t\":STACK \\
GPRINT:intc3max:\"Max\\: %8.2lf %s\" \\
GPRINT:intc3avg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:intc3last:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
AREA:intc2#A0E59C:\"Mail\t\t\":STACK \\
GPRINT:intc2max:\"Max\\: %8.2lf %s\" \\
GPRINT:intc2avg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:intc2last:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
AREA:intc1#E36363:\"Interactif\t\":STACK \\
GPRINT:intc1max:\"Max\\: %8.2lf %s\" \\
GPRINT:intc1avg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:intc1last:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
COMMENT:\"Outgoing\\n\" \\
AREA:outtc4_neg#E3D85D:\"Low+Guest\t\" \\
GPRINT:outtc4max:\"Max\\: %8.2lf %s\" \\
GPRINT:outtc4avg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:outtc4last:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
AREA:outtc3_neg#68A5D3:\"Defaut\t\t\":STACK \\
GPRINT:outtc3max:\"Max\\: %8.2lf %s\" \\
GPRINT:outtc3avg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:outtc3last:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
AREA:outtc2_neg#A0E59C:\"Mail\t\t\":STACK \\
GPRINT:outtc2max:\"Max\\: %8.2lf %s\" \\
GPRINT:outtc2avg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:outtc2last:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
AREA:outtc1_neg#E36363:\"Interactif\t\":STACK \\
GPRINT:outtc1max:\"Max\\: %8.2lf %s\" \\
GPRINT:outtc1avg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:outtc1last:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
HRULE:0#202020 \\
2>&1 > /dev/null";
}
sub cpu
{
my $this = shift;
my $stat = `grep '^cpu ' /proc/stat`;
my @res = ($stat =~ m/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/);
my $user = $res[0];
my $nice = $res[1];
my $sys = $res[2];
my $iowait = $res[4];
print "CPU user : $user\n";
print "CPU nice : $nice\n";
print "CPU systeme : $sys\n";
print "CPU iowait : $iowait\n";
my $filename = "$this->{_rrd}/system-cpu.rrd";
if (! -e $filename)
{
print "creating rrd database for cpu...\n";
system "$this->{_rrdtool} create \"$filename\" \\
-s 300 \\
DS:user:DERIVE:600:0:U \\
DS:sys:DERIVE:600:0:U \\
DS:nice:DERIVE:600:0:U \\
DS:iowait:DERIVE:600:0:U \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t user:sys:nice:iowait N:$user:$sys:$nice:$iowait";
$this->cpuGraph('day');
$this->cpuGraph('week');
$this->cpuGraph('month');
$this->cpuGraph('year');
}
sub cpuGraph
{
my $this = shift;
my $type = shift;
my $rrd_filename = "$this->{_rrd}/system-cpu.rrd";
my $graph_filename = "$this->{_img}/system-cpu-$type.png";
my $ncpu=`grep -E '^cpu[0-9]+ ' /proc/stat | wc -l`;
my $max = $ncpu * 100;
system "$this->{_rrdtool} graph \"$graph_filename\" \\
--lazy \\
--tabwidth 20 \\
-s -1$type \\
-t \"Utilisation CPU\" \\
-h 250 -w 1100 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"%\" \\
-u $max \\
-l 0 \\
-r \\
DEF:user=$rrd_filename:user:AVERAGE \\
DEF:sys=$rrd_filename:sys:AVERAGE \\
DEF:iowait=$rrd_filename:iowait:AVERAGE \\
DEF:nice=$rrd_filename:nice:AVERAGE \\
VDEF:usermax=user,MAXIMUM \\
VDEF:useravg=user,AVERAGE \\
VDEF:userlast=user,LAST \\
VDEF:sysmax=sys,MAXIMUM \\
VDEF:sysavg=sys,AVERAGE \\
VDEF:syslast=sys,LAST \\
VDEF:iowaitmax=iowait,MAXIMUM \\
VDEF:iowaitavg=iowait,AVERAGE \\
VDEF:iowaitlast=iowait,LAST \\
VDEF:nicemax=nice,MAXIMUM \\
VDEF:niceavg=nice,AVERAGE \\
VDEF:nicelast=nice,LAST \\
AREA:user#A0E59C:\"Utilisateur\t\" \\
GPRINT:usermax:\"Max\\: %6.2lf\" \\
GPRINT:useravg:\"\tAvg\\: %6.2lf\" \\
GPRINT:userlast:\"\tCurrent\\: %6.2lf %%\\n\" \\
AREA:sys#E36363:\"Systeme\t\t\":STACK \\
GPRINT:sysmax:\"Max\\: %6.2lf\" \\
GPRINT:sysavg:\"\tAvg\\: %6.2lf\" \\
GPRINT:syslast:\"\tCurrent\\: %6.2lf %%\\n\" \\
AREA:iowait#E3D85D:\"IO wait\t\t\":STACK \\
GPRINT:iowaitmax:\"Max\\: %6.2lf\" \\
GPRINT:iowaitavg:\"\tAvg\\: %6.2lf\" \\
GPRINT:iowaitlast:\"\tCurrent\\: %6.2lf %%\\n\" \\
AREA:nice#68A5D3:\"Nice\t\t\":STACK \\
GPRINT:nicemax:\"Max\\: %6.2lf\" \\
GPRINT:niceavg:\"\tAvg\\: %6.2lf\" \\
GPRINT:nicelast:\"\tCurrent\\: %6.2lf %%\\n\" \\
2>&1 > /dev/null";
}
sub memory
{
my $this = shift;
my $ramMax = shift;
my $swapMax = shift;
my $mems = ();
open IN, "</proc/meminfo";
while (<IN>)
{
if (/^(\w+):\s*(\d+)\s+kb/i)
{
$mems->{$1} = $2 / 1024;
}
}
close (IN);
my $total = ($mems->{'MemTotal'} || 0) - ($mems->{'MemFree'} || 0);
my $apps = ($mems->{'MemTotal'} || 0) - ($mems->{'MemFree'} || 0) - ($mems->{'Buffers'} || 0) - ($mems->{'Cached'} || 0) - ($mems->{'Slab'} || 0) - ($mems->{'PageTables'} || 0);
my $cache = $mems->{'Cached'} || 0;
my $buffers = $mems->{'Buffers'} || 0;
my $slab = $mems->{'Slab'} || 0;
my $swap = ($mems->{'SwapTotal'} || 0) - ($mems->{'SwapFree'} || 0);
print "Total : $total\n";
print "Apps : $apps\n";
print "Cache : $cache\n";
print "Buffers : $buffers\n";
print "Slab : $slab\n";
print "Swap : $swap\n";
my $filename = "$this->{_rrd}/system-mem.rrd";
if (! -e $filename)
{
print "creating rrd database for mem...\n";
system "$this->{_rrdtool} create \"$filename\" \\
-s 300 \\
DS:apps:GAUGE:600:0:$ramMax \\
DS:cache:GAUGE:600:0:$ramMax \\
DS:buffers:GAUGE:600:0:$ramMax \\
DS:slab:GAUGE:600:0:$ramMax \\
DS:total:GAUGE:600:0:$ramMax \\
DS:swap:GAUGE:600:0:$swapMax \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t apps:cache:buffers:slab:total:swap N:$apps:$cache:$buffers:$slab:$total:$swap";
$this->memoryGraph('day');
$this->memoryGraph('week');
$this->memoryGraph('month');
$this->memoryGraph('year');
}
sub memoryGraph
{
my $this = shift;
my $type = shift;
my $rrd_filename = "$this->{_rrd}/system-mem.rrd";
my $graph_filename = "$this->{_img}/system-mem-$type.png";
system "$this->{_rrdtool} graph \"$graph_filename\" \\
--lazy \\
--tabwidth 20 \\
-s -1$type \\
-t \"Utilisation Memoire\" \\
-h 250 -w 1100 \\
-l 0 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"Mo\" \\
-b 1024 \\
DEF:apps=$rrd_filename:apps:AVERAGE \\
DEF:cache=$rrd_filename:cache:AVERAGE \\
DEF:buffers=$rrd_filename:buffers:AVERAGE \\
DEF:slab=$rrd_filename:slab:AVERAGE \\
DEF:total=$rrd_filename:total:AVERAGE \\
DEF:swap=$rrd_filename:swap:AVERAGE \\
CDEF:swap_neg=swap,-1,* \\
VDEF:appsmin=apps,MINIMUM \\
VDEF:appsmax=apps,MAXIMUM \\
VDEF:appsavg=apps,AVERAGE \\
VDEF:appslast=apps,LAST \\
VDEF:cachemin=cache,MINIMUM \\
VDEF:cachemax=cache,MAXIMUM \\
VDEF:cacheavg=cache,AVERAGE \\
VDEF:cachelast=cache,LAST \\
VDEF:buffersmin=buffers,MINIMUM \\
VDEF:buffersmax=buffers,MAXIMUM \\
VDEF:buffersavg=buffers,AVERAGE \\
VDEF:bufferslast=buffers,LAST \\
VDEF:slabmin=slab,MINIMUM \\
VDEF:slabmax=slab,MAXIMUM \\
VDEF:slabavg=slab,AVERAGE \\
VDEF:slablast=slab,LAST \\
VDEF:totalmin=total,MINIMUM \\
VDEF:totalmax=total,MAXIMUM \\
VDEF:totalavg=total,AVERAGE \\
VDEF:totallast=total,LAST \\
VDEF:swapmin=swap,MINIMUM \\
VDEF:swapmax=swap,MAXIMUM \\
VDEF:swapavg=swap,AVERAGE \\
VDEF:swaplast=swap,LAST \\
AREA:total#3B743F:\"Total\t\" \\
GPRINT:totalmin:\"Min\\: %8.2lf\" \\
GPRINT:totalmax:\"\tMax\\: %8.2lf\" \\
GPRINT:totalavg:\"\tAvg\\: %8.2lf\" \\
GPRINT:totallast:\"\tCurrent\\: %8.2lf Mo\\n\" \\
AREA:apps#E36363:\"Apps\t\" \\
GPRINT:appsmin:\"Min\\: %8.2lf\" \\
GPRINT:appsmax:\"\tMax\\: %8.2lf\" \\
GPRINT:appsavg:\"\tAvg\\: %8.2lf\" \\
GPRINT:appslast:\"\tCurrent\\: %8.2lf Mo\\n\" \\
AREA:cache#68A5D3:\"Cache\t\":STACK \\
GPRINT:cachemin:\"Min\\: %8.2lf\" \\
GPRINT:cachemax:\"\tMax\\: %8.2lf\" \\
GPRINT:cacheavg:\"\tAvg\\: %8.2lf\" \\
GPRINT:cachelast:\"\tCurrent\\: %8.2lf Mo\\n\" \\
AREA:buffers#3D617C:\"Buffers\t\":STACK \\
GPRINT:buffersmin:\"Min\\: %8.2lf\" \\
GPRINT:buffersmax:\"\tMax\\: %8.2lf\" \\
GPRINT:buffersavg:\"\tAvg\\: %8.2lf\" \\
GPRINT:bufferslast:\"\tCurrent\\: %8.2lf Mo\\n\" \\
AREA:slab#A0E59C:\"Slab\t\":STACK \\
GPRINT:slabmin:\"Min\\: %8.2lf\" \\
GPRINT:slabmax:\"\tMax\\: %8.2lf\" \\
GPRINT:slabavg:\"\tAvg\\: %8.2lf\" \\
GPRINT:slablast:\"\tCurrent\\: %8.2lf Mo\\n\" \\
AREA:swap_neg#E3D85D:\"Swap\t\" \\
GPRINT:swapmin:\"Min\\: %8.2lf\" \\
GPRINT:swapmax:\"\tMax\\: %8.2lf\" \\
GPRINT:swapavg:\"\tAvg\\: %8.2lf\" \\
GPRINT:swaplast:\"\tCurrent\\: %8.2lf Mo\\n\" \\
HRULE:0#202020 \\
2>&1 > /dev/null";
}
sub load
{
my $this = shift;
my $charge=`cut -f2 -d' ' < /proc/loadavg`;
chomp $charge;
print "CPU Load : $charge\n";
my $filename = "$this->{_rrd}/system-load.rrd";
if (! -e $filename)
{
print "creating rrd database for load...\n";
system "$this->{_rrdtool} create \"$filename\" \\
-s 300 \\
DS:charge:GAUGE:600:0:100 \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t charge N:$charge";
$this->loadGraph('day');
$this->loadGraph('week');
$this->loadGraph('month');
$this->loadGraph('year');
}
sub loadGraph
{
my $this = shift;
my $type = shift;
my $rrd_filename = "$this->{_rrd}/system-load.rrd";
my $graph_filename = "$this->{_img}/system-load-$type.png";
system "$this->{_rrdtool} graph \"$graph_filename\" \\
--lazy \\
--tabwidth 20 \\
-s -1$type \\
-t \"Charge Systeme\" \\
-X 0 \\
-h 250 -w 1100 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v load \\
DEF:charge=$rrd_filename:charge:AVERAGE \\
VDEF:chargemax=charge,MAXIMUM \\
VDEF:chargeavg=charge,AVERAGE \\
VDEF:chargelast=charge,LAST \\
LINE1.5:charge#3D617C:\"Charge Systeme\t\" \\
GPRINT:chargemax:\"Max\\: %4.2lf\" \\
GPRINT:chargeavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:chargelast:\"\tCurrent\\: %4.2lf\\n\" \\
2>&1 > /dev/null";
}
sub cswitch
{
my $this = shift;
my $intr;
my $ctxt;
open IN, "</proc/stat";
while (my $line = <IN>)
{
if (my ($val) = ($line =~ m/^intr\s+(\d+)/))
{
$intr = $val;
}
if (my ($val) = ($line =~ m/^ctxt\s+(\d+)/))
{
$ctxt = $val;
}
}
close (IN);
print "Interrupts: $intr\n";
print "Context switches: $ctxt\n";
my $filename = "$this->{_rrd}/system-cswitch.rrd";
if (! -e $filename)
{
print "creating rrd database for cswitch...\n";
system "$this->{_rrdtool} create \"$filename\" -s 300 \\
DS:intr:DERIVE:600:0:100000 \\
DS:ctxt:DERIVE:600:0:100000 \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t intr:ctxt N:$intr:$ctxt";
$this->cswitchGraph('day');
$this->cswitchGraph('week');
$this->cswitchGraph('month');
$this->cswitchGraph('year');
}
sub cswitchGraph
{
my $this = shift;
my $type = shift;
my $rrd_filename = "$this->{_rrd}/system-cswitch.rrd";
my $graph_filename = "$this->{_img}/system-cswitch-$type.png";
system "$this->{_rrdtool} graph \"$graph_filename\" \\
-s -1$type \\
-t 'Interrupts / Context switches' \\
--lazy \\
--tabwidth 20 \\
-h 250 -w 1100 \\
-l 0 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"unit/s\" \\
DEF:ctxt=$rrd_filename:ctxt:AVERAGE \\
DEF:intr=$rrd_filename:intr:AVERAGE \\
VDEF:ctxtmax=ctxt,MAXIMUM \\
VDEF:ctxtavg=ctxt,AVERAGE \\
VDEF:ctxtlast=ctxt,LAST \\
VDEF:intrmax=intr,MAXIMUM \\
VDEF:intravg=intr,AVERAGE \\
VDEF:intrlast=intr,LAST \\
LINE1.5:ctxt#3D617C:\"Context switches\t\" \\
GPRINT:ctxtmax:\"Max\\: %8.2lf %S\" \\
GPRINT:ctxtavg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:ctxtlast:\"\tCurrent\\: %8.2lf %Sunit/s\\n\" \\
LINE1.5:intr#3B743F:\"Interrupts\t\t\" \\
GPRINT:intrmax:\"Max\\: %8.2lf %s\" \\
GPRINT:intravg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:intrlast:\"\tCurrent\\: %8.2lf %Sunit/s\\n\" \\
2>&1 > /dev/null";
}
sub iostat
{
my $this = shift;
my $device = shift;
my $devstring = `grep ' $device ' /proc/diskstats`;
my ($rio, $rmerge, $rsect, $ruse, $wio, $wmerge, $wsect, $wuse) = ($devstring =~ m/$device\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/);
print "I/O read: $rsect\n";
print "I/O write: $wsect\n";
my $filename = "$this->{_rrd}/system-iostat-$device.rrd";
if (! -e $filename)
{
print "creating rrd database for cswitch...\n";
system "$this->{_rrdtool} create \"$filename\" -s 300 \\
DS:rsect:DERIVE:600:0:U \\
DS:wsect:DERIVE:600:0:U \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t rsect:wsect N:$rsect:$wsect";
$this->iostatGraph($device, 'day');
$this->iostatGraph($device, 'week');
$this->iostatGraph($device, 'month');
$this->iostatGraph($device, 'year');
}
sub iostatGraph
{
my $this = shift;
my $device = shift;
my $type = shift;
my $rrd_filename = "$this->{_rrd}/system-iostat-$device.rrd";
my $graph_filename = "$this->{_img}/system-iostat-$device-$type.png";
system "$this->{_rrdtool} graph \"$graph_filename\" \\
-s -1$type \\
-t 'I/O :: /dev/$device' \\
--lazy \\
--tabwidth 20 \\
-h 250 -w 1100 \\
-l 0 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"blocs/s\" \\
DEF:wsect=$rrd_filename:wsect:AVERAGE \\
DEF:rsect=$rrd_filename:rsect:AVERAGE \\
VDEF:wsectmax=wsect,MAXIMUM \\
VDEF:wsectavg=wsect,AVERAGE \\
VDEF:wsectlast=wsect,LAST \\
VDEF:rsectmax=rsect,MAXIMUM \\
VDEF:rsectavg=rsect,AVERAGE \\
VDEF:rsectlast=rsect,LAST \\
LINE1.5:wsect#3D617C:\"I/O write\t\" \\
GPRINT:wsectmax:\"Max\\: %8.2lf %S\" \\
GPRINT:wsectavg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:wsectlast:\"\tCurrent\\: %8.2lf %Sblocs/s\\n\" \\
LINE1.5:rsect#3B743F:\"I/O read\t\" \\
GPRINT:rsectmax:\"Max\\: %8.2lf %s\" \\
GPRINT:rsectavg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:rsectlast:\"\tCurrent\\: %8.2lf %Sblocs/s\\n\" \\
2>&1 > /dev/null";
}
sub hddtemp
{
my $this = shift;
my $device = shift;
my $title = shift;
my $temp;
if ($device =~ /nvm/)
{
$temp = `/usr/sbin/nvme smart-log /dev/$device | awk '/temperature/ {gsub("°C", "", \$3); print \$3}'`
}
else
{
$temp = `/usr/sbin/hddtemp -n /dev/$device`;
}
$temp =~ s/[\n ]//g;
print "$title (/dev/$device) temp: $temp degrees C\n";
my $filename = "$this->{_rrd}/system-$device.rrd";
if (! -e $filename)
{
print "creating rrd database for /dev/$device...\n";
system "$this->{_rrdtool} create \"$filename\" \\
-s 300 \\
DS:temp:GAUGE:600:0:100 \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t temp N:$temp";
$this->hddtempGraph($device, 'day', $title);
$this->hddtempGraph($device, 'week', $title);
$this->hddtempGraph($device, 'month', $title);
$this->hddtempGraph($device, 'year', $title);
}
sub hddtempGraph
{
my $this = shift;
my $device = shift;
my $type = shift;
my $title = shift;
my $rrd_filename = "$this->{_rrd}/system-$device.rrd";
my $graph_filename = "$this->{_img}/system-$device-$type.png";
system "$this->{_rrdtool} graph \"$graph_filename\" \\
--lazy \\
--tabwidth 20 \\
-s -1$type \\
-t \"Temperature DD :: $title (/dev/$device)\" \\
-h 250 -w 1100 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"C\" \\
DEF:temp=$rrd_filename:temp:AVERAGE \\
VDEF:tempmin=temp,MINIMUM \\
VDEF:tempmax=temp,MAXIMUM \\
VDEF:tempavg=temp,AVERAGE \\
VDEF:templast=temp,LAST \\
LINE1.5:temp#3D617C:\"$title (/dev/$device)\t\" \\
GPRINT:tempmin:\"Min\\: %4.2lf\" \\
GPRINT:tempmax:\"\tMax\\: %4.2lf\" \\
GPRINT:tempavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:templast:\"\tCurrent\\: %4.2lf C\\n\" \\
2>&1 > /dev/null";
}
sub sensorstemp
{
my $this = shift;
my $sets = shift;
my $valuesCollected = {};
my $sensorsData = decode_json `sensors -j 2>/dev/null`;
for my $hwmon (keys %$sets)
{
my $sensors = $sets->{$hwmon};
for my $key (keys %$sensors)
{
my $item = $sensors->{$key};
my $temp = $sensorsData->{$hwmon}->{$key}->{$item->{key}} || 0;
print $item->{name}, " : $temp degrees C\n";
# ds can only be 19 chars long [a-zA-Z0-9_] - this should not colide that much
my $ds = substr md5_hex($hwmon . '_' . $item->{key}), 0, 19;
$valuesCollected->{$ds}->{name} = $item->{name};
$valuesCollected->{$ds}->{value} = $temp;
}
}
my $filename = "$this->{_rrd}/system-sensors.rrd";
if (! -e $filename)
{
print "creating rrd database for system temperatures...\n";
my $entries = '';
for my $device (keys %$valuesCollected)
{
$entries .= "DS:$device:GAUGE:600:0:127 ";
}
system "$this->{_rrdtool} create \"$filename\" \\
-s 300 \\
$entries \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
# attention : sort pour faire coller les clés !!
my $entries = join ':', sort keys %$valuesCollected;
my $values = 'N';
for my $device (sort keys %$valuesCollected)
{
$values .= ":" . $valuesCollected->{$device}->{value};
}
system "$this->{_rrdtool} update \"$filename\" -t $entries $values";
$this->sensorstempGraph('day', $valuesCollected);
$this->sensorstempGraph('week', $valuesCollected);
$this->sensorstempGraph('month', $valuesCollected);
$this->sensorstempGraph('year', $valuesCollected);
}
sub sensorstempGraph
{
my $this = shift;
my $type = shift;
my $sensors = shift;
my $rrd_filename = "$this->{_rrd}/system-sensors.rrd";
my $graph_filename = "$this->{_img}/system-sensors-$type.png";
my @colors = ("#3D617C", "#3B743F", "#913F3F", "#68A5D3", "#A0E59C", "#E36363", "#E3D85D", "#6e3d7c", "#bc68d3", "#7c633d", "#d3a868");
my $colorId = 0;
my $defs = '';
# lexical sort for graph
my @orderedKeys = sort { $sensors->{$a}->{name} cmp $sensors->{$b}->{name} } keys %$sensors;
for my $device (@orderedKeys)
{
$defs .= "DEF:$device=$rrd_filename:$device:AVERAGE \\
VDEF:${device}min=$device,MINIMUM \\
VDEF:${device}max=$device,MAXIMUM \\
VDEF:${device}avg=$device,AVERAGE \\
VDEF:${device}last=$device,LAST \\
LINE1.5:${device}$colors[$colorId]:\"$sensors->{$device}->{name}\t\" \\
GPRINT:${device}min:\"Min\\: %4.2lf\" \\
GPRINT:${device}max:\"\tMax\\: %4.2lf\" \\
GPRINT:${device}avg:\"\tAvg\\: %4.2lf\" \\
GPRINT:${device}last:\"\tCurrent\\: %4.2lf C\\n\" ";
$colorId = ($colorId + 1) % scalar @colors;
}
system "$this->{_rrdtool} graph \"$graph_filename\" \\
-s -1$type \\
-t 'Températures système' \\
--lazy \\
--tabwidth 20 \\
-h 250 -w 1100 \\
-l 0 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"C\" \\
$defs \\
2>&1 > /dev/null";
}
sub sensorsfan
{
my $this = shift;
my $sets = shift;
my $valuesCollected = {};
my $sensorsData = decode_json `sensors -j 2>/dev/null`;
for my $hwmon (keys %$sets)
{
my $sensors = $sets->{$hwmon};
for my $key (keys %$sensors)
{
my $item = $sensors->{$key};
my $rpm = $sensorsData->{$hwmon}->{$key}->{$item->{key}} || 0;
print $item->{name}, " : $rpm RPM\n";
# ds can only be 19 chars long [a-zA-Z0-9_] - this should not colide that much
my $ds = substr md5_hex($hwmon . '_' . $item->{key}), 0, 19;
$valuesCollected->{$ds}->{name} = $item->{name};
$valuesCollected->{$ds}->{value} = $rpm;
}
}
my $filename = "$this->{_rrd}/system-fan-sensors.rrd";
if (! -e $filename)
{
print "creating rrd database for system fan speed...\n";
my $entries = '';
for my $device (keys %$valuesCollected)
{
$entries .= "DS:$device:GAUGE:600:0:3000 ";
}
system "$this->{_rrdtool} create \"$filename\" \\
-s 300 \\
$entries \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
# attention : sort pour faire coller les clés !!
my $entries = join ':', sort keys %$valuesCollected;
my $values = 'N';
for my $device (sort keys %$valuesCollected)
{
$values .= ":" . $valuesCollected->{$device}->{value};
}
system "$this->{_rrdtool} update \"$filename\" -t $entries $values";
$this->sensorsfanGraph('day', $valuesCollected);
$this->sensorsfanGraph('week', $valuesCollected);
$this->sensorsfanGraph('month', $valuesCollected);
$this->sensorsfanGraph('year', $valuesCollected);
}
sub sensorsfanGraph
{
my $this = shift;
my $type = shift;
my $sensors = shift;
my $rrd_filename = "$this->{_rrd}/system-fan-sensors.rrd";
my $graph_filename = "$this->{_img}/system-fan-sensors-$type.png";
my @colors = ("#3D617C", "#3B743F", "#913F3F", "#68A5D3", "#A0E59C", "#E36363", "#E3D85D");
my $colorId = 0;
my $defs = '';
# lexical sort for graph
my @orderedKeys = sort { $sensors->{$a}->{name} cmp $sensors->{$b}->{name} } keys %$sensors;
for my $device (@orderedKeys)
{
$defs .= "DEF:$device=$rrd_filename:$device:AVERAGE \\
VDEF:${device}min=$device,MINIMUM \\
VDEF:${device}max=$device,MAXIMUM \\
VDEF:${device}avg=$device,AVERAGE \\
VDEF:${device}last=$device,LAST \\
LINE1.5:${device}$colors[$colorId]:\"$sensors->{$device}->{name}\t\" \\
GPRINT:${device}min:\"Min\\: %4.2lf\" \\
GPRINT:${device}max:\"\tMax\\: %4.2lf\" \\
GPRINT:${device}avg:\"\tAvg\\: %4.2lf\" \\
GPRINT:${device}last:\"\tCurrent\\: %4.2lf RPM\\n\" ";
$colorId = ($colorId + 1) % scalar @colors;
}
system "$this->{_rrdtool} graph \"$graph_filename\" \\
-s -1$type \\
-t 'Vitesse ventilation' \\
--lazy \\
--tabwidth 20 \\
-h 250 -w 1100 \\
-l 0 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"RPM\" \\
$defs \\
2>&1 > /dev/null";
}
sub ups
{
my $this = shift;
my $upsname = shift;
my $multiplier = shift;
my $upsc = ();
open IN, "upsc $upsname |";
while (<IN>)
{
if (/^([\w.]+):\s*([\d.]+)/i)
{
$upsc->{$1} = $2;
}
}
close (IN);
my $load = $upsc->{'ups.load'};
my $input = $upsc->{'input.voltage'};
my $output= $upsc->{'output.voltage'};
chomp $load;
chomp $input;
chomp $output;
$load *= $multiplier;
print "UPS $upsname load: $load VA\n";
print "UPS $upsname input voltage: $input V\n";
print "UPS $upsname output voltage: $output V\n";
if (! -e "$this->{_rrd}/ups-$upsname.rrd")
{
print "creating rrd database for UPS $upsname...\n";
system "$this->{_rrdtool} create \"$this->{_rrd}/ups-$upsname.rrd\" \\
-s 300 \\
DS:load:GAUGE:600:0:500 \\
DS:input:GAUGE:600:0:500 \\
DS:output:GAUGE:600:0:500 \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$this->{_rrd}/ups-$upsname.rrd\" -t load:input:output N:$load:$input:$output";
$this->upsGraph($upsname, 'day');
$this->upsGraph($upsname, 'week');
$this->upsGraph($upsname, 'month');
$this->upsGraph($upsname, 'year');
}
sub upsGraph
{
my $this = shift;
my $upsname = shift;
my $type = shift;
system "$this->{_rrdtool} graph \"$this->{_img}/ups-load-$upsname-$type.png\" \\
--lazy \\
--tabwidth 20 \\
-s -1$type \\
-t \"Charge UPS :: $upsname\" \\
-h 250 -w 1100 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"VA\" \\
DEF:load=$this->{_rrd}/ups-$upsname.rrd:load:AVERAGE \\
VDEF:loadmin=load,MINIMUM \\
VDEF:loadmax=load,MAXIMUM \\
VDEF:loadavg=load,AVERAGE \\
VDEF:loadlast=load,LAST \\
LINE1.5:load#3D617C:\"Charge\t\" \\
GPRINT:loadmin:\"Min\\: %4.2lf\" \\
GPRINT:loadmax:\"\tMax\\: %4.2lf\" \\
GPRINT:loadavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:loadlast:\"\tCurrent\\: %4.2lf VA\\n\" \\
2>&1 > /dev/null";
system "$this->{_rrdtool} graph \"$this->{_img}/ups-voltage-$upsname-$type.png\" \\
--lazy \\
--tabwidth 20 \\
-s -1$type \\
-t \"Tension UPS :: $upsname\" \\
-h 250 -w 1100 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"V\" \\
DEF:input=$this->{_rrd}/ups-$upsname.rrd:input:AVERAGE \\
DEF:output=$this->{_rrd}/ups-$upsname.rrd:output:AVERAGE \\
VDEF:inputmin=input,MINIMUM \\
VDEF:inputmax=input,MAXIMUM \\
VDEF:inputavg=input,AVERAGE \\
VDEF:inputlast=input,LAST \\
VDEF:outputmin=output,MINIMUM \\
VDEF:outputmax=output,MAXIMUM \\
VDEF:outputavg=output,AVERAGE \\
VDEF:outputlast=output,LAST \\
LINE1.5:input#3D617C:\"Tension entrée\t\" \\
GPRINT:inputmin:\"Min\\: %4.2lf\" \\
GPRINT:inputmax:\"\tMax\\: %4.2lf\" \\
GPRINT:inputavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:inputlast:\"\tCurrent\\: %4.2lf V\\n\" \\
LINE1.5:output#3B743F:\"Tension sortie\t\" \\
GPRINT:outputmin:\"Min\\: %4.2lf\" \\
GPRINT:outputmax:\"\tMax\\: %4.2lf\" \\
GPRINT:outputavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:outputlast:\"\tCurrent\\: %4.2lf V\\n\" \\
2>&1 > /dev/null";
}
sub nginx
{
my $this = shift;
my $url = shift;
my $ua = LWP::UserAgent->new (timeout => 10);
my $response = $ua->get ($url);
my $connections_accept = "U";
my $connections_handeled = "U";
my $requests = "U";
if ($response->content =~ /^\s*(\d+)\s+(\d+)\s+(\d+)\s*$/im)
{
$connections_accept = $1;
$connections_handeled = $2;
$requests = $3;
}
print "nginx requests: $connections_accept $connections_handeled $requests\n";
my $filename = "$this->{_rrd}/system-nginx.rrd";
if (! -e $filename)
{
print "creating rrd database for nginx...\n";
system "$this->{_rrdtool} create \"$filename\" \\
-s 300 \\
DS:connectionsaccept:DERIVE:600:0:U \\
DS:connectionshandeled:DERIVE:600:0:U \\
DS:requests:DERIVE:600:0:U \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t connectionsaccept:connectionshandeled:requests N:$connections_accept:$connections_handeled:$requests";
$this->nginxGraph('day');
$this->nginxGraph('week');
$this->nginxGraph('month');
$this->nginxGraph('year');
}
sub nginxGraph
{
my $this = shift;
my $type = shift;
my $rrd_filename = "$this->{_rrd}/system-nginx.rrd";
my $graph_filename = "$this->{_img}/system-nginx-$type.png";
system "$this->{_rrdtool} graph \"$graph_filename\" \\
--lazy \\
--tabwidth 20 \\
-s -1$type \\
-t \"Requêtes nginx\" \\
-h 250 -w 1100 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"reqs/s\" \\
DEF:connectionsaccept=$rrd_filename:connectionsaccept:AVERAGE \\
DEF:connectionshandeled=$rrd_filename:connectionshandeled:AVERAGE \\
DEF:requests=$rrd_filename:requests:AVERAGE \\
VDEF:camax=connectionsaccept,MAXIMUM \\
VDEF:caavg=connectionsaccept,AVERAGE \\
VDEF:calast=connectionsaccept,LAST \\
VDEF:chmax=connectionshandeled,MAXIMUM \\
VDEF:chavg=connectionshandeled,AVERAGE \\
VDEF:chlast=connectionshandeled,LAST \\
VDEF:requestsmax=requests,MAXIMUM \\
VDEF:requestsavg=requests,AVERAGE \\
VDEF:requestslast=requests,LAST \\
LINE1.5:connectionsaccept#3D617C:\"Connections\t\t\t\" \\
GPRINT:camax:\"Max\\: %4.2lf\" \\
GPRINT:caavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:calast:\"\tCurrent\\: %4.2lf conns/s\\n\" \\
LINE1.5:connectionshandeled#3B743F:\"Connections handeled\t\" \\
GPRINT:chmax:\"Max\\: %4.2lf\" \\
GPRINT:chavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:chlast:\"\tCurrent\\: %4.2lf conns/s\\n\" \\
LINE1.5:requests#913F3F:\"Requests\t\t\t\" \\
GPRINT:requestsmax:\"Max\\: %4.2lf\" \\
GPRINT:requestsavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:requestslast:\"\tCurrent\\: %4.2lf reqs/s\\n\" \\
2>&1 > /dev/null";
}
sub haproxy
{
my $this = shift;
my $socket = shift;
my $farms = shift;
my $sock = new IO::Socket::UNIX (Peer => $socket, Type => SOCK_STREAM, Timeout => 1);
return if not $sock;
print $sock "show stat\n";
while (<$sock>)
{
chomp;
my @csv = split /,/;
# HTTP stats
next if not defined $csv[1];
if (exists $farms->{http}->{$csv[0]})
{
if ($csv[1] eq 'FRONTEND' or $csv[1] eq 'BACKEND')
{
$farms->{http}->{$csv[0]} = \@csv;
}
}
# Socket stats
if (exists $farms->{socket}->{$csv[0]})
{
if ($csv[1] eq 'FRONTEND' or $csv[1] eq 'BACKEND')
{
$farms->{socket}->{$csv[0]}->{total} = \@csv;
}
else
{
$farms->{socket}->{$csv[0]}->{$csv[1]} = \@csv;
}
}
}
# HTTP stats
for my $farmName (keys %{$farms->{http}})
{
my @csv = @{$farms->{http}->{$farmName}};
print "haproxy requests on $farmName: $csv[39]:$csv[40]:$csv[41]:$csv[42]:$csv[43]:$csv[44]\n";
my $filename = "$this->{_rrd}/system-haproxy-http-$farmName.rrd";
if (! -e $filename)
{
print "creating rrd database for haproxy $farmName HTTP farm...\n";
system "$this->{_rrdtool} create \"$filename\" \\
-s 300 \\
DS:1XX:DERIVE:600:0:U \\
DS:2XX:DERIVE:600:0:U \\
DS:3XX:DERIVE:600:0:U \\
DS:4XX:DERIVE:600:0:U \\
DS:5XX:DERIVE:600:0:U \\
DS:other:DERIVE:600:0:U \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t 1XX:2XX:3XX:4XX:5XX:other N:$csv[39]:$csv[40]:$csv[41]:$csv[42]:$csv[43]:$csv[44]";
}
# Socket stats
for my $farmName (keys %{$farms->{socket}})
{
my $stats = $farms->{socket}->{$farmName};
my @keys = ();
my @vals = ();
for my $socket (keys %{$stats})
{
push @keys, "${socket}_in";
push @vals, $stats->{$socket}[8];
push @keys, "${socket}_out";
push @vals, $stats->{$socket}[9];
}
print "haproxy sock stats on $farmName: " . join(':', @keys) . "/" . join(':', @vals) . "\n";
my $filename = "$this->{_rrd}/system-haproxy-socket-$farmName.rrd";
if (! -e $filename)
{
print "creating rrd database for haproxy $farmName Socket farm...\n";
my $create = "$this->{_rrdtool} create \"$filename\" \\
-s 300 ";
for my $socket (@keys)
{
$create .= "DS:$socket:DERIVE:600:0:U ";
}
$create .= "RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
system $create;
}
system "$this->{_rrdtool} update \"$filename\" -t " . join(':', @keys) . " N:" . join(':', @vals);
}
$this->haproxyGraphHttp('day', $farms->{http});
$this->haproxyGraphHttp('week', $farms->{http});
$this->haproxyGraphHttp('month', $farms->{http});
$this->haproxyGraphHttp('year', $farms->{http});
$this->haproxyGraphSocket('day', $farms->{socket});
$this->haproxyGraphSocket('week', $farms->{socket});
$this->haproxyGraphSocket('month', $farms->{socket});
$this->haproxyGraphSocket('year', $farms->{socket});
}
sub haproxyGraphHttp
{
my $this = shift;
my $type = shift;
my $farms = shift;
for my $farmName (keys %$farms)
{
my $rrd_filename = "$this->{_rrd}/system-haproxy-http-$farmName.rrd";
my $graph_filename = "$this->{_img}/system-haproxy-http-$farmName-$type.png";
system "$this->{_rrdtool} graph \"$graph_filename\" \\
--lazy \\
--tabwidth 20 \\
-s -1$type \\
-t \"Haproxy HTTP stats - $farmName\" \\
-h 250 -w 1100 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"reqs/s\" \\
DEF:1XX=$rrd_filename:1XX:AVERAGE \\
DEF:2XX=$rrd_filename:2XX:AVERAGE \\
DEF:3XX=$rrd_filename:3XX:AVERAGE \\
DEF:4XX=$rrd_filename:4XX:AVERAGE \\
DEF:5XX=$rrd_filename:5XX:AVERAGE \\
DEF:other=$rrd_filename:other:AVERAGE \\
VDEF:1XXmax=1XX,MAXIMUM \\
VDEF:1XXavg=1XX,AVERAGE \\
VDEF:1XXlast=1XX,LAST \\
VDEF:2XXmax=2XX,MAXIMUM \\
VDEF:2XXavg=2XX,AVERAGE \\
VDEF:2XXlast=2XX,LAST \\
VDEF:3XXmax=3XX,MAXIMUM \\
VDEF:3XXavg=3XX,AVERAGE \\
VDEF:3XXlast=3XX,LAST \\
VDEF:4XXmax=4XX,MAXIMUM \\
VDEF:4XXavg=4XX,AVERAGE \\
VDEF:4XXlast=4XX,LAST \\
VDEF:5XXmax=5XX,MAXIMUM \\
VDEF:5XXavg=5XX,AVERAGE \\
VDEF:5XXlast=5XX,LAST \\
VDEF:othermax=other,MAXIMUM \\
VDEF:otheravg=other,AVERAGE \\
VDEF:otherlast=other,LAST \\
CDEF:total=1XX,2XX,3XX,4XX,5XX,other,+,+,+,+,+ \\
VDEF:totalmax=total,MAXIMUM \\
VDEF:totalavg=total,AVERAGE \\
VDEF:totallast=total,LAST \\
AREA:total#CDCDCD:\"Total\t\" \\
GPRINT:totalmax:\"Max\\: %4.2lf\" \\
GPRINT:totalavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:totallast:\"\tCurrent\\: %4.2lf reqs/s\\n\" \\
AREA:1XX#3D617C:\"1XX\t\t\" \\
GPRINT:1XXmax:\"Max\\: %4.2lf\" \\
GPRINT:1XXavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:1XXlast:\"\tCurrent\\: %4.2lf reqs/s\\n\" \\
AREA:2XX#68A5D3:\"2XX\t\t\":STACK \\
GPRINT:2XXmax:\"Max\\: %4.2lf\" \\
GPRINT:2XXavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:2XXlast:\"\tCurrent\\: %4.2lf reqs/s\\n\" \\
AREA:3XX#A0E59C:\"3XX\t\t\":STACK \\
GPRINT:3XXmax:\"Max\\: %4.2lf\" \\
GPRINT:3XXavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:3XXlast:\"\tCurrent\\: %4.2lf reqs/s\\n\" \\
AREA:4XX#3B743F:\"4XX\t\t\":STACK \\
GPRINT:4XXmax:\"Max\\: %4.2lf\" \\
GPRINT:4XXavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:4XXlast:\"\tCurrent\\: %4.2lf reqs/s\\n\" \\
AREA:5XX#913F3F:\"5XX\t\t\":STACK \\
GPRINT:5XXmax:\"Max\\: %4.2lf\" \\
GPRINT:5XXavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:5XXlast:\"\tCurrent\\: %4.2lf reqs/s\\n\" \\
AREA:other#E3D85D:\"other\t\":STACK \\
GPRINT:othermax:\"Max\\: %4.2lf\" \\
GPRINT:otheravg:\"\tAvg\\: %4.2lf\" \\
GPRINT:otherlast:\"\tCurrent\\: %4.2lf reqs/s\\n\" \\
2>&1 > /dev/null";
}
}
sub haproxyGraphSocket
{
my $this = shift;
my $type = shift;
my $farms = shift;
my @colors = ("#68A5D3", "#A0E59C", "#E36363", "#E3D85D", "#3D617C", "#3B743F", "#913F3F");
for my $farmName (keys %$farms)
{
my $rrd_filename = "$this->{_rrd}/system-haproxy-socket-$farmName.rrd";
my $graph_filename = "$this->{_img}/system-haproxy-socket-$farmName-$type.png";
my @keys = ();
for my $socket (sort keys %{$farms->{$farmName}})
{
push @keys, "${socket}_in";
push @keys, "${socket}_out";
}
my $colorId = 0;
my $idIn = 0;
my $idOut = 0;
my @defs = ();
my @graphsIn = ();
my @graphsOut = ();
for my $key (@keys)
{
# data
my $graphDataKey = $key;
my $stack = "";
my $def = "DEF:${key}=${rrd_filename}:${key}:AVERAGE \\
VDEF:${key}max=${key},MAXIMUM \\
VDEF:${key}avg=${key},AVERAGE \\
VDEF:${key}last=${key},LAST ";
if ($key =~ m/_in$/)
{
$graphDataKey = "${key}_neg";
$def .= "CDEF:${graphDataKey}=${key},-1,* ";
}
push @defs, $def;
next if $key =~ m/^total_(in|out)$/;
# graphs items
if ($key =~ m/_in$/)
{
$stack = ":STACK" if $idIn++ > 0;
push @graphsIn, "AREA:${graphDataKey}$colors[$colorId]:\"${key}\t\t\"${stack} \\
GPRINT:${key}max:\"Max\\: %8.2lf %s\" \\
GPRINT:${key}avg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:${key}last:\"\tCurrent\\: %8.2lf %So/s\\n\" ";
}
else
{
$stack = ":STACK" if $idOut++ > 0;
push @graphsOut, "AREA:${graphDataKey}$colors[$colorId]:\"${key}\t\t\"${stack} \\
GPRINT:${key}max:\"Max\\: %8.2lf %s\" \\
GPRINT:${key}avg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:${key}last:\"\tCurrent\\: %8.2lf %So/s\\n\" ";
}
$colorId = ($colorId + 1) % scalar @colors if $key =~ m/_out$/;
}
system "$this->{_rrdtool} graph \"$graph_filename\" \\
--lazy \\
--tabwidth 20 \\
-s -1$type \\
-t \"Haproxy socket stats - $farmName\" \\
-h 250 -w 1100 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"o/s\" \\
" . join(' ', @defs) . " \\
AREA:total_out#CDCDCD:\"Total_out\t\" \\
GPRINT:total_outmax:\"Max\\: %8.2lf %s\" \\
GPRINT:total_outavg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:total_outlast:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
" . join(' ', @graphsOut) . " \\
AREA:total_in_neg#CDCDCD:\"Total_in\t\t\" \\
GPRINT:total_inmax:\"Max\\: %8.2lf %s\" \\
GPRINT:total_inavg:\"\tAvg\\: %8.2lf %S\" \\
GPRINT:total_inlast:\"\tCurrent\\: %8.2lf %So/s\\n\" \\
" . join(' ', @graphsIn) . " \\
HRULE:0#202020 \\
2>&1 > /dev/null";
}
}
sub battery
{
my $this = shift;
my $bat = shift;
open FH, "</sys/class/power_supply/$bat/charge_full_design";
my $full = <FH>;
close FH;
open FH, "</sys/class/power_supply/$bat/charge_now";
my $now = <FH>;
close FH;
chomp $full;
chomp $now;
my $level = ($now * 100) / $full;
print "Niveau batterie $bat: $level\n";
my $filename = "$this->{_rrd}/system-battery-$bat.rrd";
if (! -e $filename)
{
print "creating rrd database for system battery...\n";
system "$this->{_rrdtool} create \"$filename\" \\
-s 300 \\
DS:bat:GAUGE:600:0:100 \\
RRA:AVERAGE:0.5:1:576 \\
RRA:AVERAGE:0.5:6:672 \\
RRA:AVERAGE:0.5:24:732 \\
RRA:AVERAGE:0.5:144:1460 \\
2>&1 > /dev/null";
}
system "$this->{_rrdtool} update \"$filename\" -t bat N:$level";
$this->batteryGraph('day', $bat);
$this->batteryGraph('week', $bat);
$this->batteryGraph('month', $bat);
$this->batteryGraph('year', $bat);
}
sub batteryGraph
{
my $this = shift;
my $type = shift;
my $bat = shift;
my $rrd_filename = "$this->{_rrd}/system-battery-$bat.rrd";
my $graph_filename = "$this->{_img}/system-battery-$bat-$type.png";
system "$this->{_rrdtool} graph \"$graph_filename\" \\
--lazy \\
--tabwidth 20 \\
-s -1$type \\
-t \"Niveau Batterie - $bat\" \\
-h 250 -w 1100 \\
--border 0 \\
-a PNG \\
-E \\
-n DEFAULT:0:monospace \\
-n TITLE:11 \\
-n AXIS:10 \\
-n LEGEND:10 \\
-n UNIT:10 \\
-v \"%\" \\
-u 100 \\
-l 0 \\
-r \\
DEF:bat=$rrd_filename:bat:AVERAGE \\
VDEF:batmax=bat,MAXIMUM \\
VDEF:batavg=bat,AVERAGE \\
VDEF:batlast=bat,LAST \\
LINE1.5:bat#3D617C:\"Batterie\t\" \\
GPRINT:batmax:\"Max\\: %4.2lf\" \\
GPRINT:batavg:\"\tAvg\\: %4.2lf\" \\
GPRINT:batlast:\"\tCurrent\\: %4.2lf %%\\n\" \\
2>&1 > /dev/null";
}
1;