I wrote a bash script that can be used to monitor uptime. It attempts to ping various hosts and logs when they go down and come back up. You can also use it to send an email when this happens as well. It's my first bash script ever, so let me know if there's anything I could do to improve it.
#!/bin/bash # Uptime monitoring # Based on: http://www.techrapid.co.uk/openwrt/monitoring-uptime-on-openwrt/ by justhrun # MIT License # Copyright (c) 2016 multiwebinc # # 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. #################################################### # How to install on EdgeOS: # Install fping and mailutils. # See https://help.ubnt.com/hc/en-us/articles/205202560-EdgeMAX-Add-other-Debian-packages-to-EdgeOS # Edit /etc/ssmtp/ssmtp.conf and add the last few lines there: # # mailhub=mailserverip # AuthUser=username # AuthPass=password # FromLineOverride=YES # UseTLS=YES #################################################### ## Configuration ## #################################################### # A list of all hosts to check separated by a space HOSTS="google.com facebook.com yahoo.com bing.com" # Append the gateway IP to the list of hosts (recommended) # This should give you an indication if there is a problem between you and your # ISP or between the ISP and the hosts listed in $HOSTS APPEND_GATEWAY=true # Directory to store log file and host.isdown files LOGDIR=/tmp/log/ # Whether or not to log the messages of when the hosts go up or down. LOGMESSAGES=true # Whether or not to keep track of how long a host has been down for. If this is # false, a message will be displayed, logged or emailed on every iteration. It # is therefore highly recommended to leave this as true. TRACK_DOWNTIME=true # Send email when a host goes up or down. Note: You need to be able to # access the mail server and the mail server needs to be able to access # the domain in $MAILTO for this to be useful SENDEMAIL=false MAILFROM="Uptime monitor <root@ubnt>" MAILTO="user@intranet.server" # Whether to echo messages to stdout ECHOMESSAGES=true # Number of seconds to wait between checking the hosts. Set to 60 to only
# check once per host every time this script is executed INTERVAL=10 #################################################### set -e function messageHandler { if [ "$SENDEMAIL" = false ] && [ "$ECHOMESSAGES" = false ] && [ "$LOGMESSAGES" = false ] ; then>&2 echo "No way to handle messages. Exiting." exit 1 fi message=$1 if [ "$SENDEMAIL" = true ]; then subject=$2 `echo "$message" | mail -a "From:$MAILFROM" -s "$subject" $MAILTO` fi if [ "$ECHOMESSAGES" = true ] ; then echo "$message" fi if [ "$LOGMESSAGES" = true ] ; then echo "$message" >> ${LOGFILE} fi } # Get default interface INTERFACE=`/sbin/ip route | awk '/default/ { print $5 }'` if [ ! $INTERFACE ] ; then >&2 echo "No network interfaces are up. Exiting." exit 1 fi # Make sure fping is installed if [ ! `which fping` ] ; then >&2 echo "fping is not installed. Exiting." exit 1 fi # Make sure mail is installed if [ "$SENDEMAIL" = true ] && [ ! `which mail` ] ; then>&2 echo "The 'mail' command does not exist. Exiting." exit 1 fi # Add the gateway IP to $HOSTS if [ "$APPEND_GATEWAY" = true ] ; then AWKCOMMAND="/${INTERFACE}/ {print \$3}" GATEWAY=`/sbin/ip route |grep "^default" | awk "$AWKCOMMAND"` HOSTS="${GATEWAY} ${HOSTS}" fi # Create log directory if it doesn't exist mkdir -p ${LOGDIR} LOGFILE="${LOGDIR}hostcheck.log" # Execute loop $INTERVAL number of times for ~1 minute for (( i = 0 ; i < $(( 60 / $INTERVAL )) ; i++ )); do # Make sure the network interface is still up if [[ ! `/sbin/ip route | grep $INTERFACE` ]] ; then>&2 echo "Network is down. Exiting." exit 1 fi # Get the current time in milliseconds to calculate execution time later STARTTIME=$(date +%s%3N) # Ping all hosts and loop over results as they come in fping -B 1 -r 3 $HOSTS | while read line ; do if [ "$ECHOMESSAGES" = true ] ; then echo $line fi regex="(^\S*) (.*)" if [[ $line =~ $regex ]]; then myHost=${BASH_REMATCH[1]} alive=${BASH_REMATCH[2]} TCHECK=`date "+%Y-%m-%d %H:%M:%S"` downfile=${LOGDIR}${myHost}.isdown # Host is up if [ "$alive" = "is alive" ] ; then ## host alive, check then remove file host.isdown if [ -f ${downfile} ]; then if [ "$TRACK_DOWNTIME" = true ] ; then DOWNTIME=$(($(date +%s) - $(date +%s -r ${downfile}))) message="${TCHECK} : $myHost is back up. Total downtime: ${DOWNTIME} seconds" subject="[Uptime Monitor] $myHost is back up!" messageHandler "$message" "$subject" fi rm -f ${downfile} fi # Host is down else ## No host.isdown file exists, so create it if [ ! -f ${downfile} ]; then ## not exist, host is down message="${TCHECK} : $myHost is down" subject="[Uptime Monitor] $myHost is down!" messageHandler "$message" "$subject" if [ "$TRACK_DOWNTIME" = true ] ; then touch ${downfile} fi fi fi else >&2 echo "An error occurred with the regex" exit 1 fi done if [ "$ECHOMESSAGES" = true ] ; then echo "" fi # Sleep for up to $INTERVAL seconds ELAPSED=$(($(date +%s%3N) - STARTTIME)) if [[ $ELAPSED -lt $(( $INTERVAL * 1000 )) ]] ; then sleeptime=$(awk -v el=$ELAPSED -v intv=$(( $INTERVAL * 1000 )) "BEGIN { print (intv-el)/1000 }") sleep $sleeptime fi done