Ping-Statistik mitGnuPlot

Darstellung
ping stat image

Für Netzwerkanalyse in Echtzeit ist ping gut geeignet, besser noch mrt. Wenn es aber darum geht Schwankungen in der Übertragung zu dokumentieren wird das mit diesen Tools schwierig. Dieses Skript kann die Pings zu einem Host über längere Zeiträume machen. Das Ergebnis wird grafisch aufbereitet und in PDF Format dokumentiert. Wie in diesem Beispiel, wo das zeitweise Aussetzen der Netzwerkschnittstelle eines OKI-Druckers dokumentiert wird, das nur sporadisch auftritt, aber auf einen Defekt hinweist.

Dieser Skript erfordert GhostScript, Gnuplot lokal installiert. Der eigentliche Ping kann auch über eine SSH Verbindung von einem anderen Host aus geschehen, dort wird lediglich ping und ein ssh-server benötigt. Empfohlen ist natürlich eine eingerichtete Hostkey-Authentifizierung. Der Host könnte auch ein BSD oder OSX sein, das sollte prinzipiell auch gehen. Für Linux sollte man iputils-ping installiert haben, andere Varianten funktionieren wahrscheinlich nicht, weil die Ausgaben von ping andere Formatierung haben.

Im Ergebnis sieht man sogar das nichtmonotone Eintreffen der ICMP Antworten, da die Verbindungslinien der Punkte chronologisch sind, die Punke aber in der Reihenfolge der ICMP Anfragen sind. Paketverluste sind auffällig durch jeweils eine senkrechte Linie zu sehen. Das ist schon bedeutend aussagekräftiger als nur eine Zusammenfassung wie bei ping, wo man zwar sieht dass es Paketverluste gibt, aber nicht wo genau.

Auf einer zweiten Seite werden die Ergebnisse in einem Histogramm zusammengefasst, und auf einer dritten Seite sind statistische Parameter gelistet.

pingstat.sh:

download

#!/bin/bash
#   Ping-Statistik mit geringem Aufwand (Vergleich zu smokeping)
#  erfordert GhostScript, Gnuplot
#
usage() {
    echo "usage: pingstat.sh [source hostname/ip] [target hostname/ip] [number of pings] [time interval between pings] [psize]"
    echo "   default:                 -                    -                  100                       0.1               56"
    echo " you need rights to execute sudo on ping and if your source is a remote host you need ssh to it."
    exit 0
}
if [ "$1" = "-h" ]
then usage
fi

if [ -n "$1" ]
then QUELLHOST=$1
    if [ "$QUELLHOST" != "$(hostname)" ]
    then REMOTEHOST=$QUELLHOST
	 echo "run from remote host: $REMOTEHOST"
    fi
else usage
fi
if [ -n "$2" ]
then ZIEL=$2
else usage
fi
if [ -n "$3" ]
then ANZAHL=$3
else ANZAHL=100
fi
if [ -n "$4" ]
then INTV=$4
else INTV=0.1
fi
if [ -n "$5" ]
then PSIZE=$5
else PSIZE=56
fi
#

DAUER=$(echo "$INTV * $ANZAHL" | bc)
echo "Testdauer: $DAUER s"
PDFDATUM=$(date +%Y%m%d%H%M%S:%z)
DATUM=$(date +%Y%m%d%H%M%S)
CREDATUM=$PDFDATUM
TITLE="Pingtest $QUELLHOST - $ZIEL"
USERNAME=$(getent passwd "$USER"|cut -d':' -f5|cut -d',' -f1)   # Benutzername ermitteln
FNAME=ping+${QUELLHOST}+X$ZIEL-$DATUM
PDFMETADATA=$FNAME.pdfmeta
PINGAUSGABE=$FNAME.ping
PDFDATEI=$FNAME.pdf
STATDATEI=$FNAME.stats
CSV1=$FNAME.csv
CSV2=$FNAME-missing.csv
TMPPDF1=$FNAME-temp1.pdf
TMPPDF2=$FNAME-temp2.pdf
TMPPDF3=$FNAME-temp3.pdf
GnuPlotFile=$FNAME.p
#------------------------------------------
CreateMetaDataFile() {
#   Jetzt Datei mit Metadaten vorbereiten
cat > "$1" < "$1" <"$2"
    else sudo ping -n -s "$PSIZE" -i "$INTV" -c "$ANZAHL" "$ZIEL" >"$2"
    fi
}
get_missing()  {
YYY=0
grep "time=" "$1"|awk '{print $5}'|cut -d'=' -f2|sort -n|while read -r XXX
do
#	echo $XXX : $YYY
	YYY=$((YYY+1))
	while [ $YYY -lt "$XXX" ]
	do
		echo "$YYY"
		YYY=$((YYY+1))
	done
done
}
#
echo "Pingtest von $QUELLHOST auf $ZIEL mit $PSIZE × $ANZAHL pings im Intervall $INTV"
run_test  "$ZIEL"   "$PINGAUSGABE"
RESULT=$(grep received "$PINGAUSGABE")
#
awk '{printf "%s,%s\n",$5,$7}' "$PINGAUSGABE" |sed -e "s/time=//g" -e "s/icmp_[sr]eq=//g" |head -n -4|tail -n +2 >"$CSV1"
get_missing "$PINGAUSGABE" >"$CSV2"
MISS=$(awk '{x++}END{ print x}' "$CSV2")
CreateMetaDataFile "$PDFMETADATA"
CreateGnuplotFile "$GnuPlotFile"
cat /usr/lib/pingstat/pingstat.p >> "$GnuPlotFile"
#
#gnuplot -e "includefile='$GnuPlotFile'" pingstat.p 2>$STATDATEI || exit 1
gnuplot "$GnuPlotFile" 2>"$STATDATEI" || exit 1
txt2pdf.py --landscape 1 --output "$TMPPDF3" "$STATDATEI"
# Nachbearbeting der PDF Dateien
gs -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile="$PDFDATEI" "$TMPPDF1" "$TMPPDF2" "$TMPPDF3" "$PDFMETADATA"
# Aufräumen
rm "$TMPPDF1" "$TMPPDF2" "$TMPPDF3" "$PDFMETADATA" #"$PINGAUSGABE" #"$STATDATEI"  #temp.inc

Dazu gehört die Datei, die GnuPlot verwendet. pingstat.p:

download

# Definiere die Breite der Bins (“bin width”, ∆x)
# und eine sog. “binning”-Funktion:
hist(x,s)=s*ceil(x/s) - 0.5*s

# Die Funktion ceil(x) rundet den Wert von x ab
# Die Anzahl der Datenpunkte (für die Normierung)
set datafile separator ","
stats datei1 ; N = STATS_records
set output ausgabe1
plot datei1  using 1:2
ymax = GPVAL_DATA_Y_MAX
ymin = GPVAL_DATA_Y_MIN
bw = (10.0 ** floor(log10(ymax))) /10.0

#set terminal pdf size 11.6929,8.267
set terminal pdf size 29.7cm,21cm
set output ausgabe1
#set decimalsign locale "de_DE.UTF-8"
set size 0.95,0.95
set origin 0.03,0.03
set grid #linestyle 30, linestyle 31
set grid xtics mxtics ytics mytics

set title title1
#"Pingzeit Verlauf"
set xlabel "seq."
set ylabel "Zeit in ms"
#set yrange [*<0:*]
set logscale y
set mytics
if ( miss >0 ) {
plot datei1  using 1:2 with linespoints lc rgb "blue" pt 7 ps 0.3 title "rtt", \
     datei2  using 1:(ymax * 0.95) with impulses lc rgb "red" title "loss"
} else {
plot datei1  using 1:2 with linespoints lc rgb "blue" pt 7 ps 0.3 title "rtt"
}
# mit logscale y muss man die max und min Werte entsprechend korrigieren
print "   Breite ", bw, " ms ", ymax
set boxwidth bw
print title1
print datum

set output ausgabe2
set title title2
#"Pingzeit Histogramm"
set xlabel "Pingzeit in ms"
set ylabel "Relative Häufigkeit in %"
#set logscale y
unset logscale y
set xrange [0:]
set yrange [0:*]
#set ytics default
unset mytics
# Das Histogramm wird erzeugt und dargestellt durch:
plot datei1 u (hist($2,bw)):(1./N*100.0) smooth frequency with boxes lc rgb "blue" title "success"
# Dabei werden die Daten in Bins aufgeteilt (“gebinnt”) und durch die
# Direktive smooth frequency die Treffer eines jeden Bins aufsummiert;
# das Ergebnis wird als Funktion des Bins aufgetragen, und zwar mit
# Balken (“boxes”).