skip to Main Content

I scraped together a bash script to do multi-ping logging on Centos/Debian, when run from console it works fine, but run under crontab, the variable $NUM is left blank which should be a number such as 02 or 03, which lets the script find the IP address to ping from the config file.

More info: The goal is to provide bare basic ping data to an ISP that refuses to recognize advanced tools like MTR or router logs/graphs for troubleshooting. The ISP is having packet loss on several circuits, and they check it and say "looks good to us", they recognize ping data as a valid troubleshooting tool, so my ping script saves ping data in 10 minute increments to timestamped files, then another script sorts those files for any high latency or packet loss, which I send to the ISP as proof that the failure is inside their network. I have a backup ISP that I also log at the same time as proof that the destinations are generally available via other providers. My scripting skills are not fantastic, so I definitely consider any improvements.

Script has 2 components, a cfg file:

### Main program variables:
SPOOLDIR="/var/spool/pingstats"
BADPINGSDIR="/tmp/badpings"
BADPINGLOG="$BADPINGSDIR/badpings.log"
PINGLOG="$PROGRAMDIR/ping.log"

##### Set NODE NAMES (its just a name), host can be IP or hostname ie abc.com and maxping latency thresholds (edit/add nodes as needed)
NODENAME01=router
HOST01=10.0.0.1
MAXPING01=5

NODENAME02=dns1
HOST02=68.6.16.30
MAXPING02=35

NODENAME03=dns2
HOST03=1.1.1.1
MAXPING03=35

NODENAME04=fibergw
HOST04=77.77.77.74
MAXPING04=10

## Several more....

The script:

#!/bin/bash

## Base variables
PROGRAMDIR="/root/pingstats"
PINGCONF="$PROGRAMDIR/PingConfig.cfg"
TIMESTAMP="$(date +%Y%m%d%H%M)"
TIMESTAMP2() {
  date +"%Y-%m-%d_%H:%M:%S" # current time
}

source $PINGCONF

## check dir structure:
if [ ! -d $SPOOLDIR ]; then
        mkdir $SPOOLDIR
fi

## Loop through each nodename listed in cfg
for n in `grep NODENAME $PINGCONF`
        do
        echo "Processing Node: $n"
        echo "$(TIMESTAMP2) : Processing Node: $n" >> $PINGLOG
#### The next couple of lines are the problem, because $NUM ends up blank via cron
        NUM=$(grep -oE '[N]ODENAME.{,2}' <<< "$n" | grep -o '[0-9]+')
        echo "Node number for $n is $NUM" >> $PINGLOG
        HOSTTMP=HOST$NUM
        HOSTIP=${!HOSTTMP}
        echo "NODE is $n and HOSTIP is $HOSTIP"
        if [ ! -d "$SPOOLDIR/$NODENAME" ]; then
                mkdir "$SPOOLDIR/$NODENAME"
        fi
        echo "$(TIMESTAMP2) : Pinging NODE: $NODENAME at $HOSTIP logging to file:
        $SPOOLDIR/$NODENAME/$TIMESTAMP" >> $PINGLOG

        echo " Starting ping to $HOSTIP"
        ping -i 2 -s 8000 -c 300 $HOSTIP > "$SPOOLDIR/$NODENAME/$TIMESTAMP" &

        sleep 1
done

Expected to see several processes to be running pings. The logging shows me this:

2024-09-05_13:08:03 : Processing Node: NODENAME02=dns1
Node number for NODENAME02=dns1 is
2024-09-05_13:08:03 : Pinging NODE:  at  logging to file:
        /var/spool/pingstats//202409051308

There is a blank after the is and at, which should show $NUM and $HOSTIP, which was found via nested var $HOST$NUM

My /etc/crontab is:

*/10 * * * * root /root/pingstats/ping-nodes

Successful run from console spawns several processes such as:

 ps aux | grep ping
root     14533  0.0  0.1   1952   580 pts/8    S    13:19   0:00 ping -i 2 -s 8000 -c 300 10.0.0.1
root     14550  0.0  0.1   1952   584 pts/8    S    13:19   0:00 ping -i 2 -s 8000 -c 300 68.6.16.30
root     14560  0.0  0.1   1952   580 pts/8    S    13:19   0:00 ping -i 2 -s 8000 -c 300 1.1.1.1
root     14570  0.0  0.1   1952   580 pts/8    S    13:19   0:00 ping -i 2 -s 8000 -c 300 77.77.77.74

2

Answers


  1. Chosen as BEST ANSWER

    Thanks for everyone's patience, I did some revisions and cleanup and came up with this working method that works the same on console or crontab:

    Ping.cfg file (used in a few other scripts)

    ### Main program variables, suggested to leave these
    SPOOLDIR="/var/spool/pingstats"
    BADPINGSDIR="/tmp/badpings"
    BADPINGLOG="$BADPINGSDIR/badpings.log"
    PINGLOG="$PROGRAMDIR/ping.log"
    
    ### Set your email prefs:
    CLIENT="ACME Inc"
    ADMINEMAIL="[email protected]"
    SENDEMAIL=yes
    
    ##### Set list of nodes to ping with 3 criteria: name, IP/hostname, and max latency in milliseconds.
    
    NODE01="router,10.0.0.1,10"
    NODE02="dns1,68.6.16.30,35"
    NODE03="dns2,1.1.1.1,35"
    NODE04="fibergw,7.7.7.4,10"
    NODE05="cablegw,6.2.1.5,10"
    ## Several more...
    

    Script:

    #!/bin/bash
    ##   Schedule in /etc/crontab every 10 minutes:
    ##   */10 * * * * root /root/pingstats/ping-nodes
    ##   Edit Ping.cfg with as many hosts as needed.
    #################################################
    
    ## More vars:
    scripts out of the /root dir
    PROGRAMDIR="/root/pingstats"
    PINGCONF="$PROGRAMDIR/Ping.cfg"
    TIMESTAMP="$(date +%Y%m%d%H%M)"
    TIMESTAMP2() {
      date +"%Y-%m-%d_%H:%M:%S" # current time
    }
    
    source $PINGCONF
    ## check dir structure:
    if [ ! -d $SPOOLDIR ]; then
            mkdir $SPOOLDIR
    fi
    
    ## Loop through each nodename variable listed in cfg file:
    while read -r NODENAME HOSTIP rest; do
        printf 'Nodename is %s and hostip is %sn' "$NODENAME" "$HOSTIP"
        if [ ! -d "$SPOOLDIR/$NODENAME" ]; then
                    mkdir "$SPOOLDIR/$NODENAME"
        fi
        echo "$(TIMESTAMP2) : Pinging NODE: $NODENAME at $HOSTIP logging to file: $SPOOLDIR/$NODENAME/$TIMESTAMP" >> $PINGLOG
        echo " Starting ping to $HOSTIP logging to file: $SPOOLDIR/$NODENAME/$TIMESTAMP"
        ping -i 2 -s 8000 -c 300 $HOSTIP > "$SPOOLDIR/$NODENAME/$TIMESTAMP" &
        sleep 1
            echo ""; echo "" >> $PINGLOG
    done < <(awk -F'[",]' '/^NODE/{print $2, $3}' $PINGCONF)
    

    Sorry if my code isn't great, I have written ~5000 lines of bash over the last 20 years, I'm probably 6/10 on expertise.


  2. Simply by sourcing your PingConfig.cfg

    If you’re confident with content of $PINGCONF, you could source them. (Care, this will execute commands, if present in your config file!)

    Notes:

    • I use printf '%(date format string)T' instead of fork to date, for date time print.
    • I use indirection to build numbered variables
    #!/bin/bash
    shopt -s extglob
    
    PROGRAMDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
    PINGCONF="$PROGRAMDIR/PingConfig.cfg"
    printf -v TIMESTAMP '%(%Y%m%d%H%M)T' -1
    
    . "$PINGCONF"
    
    for nodename in ${!NODENAME*}; do
        host=HOST${nodename//*([A-Z])} maxping=MAXPING${nodename//*([A-Z])}
        printf 'Processing Node: %d: "%s"n' ${nodename//*([A-Z])} "${!nodename}"
        if [ ! -d "$SPOOLDIR/${!nodename}" ]; then
            mkdir -p "$SPOOLDIR/${!nodename}"
        fi
        printf >>$PINGLOG 
            '%(%Y-%m-%d_%H:%M:%S)T: Pinging NODE: %s at %s logging to file: %sn' 
            -1 "${!nodename}" "${!host}" "$SPOOLDIR/${!nodename}/$TIMESTAMP" 
    
        echo " Starting ping to ${!host}"
        ping -i 2 -s 8000 -c ${!maxping} ${!host} 
            >"$SPOOLDIR/${!nodename}/$TIMESTAMP" &
        sleep .2
    done
    
    Processing Node: 1: "router"
     Starting ping to 10.0.0.1
    Processing Node: 2: "dns1"
     Starting ping to 68.6.16.30
    Processing Node: 3: "dns2"
     Starting ping to 1.1.1.1
    Processing Node: 4: "fibergw"
     Starting ping to 77.77.77.74
    
    $ cat ping.log 
    2024-09-05_16:24:03: Pinging NODE: router at 10.0.0.1 logging to file: /tmp/so/pingstats/router/202409051624
    2024-09-05_16:24:03: Pinging NODE: dns1 at 68.6.16.30 logging to file: /tmp/so/pingstats/dns1/202409051624
    2024-09-05_16:24:03: Pinging NODE: dns2 at 1.1.1.1 logging to file: /tmp/so/pingstats/dns2/202409051624
    2024-09-05_16:24:03: Pinging NODE: fibergw at 77.77.77.74 logging to file: /tmp/so/pingstats/fibergw/202409051624
    
    $ ls -gR ping*
    -rw-r--r-- 1 user  434  5 sep 16:24 ping.log
    
    pingstats:
    total 16
    drwxr-xr-x 2 user 4096  5 sep 16:24 dns1
    drwxr-xr-x 2 user 4096  5 sep 16:24 dns2
    drwxr-xr-x 2 user 4096  5 sep 16:24 fibergw
    drwxr-xr-x 2 user 4096  5 sep 16:24 router
    
    pingstats/dns1:
    total 4
    -rw-r--r-- 1 user 159  5 sep 16:25 202409051624
    
    pingstats/dns2:
    total 4
    -rw-r--r-- 1 user 150  5 sep 16:25 202409051624
    
    pingstats/fibergw:
    total 4
    -rw-r--r-- 1 user 162  5 sep 16:24 202409051624
    
    pingstats/router:
    total 4
    -rw-r--r-- 1 user 151  5 sep 16:24 202409051624
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search