#! /usr/bin/ksh # scan_log # nagios plugin to scan for multiple patterns in a log file # author: Sergei Haramundanis 27-Apr-2006 # update: [2.0] 11-Apr-2007 by S. Haramundanis to include performing monitor within a specific timeframe # update: [2.1] 10-May-2007 by S. Haramundanis to include reinitializing .new and .old files if .new file is smaller after scan # # usage: scan_log runtime_directory pattern_data_file log_file_to_scan check_from_time check_to_time # # Description: # # This plugin will scan a log file (specified by the log_file_to_scan argument), # at a specific timeframe specified by check_from_time and check_to_time (in HHMM format), # for a set of patterns listed in the pattern data file (specified by the pattern_data_file argument). # # When initially started, this plugin creates empty pattern_data_file.new and pattern_data_file.old files # which are used to contain any pattern matches it finds during the scan. The pattern matches found in the # log file are appended to the .new file, and a diff is executed on the .new and .old files to determine if any # new patterns have been found. # # Note that this potentially uses much less disk space than check_log as it does not depend on an entire # copy of the log file to scan for differences. # # Lines beginning with # or blank lines in the pattern data file are ignored. # # Output: # # During any run of the plugin, the value returned will be as follows: # # if the current time is outside the specified timeframe it will return an OK state with the message: # # [OK] current time outside of monitoring timeframe check_from_time and check_to_time # # if the current time is within the specified timeframe and: # # if differences between the .new and .old pattern matches found exist it will return a WARNING state and provide a message in the following format: # # [line count of diff] last line of diff of .new and .old files # # if no differences between .new and .old files exist it will return an OK state with the message: # # [OK] 0 differences found # # if after scan .new file is smaller than .old file the plugin assumes the log_file_to_scan has been initialized, reinitializes # both .new and .old files and returns an OK state with the message: # # [OK] .new and .old pattern matching results files have been reinitialized # SCRIPTPATH=`echo $0 | /bin/sed -e 's,[\\/][^\\/][^\\/]*$,,'` . ${SCRIPTPATH}/utils.sh # sets correct STATE_* return values if [ "${1}" = "" -o "${1}" = "--help" ]; then echo "scan_log 2.1" echo "" echo "nagios plugin to scan for multiple patterns in a log file" echo "" echo "This nagios plugin comes with ABSOLUTELY NO WARRANTY." echo "You may redistribute copies of this plugin under the terms of the GNU General Public License" echo "as long as the original author, edit history and description information remain in place." echo "" echo "usage: scan_log " echo "usage: scan_log --help" echo "usage: scan_log --version" exit ${STATE_OK} fi if [ ${1} == "--version" ]; then echo "scan_log 2.1" echo "This nagios plugin comes with ABSOLUTELY NO WARRANTY." echo "You may redistribute copies of this plugin under the terms of the GNU General Public License" echo "as long as the original author, edit history and description information remain in place." exit ${STATE_OK} fi if [ $# -lt 5 ]; then echo "[CRITICAL] insufficient arguments" exit ${STATE_CRITICAL} fi RUNDIR=${1} DATFILE=${2} LOGFILE=${3} CHECK_FROM_TIME=${4} CHECK_TO_TIME=${5} #echo "RUNDIR=\"${RUNDIR}\"" #echo "DATFILE=\"${DATFILE}\"" #echo "LOGFILE=\"${LOGFILE}\"" #echo "CHECK_FROM_TIME=\"${CHECK_FROM_TIME}\"" #echo "CHECK_TO_TIME=\"${CHECK_TO_TIME}\"" START_TIME=`date +%H%M%S` #### if [ ! -d ${RUNDIR} ]; then echo "[CRITICAL] unable to locate runtime_directory ${RUNDIR}" exit ${STATE_CRITICAL} fi if [ ! -w ${RUNDIR} ]; then echo "[CRITICAL] no write access to runtime_directory ${RUNDIR}" exit ${STATE_CRITICAL} fi #### #### if [ ! -f ${DATFILE} ]; then echo "[CRITICAL] unable to locate pattern_data_file ${DATFILE} from `pwd`" exit ${STATE_CRITICAL} fi if [ ! -r ${DATFILE} ]; then echo "[CRITICAL] unable to read pattern_data_file ${DATFILE}" exit ${STATE_CRITICAL} fi #### #### if [ ! -f ${LOGFILE} ]; then echo "[CRITICAL] unable to locate log_file_to_scan ${LOGFILE} from `pwd`" exit ${STATE_CRITICAL} fi if [ ! -r ${LOGFILE} ]; then echo "[CRITICAL] unable to read log_file_to_scan ${LOGFILE}" exit ${STATE_CRITICAL} fi #### # retrieve current date and time CURRENT_DATE=`date +%Y%m%d` CURRENT_TIME=`date +%H%M` CURRENT_DATETIME=`date +%Y%m%d%H%M` CHECK_FROM_DATETIME=`echo ${CURRENT_DATE}${CHECK_FROM_TIME}` CHECK_TO_DATETIME=`echo ${CURRENT_DATE}${CHECK_TO_TIME}` #echo "CURRENT_DATE=\"${CURRENT_DATE}\"" #echo "CURRENT_TIME=\"${CURRENT_TIME}\"" #echo "CURRENT_DATETIME=\"${CURRENT_DATETIME}\"" #echo "CHECK_FROM_DATETIME=\"${CHECK_FROM_DATETIME}\"" #echo "CHECK_TO_DATETIME=\"${CHECK_TO_DATETIME}\"" if [ ${CURRENT_DATETIME} -ge ${CHECK_FROM_DATETIME} -a ${CURRENT_DATETIME} -le ${CHECK_TO_DATETIME} ] ; then DATFILE_PREFIX=${DATFILE} let index=-1 while [ ${index} -ne 0 ] do let index=`echo $DATFILE_PREFIX "/" | awk '{print(index($1,$2))}'` if [ ${index} -ne 0 ]; then let index=index+1 DATFILE_PREFIX=`echo $DATFILE_PREFIX $index | awk '{print(substr($1,$2))}'` fi done let index=`echo $DATFILE_PREFIX "." | awk '{print(index($1,$2))}'` let index=index-1; DATFILE_PREFIX=`echo $DATFILE_PREFIX $index | awk '{print(substr($1,1,$2))}'` if [ ! -e "${RUNDIR}/${DATFILE_PREFIX}.old" ]; then RETVAL=`touch ${RUNDIR}/${DATFILE_PREFIX}.old 2>&1` if [ $? -ne 0 ]; then END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[CRITICAL] unable to execute [1] \"touch ${RUNDIR}/${DATFILE_PREFIX}.old\": \"${RETVAL}\" | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_CRITICAL} fi fi if [ ! -e "${RUNDIR}/${DATFILE_PREFIX}.new" ]; then RETVAL=`touch ${RUNDIR}/${DATFILE_PREFIX}.new 2>&1` if [ $? -ne 0 ]; then END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[CRITICAL] unable to execute [1] \"touch ${RUNDIR}/${DATFILE_PREFIX}.new\": \"${RETVAL}\" | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_CRITICAL} fi fi RETVAL=`mv ${RUNDIR}/${DATFILE_PREFIX}.new ${RUNDIR}/${DATFILE_PREFIX}.old 2>&1` if [ $? -ne 0 ]; then END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[CRITICAL] unable to execute \"mv ${RUNDIR}/${DATFILE_PREFIX}.new ${RUNDIR}/${DATFILE_PREFIX}.old\": \"${RETVAL}\" | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_CRITICAL} fi RETVAL=`touch ${RUNDIR}/${DATFILE_PREFIX}.new 2>&1` if [ $? -ne 0 ]; then END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[CRITICAL] unable to execute [2] \"touch ${RUNDIR}/${DATFILE_PREFIX}.new\": \"${RETVAL}\" | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_CRITICAL} fi while read pattern do result_1=`echo ${pattern} | sed s/' '//g | sed s/\w//g | sed s/\t//g` result_2=`echo ${pattern} | sed s/' '//g | sed s/\w//g | sed s/\t//g | awk '{print(index($1,"#"))}'` if [ "${result_1}" != "" ]; then # not a blank line if [ ${result_2} -ne 1 ]; then # not a comment grep "${pattern}" ${LOGFILE} >> ${RUNDIR}/${DATFILE_PREFIX}.new fi fi done < ${DATFILE} #### # if .new file is smaller than .old file, assume log_file_to_scan has been initialized and reinitialize .new and .old files FILE_SIZE_NEW=`cat "${RUNDIR}/${DATFILE_PREFIX}.new" | wc -c | sed /^$/d` # remove all blank lines FILE_SIZE_OLD=`cat "${RUNDIR}/${DATFILE_PREFIX}.old" | wc -c | sed /^$/d` # remove all blank lines if [ ${FILE_SIZE_NEW} -lt ${FILE_SIZE_OLD} ]; then RETVAL=`rm ${RUNDIR}/${DATFILE_PREFIX}.new 2>&1` if [ $? -ne 0 ]; then END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[CRITICAL] unable to execute \"rm ${RUNDIR}/${DATFILE_PREFIX}.new\": \"${RETVAL}\" | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_CRITICAL} fi RETVAL=`touch ${RUNDIR}/${DATFILE_PREFIX}.new 2>&1` if [ $? -ne 0 ]; then END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[CRITICAL] unable to execute [3] \"touch ${RUNDIR}/${DATFILE_PREFIX}.new\": \"${RETVAL}\" | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_CRITICAL} fi RETVAL=`rm ${RUNDIR}/${DATFILE_PREFIX}.old 2>&1` if [ $? -ne 0 ]; then END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[CRITICAL] unable to execute \"rm ${RUNDIR}/${DATFILE_PREFIX}.old\": \"${RETVAL}\" | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_CRITICAL} fi RETVAL=`touch ${RUNDIR}/${DATFILE_PREFIX}.old 2>&1` if [ $? -ne 0 ]; then END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[CRITICAL] unable to execute [2] \"touch ${RUNDIR}/${DATFILE_PREFIX}.old\": \"${RETVAL}\" | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_CRITICAL} fi END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[OK] .new and .old pattern matching results files have been reinitialized | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_OK} fi #### result_2=`diff ${RUNDIR}/${DATFILE_PREFIX}.new ${RUNDIR}/${DATFILE_PREFIX}.old | wc -l` result_2=`echo $result_2 | sed s/' '//g` # remove spaces if [ $result_2 -ne 0 ] ; then # only report if there are new patterns found END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[${result_2}]" `diff ${RUNDIR}/${DATFILE_PREFIX}.new ${RUNDIR}/${DATFILE_PREFIX}.old | tail -1 | sed s/'<'/' '/g` " | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_WARNING} else END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[OK] 0 differences found | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_OK} fi else END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[OK] current time outside of monitoring timeframe ${CHECK_FROM_TIME} and ${CHECK_TO_TIME} | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_OK} fi # shouldn't get here, but if we do return CRITICAL with reason unknown END_TIME=`date +%H%M%S` let ELAPSED_TIME=${END_TIME}-${START_TIME} echo "[CRITICAL] exiting with reason unknown, check shell script execution | elapsedTimeSecs=${ELAPSED_TIME}" exit ${STATE_CRITICAL}