Skip to content

Instantly share code, notes, and snippets.

@mjf
Last active January 20, 2021 09:41
Show Gist options
  • Save mjf/4a3302ba84120c709c37d24a97b8e48e to your computer and use it in GitHub Desktop.
Save mjf/4a3302ba84120c709c37d24a97b8e48e to your computer and use it in GitHub Desktop.
pingfmt - Format output of the ping(1) program
#! /usr/bin/awk --exec
# pingfmt - Format output of the ping(1) program
# Copyright (C) 2012, 2021 Matouš J. Fialka, <https://mjf.cz/>
# Released under the terms of The MIT License
BEGIN {
# ----- HELP SCREEN -----
help = help "Usage: pingfmt [-h|-help|-usage] [+[no][show]<opt>[=<val>]]\n"
help = help "\n"
help = help "Options:\n"
help = help "\n"
help = help " -h|-help|-usage Print this help screen\n"
help = help "\n"
help = help " +[no]highlight Highlight excessive values\n"
help = help "\n"
help = help " +label=<txt> Set hostname or IP\n"
help = help "\n"
help = help " +maxavgpktloss=<val> Set maximal average packetloss\n"
help = help " +maxavgrtt=<val> Set maximal average RTT\n"
help = help " +maxpktloss=<val> Set maximal packetloss\n"
help = help " +maxreq=<val> Set maximal request\n"
help = help " +maxrtt=<val> Set maximal RTT\n"
help = help " +maxtime=<sec> Set maximal time in seconds\n"
help = help "\n"
help = help " +[no]resolve Resolve hostname\n"
help = help "\n"
help = help " +[no]scroll Scroll output\n"
help = help " +scrollreq=<num> Scroll output every <num> requests\n"
help = help "\n"
help = help " +[no]utc Time in UTC\n"
help = help "\n"
help = help " +[no]showall [Don't] show all values\n"
help = help " +[no]showavg [Don't] show average values\n"
help = help " +[no]showavgpktloss [Don't] show average packetloss values\n"
help = help " +[no]showavgrtt [Don't] show average RTT values\n"
help = help " +[no]showcur [Don't] show current values\n"
help = help " +[no]showcurpktloss [Don't] show current packetloss values\n"
help = help " +[no]showcurrtt [Don't] show current RTT values\n"
help = help " +[no]showlabel [Don't] show label values\n"
help = help " +[no]showmax [Don't] show maximal values\n"
help = help " +[no]showmaxpktloss [Don't] show maximal packetloss values\n"
help = help " +[no]showmaxrtt [Don't] show maximal RTT values\n"
help = help " +[no]showmin [Don't] show minimal values\n"
help = help " +[no]showminpktloss [Don't] show minimal packetloss values\n"
help = help " +[no]showminrtt [Don't] show minimal RTT values\n"
help = help " +[no]showpktloss [Don't] show packetloss values\n"
help = help " +[no]showreq [Don't] show request values\n"
help = help " +[no]showrtt [Don't] show RTT\n"
help = help " +[no]showtime [Don't] show time (use "ping -D")\n"
help = help " +[no]showunits [Don't] show units\n"
help = help "\n"
help = help "Environment:\n"
help = help "\n"
help = help " PINGFMT_LABEL Use as host\n"
help = help "\n"
help = help " PINGFMT_MAXAVGPKTLOSS Use as maximal average packetloss\n"
help = help " PINGFMT_MAXAVGRTT Use as maximal average RTT\n"
help = help " PINGFMT_MAXCURPKTLOSS Use as maximal packetloss\n"
help = help " PINGFMT_MAXREQ Use as maximal request\n"
help = help " PINGFMT_MAXCURRTT Use as maximal RTT\n"
help = help "\n"
help = help "Exit codes:\n"
help = help "\n"
help = help " No errors occured 0\n"
help = help " Invalid option 1\n"
help = help " Maximal time reached 126 (see +maxtime)\n"
help = help " Maximal request reached 127 (see +maxreq)\n"
# ----- DEFAULTS -----
ret = 0
helped = 0
opthighlight = 1
optlabel = NULL
optmaxavgpktloss = 0.9
optmaxavgrtt = 9.5
optmaxcurpktloss = 3.0
optmaxcurrtt = 20.0
optmaxreq = 0
optmaxtime = 0
optresolve = 1
optscroll = 1
optscrollreq = 10
optshowall = 0
optshowavg = NULL
optshowavgpktloss = 0
optshowavgrtt = 1
optshowcur = NULL
optshowcurpktloss = 0
optshowcurrtt = 1
optshowlabel = 0
optshowmax = NULL
optshowmaxpktloss = 0
optshowmaxrtt = 1
optshowmin = NULL
optshowminpktloss = 0
optshowminrtt = 1
optshowpktloss = NULL
optshowreq = 1
optshowrtt = NULL
optshowtime = 0
optshowunits = 1
optutc = 1
# ----- ENVIRONMENT -----
if(ENVIRON["PINGFMT_LABEL"])
optlabel = ENVIRON["PINGFMT_LABEL"]
if(ENVIRON["PINGFMT_MAXAVGPKTLOSS"])
optmaxavgpktloss = ENVIRON["PINGFMT_MAXAVGPKTLOSS"]
if(ENVIRON["PINGFMT_MAXAVGRTT"])
optmaxavgrtt = ENVIRON["PINGFMT_MAXAVGRTT"]
if(ENVIRON["PINGFMT_MAXCURPKTLOSS"])
optmaxcurpktloss = ENVIRON["PINGFMT_MAXCURPKTLOSS"]
if(ENVIRON["PINGFMT_MAXREQ"])
optmaxreq = ENVIRON["PINGFMT_MAXREQ"]
if(ENVIRON["PINGFMT_MAXCURRTT"])
optmaxcurrtt = ENVIRON["PINGFMT_MAXCURRTT"]
# ----- ARGUMENTS -----
for(arg = 1; arg < ARGC; arg++) {
opt = ARGV[arg]
if(opt ~ /^-(h(elp)?|usage)$/) {
printf "%s", help
helped = 1
exit ret = 0
}
if(opt ~ /^\+(no)?highlight$/) {
opthighlight = opt !~ /^\+no/
continue
}
if(opt ~ /^\+label?=./) {
optlabel = temp[split(opt, temp, /=/)]
delete temp
continue
}
if(opt ~ /^\+(no)?showall$/) {
optshowall = opt !~ /^\+no/
optshowavgpktloss = optshowall
optshowavgrtt = optshowall
optshowcurpktloss = optshowall
optshowcurrtt = optshowall
optshowlabel = optshowall
optshowmaxpktloss = optshowall
optshowmaxrtt = optshowall
optshowminpktloss = optshowall
optshowminrtt = optshowall
optshowreq = optshowall
optshowtime = optshowall
optshowunits = optshowall
continue
}
if(opt ~ /^\+(no)?showavg$/) {
optshowavgpktloss = opt !~ /^\+no/
optshowavgrtt = optshowavgpktloss
continue
}
if(opt ~ /^\+(no)?showavgpktloss$/) {
optshowavgpktloss = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?showavgrtt$/) {
optshowavgrtt = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?showcur$/) {
optshowcurpktloss = opt !~ /^\+no/
optshowcurrtt = optshowcurpktloss
continue
}
if(opt ~ /^\+(no)?showcurpktloss$/) {
optshowcurpktloss = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?showcurrtt$/) {
optshowcurrtt = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?showlabel$/) {
optshowlabel = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?showmax$/) {
optshowmaxpktloss = opt !~ /^no/
optshowmaxrtt = optshowmaxpktloss
continue
}
if(opt ~ /^\+(no)?showmaxpktloss$/) {
optshowmaxpktloss = opt !~ /^no/
continue
}
if(opt ~ /^\+(no)?showmaxrtt$/) {
optshowmaxrtt = opt !~ /^no/
continue
}
if(opt ~ /^\+maxreq=[0-9]+$/) {
optmaxreq = temp[split(opt, temp, /=/)]
delete temp
continue
}
if(opt ~ /^\+maxrtt=[0-9]+(\.[0-9]+)?$/) {
optmaxcurrtt = temp[split(opt, temp, /=/)]
delete temp
continue
}
if(opt ~ /^\+maxavgrtt=[0-9]+(\.[0-9]+)?$/) {
optmaxavgrtt = temp[split(opt, temp, /=/)]
delete temp
continue
}
if(opt ~ /^\+maxpktloss=([1-9][0-9]?|100)(\.[0-9]+)?$/) {
optmaxavgrtt = temp[split(opt, temp, /=/)]
delete temp
continue
}
if(opt ~ /^\+maxavgpktloss=([1-9][0-9]?|100)(\.[0-9]+)?$/) {
optmaxavgpktloss = temp[split(opt, temp, /=/)]
delete temp
continue
}
if(opt ~ /^\+maxtime=[0-9]+(\.[0-9]+)?$/) {
optmaxtime = temp[split(opt, temp, /=/)]
delete temp
continue
}
if(opt ~ /^\+(no)?showmin$/) {
optshowminpktloss = opt !~ /^\+no/
optshowminrtt = optshowminpktloss
min = NULL
continue
}
if(opt ~ /^\+(no)?showminpktloss$/) {
optshowminpktloss = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?showminrtt$/) {
optshowminrtt = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?showpktloss$/) {
optshowcurpktloss = opt !~ /^\+no/
optshowminpktloss = optshowcurpktloss
optshowavgpktloss = optshowcurpktloss
optshowmaxpktloss = optshowcurpktloss
continue
}
if(opt ~ /^\+(no)?showreq$/) {
optshowreq = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?showrtt$/) {
optshowcurrtt = opt !~ /^\+no/
optshowminrtt = optshowcurrtt
optshowavgrtt = optshowcurrtt
optshowmaxrtt = optshowcurrtt
continue
}
if(opt ~ /^\+(no)?resolve$/) {
optresolve = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?scroll$/) {
optscroll = opt !~ /^\+no/
continue
}
if(opt ~ /^\+scrollreq=[1-9][0-9]*$/) {
optscrollreq = temp[split(opt, temp, /=/)]
delete temp
continue
}
if(opt ~ /^\+(no)?showunits$/) {
optshowunits = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?utc$/) {
optutc = opt !~ /^\+no/
continue
}
if(opt ~ /^\+(no)?showtime$/) {
optshowtime = opt !~ /^\+no/
continue
}
printf("Unknown option %s\n", opt) > "/dev/stderr"
exit ret = 1
}
for(arg in ARGV)
delete ARGV[arg]
delete ARGV
# ----- OPTIONS -----
optshowpktloss = \
optshowcurpktloss ||
optshowminpktloss ||
optshowavgpktloss ||
optshowmaxpktloss
optshowrtt = \
optshowcurrtt ||
optshowminrtt ||
optshowavgrtt ||
optshowmaxrtt
optshowcur = optshowcurpktloss && optshowcurrtt
optshowmin = optshowminpktloss && optshowminrtt
optshowavg = optshowavgpktloss && optshowavgrtt
optshowmax = optshowmaxpktloss && optshowmaxrtt
# ----- VARIABLES -----
hostname = NULL
ip = NULL
pktlosscur = 0.0
pktlossavg = 0.0
pktlosssum = 0.0
pktlossreq = 0.0
pktlossmin = 0.0
pktlossmax = 0.0
reqcur = 0.0
rttcur = 0.0
rttavg = 0.0
rttsum = 0.0
rttreq = 0.0
rttmax = 0.0
rttmin = 0.0
stm = systime()
dtm = 0.0
scrreq = optscrollreq
scrjst = 0
}
# ----- HOSTNAME AND IP -----
/^P/ {
hostname = $2
sub(/^\(/, NULL, hostname)
sub(/\)$/, NULL, hostname)
if(hostname ~ /[A-Z]/)
hostname = tolower(hostname)
ip = $3
sub(/^\(/, NULL, ip)
sub(/\)$/, NULL, ip)
if(ip ~ /[A-F]/)
ip = tolower(ip)
next
}
# ----- PACKETLOSS -----
/^[0-9]+(\/[0-9]+)? p/ {
if($3 ~ /[0-9]+%$/)
pktlosscur = $3
else
pktlosscur = $6
sub(/%$/, NULL, pktlosscur)
if(pktlosscur > pktlossmax) {
pktlossmax = pktlosscur
if(pktlossmin == 0)
pktlossmin = pktlossmax
} else
if(pktlosscur < pktlossmin)
pktlossmin = pktlosscur
pktlossavg = (pktlosssum += pktlosscur) / ++pktlossreq
}
# ----- RTT, OUTPUT AND REQUESTS -----
/^(\[[0-9]+(\.[0-9]+)?\] )?[0-9]+ b/ {
if($1 ~ /^\[/) {
if(optshowtime || optmaxtime) {
sub(/^\[/, NULL, $1)
sub(/^\]/, NULL, $1)
dtm = $1 - stm
}
$1 = NULL
sub(/ /, NULL, $0)
} else
if(optshowtime || optmaxtime)
dtm = systime() - stm
if($9)
rttcur = $8
else
rttcur = $7
sub(/^.*=/, NULL, rttcur)
if(rttcur > rttmax) {
rttmax = rttcur
if(rttmin == 0)
rttmin = rttmax
} else
if(rttcur < rttmin)
rttmin = rttcur
rttavg = (rttsum += rttcur) / ++rttreq
# ----- OUTPUT -----
++reqcur
if(optshowreq)
printf "% 7d", reqcur
if(optshowtime) {
if(optshowreq)
printf " | "
printf "%s", strftime("%02H:%02M:%02S", dtm, optutc)
}
if(optshowrtt) {
if(optshowreq || optshowtime)
printf " | "
if(optshowcurrtt) {
if(opthighlight)
if(rttcur >= optmaxcurrtt)
printf "\033[7m"
printf "% 7.2F", rttcur
if(opthighlight)
if(rttcur >= optmaxcurrtt)
printf "\033[0m"
}
if(optshowminrtt) {
if(optshowcurrtt)
printf "/"
printf "%7.2F", rttmin
}
if(optshowavgrtt) {
if(optshowcurrtt || optshowminrtt)
printf "/"
if(opthighlight)
if(rttavg >= optmaxavgrtt)
printf "\033[7m"
printf "%7.2F", rttavg
if(opthighlight)
if(rttavg >= optmaxavgrtt)
printf "\033[0m"
}
if(optshowmaxrtt) {
if(optshowcurrtt || optshowminrtt || optshowavgrtt)
printf "/"
if(opthighlight)
if(rttmax >= optmaxcurrtt)
printf "\033[7m"
printf "%7.2F", rttmax
if(opthighlight)
if(rttmax >= optmaxcurrtt)
printf "\033[0m"
}
if(optshowunits)
printf " ms"
}
if(optshowpktloss) {
if(optshowreq || optshowtime || optshowrtt)
printf " | "
if(optshowcurpktloss) {
if(opthighlight)
if(pktlosscur >= optmaxcurpktloss)
printf "\033[7m"
printf "%6.2F", pktlosscur
if(opthighlight)
if(pktlosscur >= optmaxcurpktloss)
printf "\033[0m"
}
if(optshowminpktloss) {
if(optshowcurpktloss)
printf "/"
printf "%6.2F", pktlossmin
}
if(optshowavgpktloss) {
if(optshowcurpktloss || optshowminpktloss)
printf "/"
if(opthighlight)
if(pktlossavg >= optmaxavgpktloss)
printf "\033[7m"
printf "%6.2F", pktlossavg
if(opthighlight)
if(pktlossavg >= optmaxavgpktloss)
printf "\033[0m"
}
if(optshowmaxpktloss) {
if(optshowcurpktloss || optshowminpktloss || optshowavgpktloss)
printf "/"
if(opthighlight)
if(pktlossmax >= optmaxcurpktloss)
printf "\033[7m"
printf "%6.2F", pktlossmax
if(opthighlight)
if(pktlossmax >= optmaxcurpktloss)
printf "\033[0m"
}
if(optshowunits)
printf " %%"
}
if(optshowlabel) {
if(optshowreq || optshowtime || optshowrtt || optshowpktloss)
printf " | "
if(optlabel == NULL)
printf "%s", optresolve ? hostname : ip
else
printf "%s", optlabel
}
# ----- SCROLL -----
if(optscroll) {
if(scrreq)
--scrreq
else
scrreq = optscrollreq - 1
if(scrreq > 0) {
scrjst = 0
printf "\r"
} else {
scrjst = 1
printf "\n"
}
} else
printf "\r"
# ----- BREAK -----
if(optmaxtime)
if(dtm >= optmaxtime)
exit ret = 126
if(optmaxreq)
if(reqcur >= optmaxreq)
exit ret = 127
}
# ----- EXIT -----
END {
if(ret == 1 || helped || scrjst)
exit ret
printf "\n"
exit ret
}
# ----- LICENSE -----
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# The Software is provided "as is", without warranty of any
# kind, express or implied, including but not limited to the
# warranties of merchantability, fitness for a particular
# purpose and noninfringement. in no event shall the authors
# or copyright holders be liable for any claim, damages or
# other liability, whether in an action of contract, tort or
# otherwise, arising from, out of or in connection with the
# Software or the use or other dealings in the Software.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment