Pings
This ain't no smokeping. It works though and isn't very complex. The core script is called by Cron every 5 minutes. It cycles through a targets file sending out 20 ICMP echo requests to each target and dumping the results into an RRD. It then calls a second script that generates these graphs:
To monitor a new host, you just add it to the targets file and call pings.sh with "create" as its first argument. After this, the next time the main program is called from Cron, it will begin collecting stats.
The core is pings.sh:
#!/usr/local/bin/bash
# Cron entry:
# */5 * * * * /home/flow/Code/Pings/pings.sh run > /dev/null 2>&1
export PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin"
args=$@
baseDir="/home/flow/Code/Pings"
targets=`cat ${baseDir}/targets.txt | sed '/#/d'`
rrd_dir="${baseDir}/RRDs"
dses="
ploss
pmin
pavg
pmax
pstddev
"
## Timestamp for RRD
step=300
now=`date +"%s"`
unixTime=`awk "BEGIN {print ($step * int(($now / $step) + 0.5))}"`
if [ ! $args ]; then
echo "Usage: ping_times.sh <create>|<run>"
## Create RRD's
elif [ $args = "create" ]; then
for x in $targets; do
name=`echo $x | awk -F "," '{print $2}'`
for y in $dses; do
if [ ! -e $rrd_dir/pings_${name}_${y}.rrd ]; then
echo "Creating $rrd_dir/pings_${name}_${y}.rrd"
rrdtool create $rrd_dir/pings_${name}_${y}.rrd --step 300 --start `date -v0H -v0M -v0S "+%s"` \
DS:${y}:GAUGE:400:U:U \ RRA:MAX:0.5:1:105120
fi
done
done
## Establish ping stats
elif [ $args = "run" ]; then
for x in $targets; do
go="no"
ip=`echo $x | awk -F "," '{print $1}'`
name=`echo $x | awk -F "," '{print $2}'`
loss=U; min=U; avg=U; max=U; stddev=U
base=`ping -n -W 6 -c 20 -q $ip | tail -n 2`
if [ ${base:0:1} = "-" ]; then
loss=`echo "$base" | sed 1d | awk -F "," '{print $3}' | awk '{print $1}' | tr -d "%"`
go="yes"
else
stats=`echo "$base" | sed 1d | awk -F "=" '{print $2}'`
loss=`echo "$base" | sed 2d | awk -F "," '{print $3}' | awk '{print $1}' | tr -d "%"`
min=`echo "$stats" | awk -F "/" '{print $1}' | tr -d " "`
avg=`echo "$stats" | awk -F "/" '{print $2}'`
max=`echo "$stats" | awk -F "/" '{print $3}'`
stddev=`echo "$stats" | awk -F "/" '{print $4}' | tr -d "ms"`
go="yes"
fi
# Update RRD's
if [ $go = "yes" ]; then
rrdtool update ${rrd_dir}/pings_${name}_ploss.rrd $unixTime:$loss
rrdtool update ${rrd_dir}/pings_${name}_pmin.rrd $unixTime:$min
rrdtool update ${rrd_dir}/pings_${name}_pavg.rrd $unixTime:$avg
rrdtool update ${rrd_dir}/pings_${name}_pmax.rrd $unixTime:$max
rrdtool update ${rrd_dir}/pings_${name}_pstddev.rrd $unixTime:$stddev
fi
# Update Graphs
$baseDir/gr_pings.sh 800 50 $name
done
else
echo "Invalid args!"
fi
Once this completes, it fires this piece which generates the graphs:
#!/usr/local/bin/bash
args=("$@")
if [ "$#" -ne 3 ]; then
echo "Usage: <width> <height> <RRD prefix>"
echo "Example: ${0}.sh 800 150 blah"
else
# Set some dirs
rrd_dir="/home/flow/RRDs/Pings"
img_dest="/usr/local/www/graphs/pings"
# Colours
background="#ffffff"
# Size
width=${args[0]}
height=${args[1]}
# Data
rrd=${args[2]}
outfile=${args[2]}
echo "$height $width $rrd $outfile"
# Find out what day it is
ymd=`date "+%Y-%m-%d"`
# Today at midnight
mark00=`date -v0H -v0M -v0S "+%s"`
# Timestamp
stamp=`date | sed 's/:/\\:/g' | sed 's/ /\\,,/g'`
sign="%"
reps=".--end=23:59.$ymd.--x-grid=MINUTE:30:HOUR:1:HOUR:2:0:%R.$stamp \
.--end=now.${ymd}_24..24Hrs. \
--start=end-3h.--end=now.3..3Hrs. \
--start=end-1w.--end=now.w.--x-grid=DAY:1:DAY:1:DAY:1:0:%b%d.weekly \
--start=end-1m.--end=now.m.--x-grid=DAY:1:WEEK:1:WEEK:1:0:%b%d.monthly \
--start=end-1y.--end=now.y..yearly"
y=0;
for x in $reps; do
start=`echo $x | awk -F . '{print $1}'`
end=`echo $x | awk -F . '{print $2}'`
char=`echo $x | awk -F . '{print $3}'`
axis=`echo $x | awk -F . '{print $4}'`
title=`echo $x | awk -F . '{print $5}' | sed 's/,,/ /g'`
rrdtool graph $img_dest/pings_${outfile}_${char}.png \
$start \
$end \
--width=$width \
--height=$height \
--vertical-label="ms" \
--imgformat=PNG \
--interlace \
--c=CANVAS$background \
--watermark "$title" \
$axis \
DEF:ploss=$rrd_dir/pings_${rrd}_ploss.rrd:ploss:MAX \
DEF:pmin=$rrd_dir/pings_${rrd}_pmin.rrd:pmin:MAX \
DEF:pavg=$rrd_dir/pings_${rrd}_pavg.rrd:pavg:MAX \
DEF:pmax=$rrd_dir/pings_${rrd}_pmax.rrd:pmax:MAX \
DEF:pstddev=$rrd_dir/pings_${rrd}_pstddev.rrd:pstddev:MAX \
CDEF:fmax=pmax,pavg,- \
COMMENT:"$rrd\l" \
\
LINE1:pavg \
\
AREA:fmax#b1bdcd::STACK \
\
LINE1:pmin#b1bdcd \
\
LINE3:pavg#003366:"median rtt\t\t" \
GPRINT:pavg:AVERAGE:"%5.2lf ms avg " \
GPRINT:pavg:MIN:"%5.2lf ms min " \
GPRINT:pavg:MAX:"%5.2lf ms max " \
GPRINT:pavg:LAST:"%5.2lf ms now\l" \
\
LINE1:pstddev#000000:"deviation\t\t\t" \
GPRINT:pstddev:AVERAGE:"%5.2lf ms avg " \
GPRINT:pstddev:MIN:"%5.2lf ms min " \
GPRINT:pstddev:MAX:"%5.2lf ms max " \
GPRINT:pstddev:LAST:"%5.2lf ms now\l" \
\
AREA:ploss#FF5B00:"packet loss\t\t" \
GPRINT:ploss:AVERAGE:"%5.2lf %% avg " \
GPRINT:ploss:MIN:"%5.2lf %% min " \
GPRINT:ploss:MAX:"%5.2lf %% max " \
GPRINT:ploss:LAST:"%5.2lf %% now\l" \
VRULE:$mark00#a50000
let y=y+1;
done;
fi;