Skip to content

Instantly share code, notes, and snippets.

@Decstasy
Last active January 14, 2020 12:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Decstasy/6a9c7c50cb965a77e5e4a1058f4e060b to your computer and use it in GitHub Desktop.
Save Decstasy/6a9c7c50cb965a77e5e4a1058f4e060b to your computer and use it in GitHub Desktop.
Icinga check to get network interface performance data
#!/bin/bash
# Dennis Ullrich
# request@decstasy.de
####################################
############# Variables ##########
################################
# Arrays
declare -A interface
declare -A stats
declare -A unit
declare -A unit_name
# Tmpfile
# WARNING: It will be redeclared while parsing the argument "-i"!
stats[tmpfile]="/tmp/check_net_if_stats.tmp"
# Units for calculation
unit[b]="1"
unit[k]="1000"
unit[m]="1000^2"
unit[g]="1000^3"
unit[t]="1000^4"
# Units for output
unit_name[b]="b"
unit_name[k]="k"
unit_name[m]="m"
unit_name[g]="g"
unit_name[t]="t"
####################################
############# Functions ##########
################################
usage() {
cat << EOF
Usage: ${0##*/} [-hd] [-i interface] [-u unit]
-h Display this help and exit
-d Debug mode (be aware - your terminal will be spammed)
-i [interface] e.g. eth0, lan0, bond0 etc...
-u [unit] b, k, m, g, t (bit/s (default), kbit/s, mbit/s, gbit/s, tbit/s)
-p [precision] Number of digits behind dot. Only 0-9 allowed. Default: 0
EOF
exit 0
}
interface_exists() {
if ! grep -qm1 "${interface[name]}:" /proc/net/dev; then
>&2 echo "CRITICAL: Interface \"${interface[name]}\" not found in /proc/net/dev!"
exit 2
fi
}
read_stats() {
stats[new-timestamp]=`date "+%s"`
stats[new-data]=$(awk "/${interface[name]}/{print \$1,\$2,\$10}" /proc/net/dev)
newtmp=( ${stats[new-data]} )
stats[old-timestamp]=$(stat -c %Y ${stats[tmpfile]})
stats[old-data]="$(awk "/${interface[name]}/{print \$1,\$2,\$10}" ${stats[tmpfile]})"
oldtmp=( ${stats[old-data]} )
stats[timestamp-diff]=$(( ${stats[new-timestamp]} - ${stats[old-timestamp]} ))
interface[rx-new]=${newtmp[1]}
interface[rx-old]=${oldtmp[1]}
interface[tx-new]=${newtmp[2]}
interface[tx-old]=${oldtmp[2]}
}
write_stats() {
cat /proc/net/dev > ${stats[tmpfile]}
}
detect_time_leap() {
if [ "${stats[timestamp-diff]}" -le 0 ]; then
>&2 echo "WARNING: Time leap detected! Stats written. Wait for next cycle. |rx_${interface[name]}=0.000${unit_name[${interface[unit]}]};;;;tx_${interface[name]}=0.000${unit_name[${interface[unit]}]};;;;"
exit 1
fi
}
detect_if_reset() {
# if the new counter is smaller than the old counter, we have detected an interface reset
for x in rx tx; do
if [ "${interface[$x-new]}" -lt "${interface[$x-old]}" ]; then
>&2 echo "WARNING: Interface \"${interface[name]}\" has been resetted! Stats written. Wait for next cycle. |rx_${interface[name]}=0.000${unit_name[${interface[unit]}]};;;;tx_${interface[name]}=0.000${unit_name[${interface[unit]}]};;;;"
exit 1
fi
done
}
calculate_stats() {
for x in rx tx; do
# scale for 0.xxx precision
# calculate difference between old and new rx * 8 to get it in bit, divide with timestamp diff since last run and divide to target unit
# check if result is between 0 and 1 and print a 0 since bc does not print a leading zero by default
interface[$x-sec]=$(bc <<< "scale=${unit[precision]}
result=(( ${interface[$x-new]} - ${interface[$x-old]} ) * 8 ) / ${stats[timestamp-diff]} / ${unit[${interface[unit]}]}
if (0 <= result && result < 1 && result != 0) {
print \"0\"
}
print result;")
done
}
###############################################
############# Parse, check, set... ##########
###########################################
# Parse args
while getopts “:hdi:u:p:” OPTION; do
case $OPTION in
d) # Debug
set -x
;;
h) usage
;;
i) interface[name]="$OPTARG"
stats[tmpfile]="/tmp/check_net_if_stats_${interface[name]}.tmp"
;;
u) if [[ ! "$OPTARG" =~ ^[bkmgt]$ ]]; then
>&2 echo "Unknown unit $OPTARG in Option $OPTION. Execute script with -h option to get help."; exit 3
fi
interface[unit]="$OPTARG"
;;
p) if [[ ! "$OPTARG" =~ ^[0-9]$ ]]; then
>&2 echo "Scale \"$OPTARG\" is not between 0 and 9 in Option $OPTION. Execute script with -h option to get help."; exit 3
fi
unit[precision]=$OPTARG
;;
'?') >&2 echo "Unknown argument $OPTARG in Option $OPTION. Execute script with -h option to get help."; exit 3
;;
esac
done
# remove the options and optional --
shift "$((OPTIND-1))"
# Set default(s)
[ -z ${interface[unit]} ] && interface[unit]="b"
[ -z ${unit[precision]} ] && unit[precision]=0
# Check input
if [ -z ${interface[name]} ] || [ -z ${interface[unit]} ] || [ -z ${unit[precision]} ]; then
>&2 echo 'UNKNOWN: Not all required arguments are given. Execute script with -h option to get help.'
exit 3
fi
###############################
############# MAIN ##########
###########################
if ! type bc > /dev/null 2>&1; then
echo "UNKNOWN: bc is not installed on this machine!"
exit 3
fi
interface_exists
if [ ! -f "${stats[tmpfile]}" ]; then
write_stats
echo "OK: Stats written. Wait for next cycle."
exit 0
fi
read_stats
write_stats
detect_time_leap
detect_if_reset
calculate_stats
# output if everything is fine
rx="'rx_${interface[name]}'=${interface[rx-sec]}${unit_name[${interface[unit]}]};0;0;0;0"
tx="'tx_${interface[name]}'=${interface[tx-sec]}${unit_name[${interface[unit]}]};0;0;0;0"
perfdata="${rx} ${tx}"
echo "OK: Interface ${interface[name]} RX: ${interface[rx-sec]} ${unit_name[${interface[unit]}]}/s, TX: ${interface[tx-sec]} ${unit_name[${interface[unit]}]}/s | ${perfdata}"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment