diff --git a/etc/opt/hc/core/check_health.conf.dist b/etc/opt/hc/core/check_health.conf.dist index 361b65c..c3b0729 100644 --- a/etc/opt/hc/core/check_health.conf.dist +++ b/etc/opt/hc/core/check_health.conf.dist @@ -21,6 +21,16 @@ HC_LOG_HEALTHY="No" # [values: Yes|No] HC_WILL_FIX="Yes" +# cache "last" reporting entries. Set to 'Yes' to speed up reporting of the last +# registered HC events +# [values: Yes|No] +HC_REPORT_CACHE_LAST="No" + +# cache "today" reporting entries. Set to 'Yes' to speed up reporting of today's +# registered HC events +# [values: Yes|No] +HC_REPORT_CACHE_TODAY="No" + #****************************************************************************** # End of FILE diff --git a/opt/hc/bin/check_health.sh b/opt/hc/bin/check_health.sh index 344ae1e..3dae3bb 100755 --- a/opt/hc/bin/check_health.sh +++ b/opt/hc/bin/check_health.sh @@ -38,7 +38,7 @@ # ------------------------- CONFIGURATION starts here ------------------------- # define the version (YYYY-MM-DD) -typeset -r SCRIPT_VERSION="2020-03-12" +typeset -r SCRIPT_VERSION="2020-04-07" # location of parent directory containing KSH functions/HC plugins typeset -r FPATH_PARENT="/opt/hc/lib" # location of custom HC configuration files @@ -104,6 +104,10 @@ typeset HC_STDOUT_LOG="" typeset HC_STDERR_LOG="" typeset HC_WILL_FIX="" # shellcheck disable=SC2034 +typeset HC_REPORT_CACHE_LAST="" +# shellcheck disable=SC2034 +typeset HC_REPORT_CACHE_TODAY="" +# shellcheck disable=SC2034 typeset LINUX_DISTRO="" # shellcheck disable=SC2034 typeset LINUX_RELEASE="" @@ -255,8 +259,8 @@ case "${KSH_VERSION}" in . ${FPATH_PARENT}/core/include_core.sh if [[ -r ${FPATH_PARENT}/core/include_data.sh && -h ${FPATH_PARENT}/core/include_data ]] then - # shellcheck source=/dev/null (( ARG_DEBUG > 0 )) && print -u2 "DEBUG: including ${FPATH_PARENT}/core/include_data.sh" + # shellcheck source=/dev/null . ${FPATH_PARENT}/core/include_data.sh else print -u2 "ERROR: library file ${FPATH_PARENT}/core/include_data.sh is not present (tip: run --fix-symlinks)" @@ -264,8 +268,8 @@ case "${KSH_VERSION}" in fi if [[ -r ${FPATH_PARENT}/core/include_os.sh && -h ${FPATH_PARENT}/core/include_os ]] then - # shellcheck source=/dev/null (( ARG_DEBUG > 0 )) && print -u2 "DEBUG: including ${FPATH_PARENT}/core/include_os.sh" + # shellcheck source=/dev/null . ${FPATH_PARENT}/core/include_os.sh else print -u2 "ERROR: library file ${FPATH_PARENT}/core/include_os.sh is not present (tip: run --fix-symlinks)" @@ -274,7 +278,7 @@ case "${KSH_VERSION}" in ;; *) # include include_* - find ${FPATH_PARENT}/core -name "include_*.sh" -type f -print 2>/dev/null | while read INCLUDE_FILE + find ${FPATH_PARENT}/core -name "include_*.sh" -type f -print 2>/dev/null | while read -r INCLUDE_FILE do if [[ -h ${INCLUDE_FILE%%.sh} ]] then @@ -330,7 +334,7 @@ function check_lock_dir (( ARG_DEBUG > 0 && ARG_DEBUG_LEVEL > 0 )) && set "${DEBUG_OPTS}" if (( ARG_LOCK > 0 )) then - mkdir ${LOCK_DIR} >/dev/null || { + mkdir ${LOCK_DIR} >/dev/null 2>/dev/null || { print -u2 "ERROR: unable to acquire lock ${LOCK_DIR}" ARG_VERBOSE=0 warn "unable to acquire lock ${LOCK_DIR}" if [[ -f ${LOCK_DIR}/.pid ]] @@ -465,12 +469,6 @@ then exit 1 fi fi -# --log-healthy -if (( ARG_LOG_HEALTHY > 0 && ARG_ACTION != 4 )) -then - print -u2 "ERROR: you can only use '--log-healthy' in combination with '--run'" - exit 1 -fi # check log location if (( ARG_LOG > 0 )) then @@ -959,6 +957,7 @@ do fi ;; -list-details|--list-details) + # shellcheck disable=SC2034 ARG_LIST_DETAILS=1 ARG_ACTION=9 ;; diff --git a/opt/hc/lib/core/include_core.sh b/opt/hc/lib/core/include_core.sh index af3cd32..3c97c84 100755 --- a/opt/hc/lib/core/include_core.sh +++ b/opt/hc/lib/core/include_core.sh @@ -30,7 +30,7 @@ # RETURNS: 0 function version_include_core { -typeset _VERSION="2020-03-12" # YYYY-MM-DD +typeset _VERSION="2020-04-07" # YYYY-MM-DD print "INFO: $0: ${_VERSION#version_*}" @@ -92,8 +92,8 @@ do ARCHIVE_FILE="${ARCHIVE_DIR}/hc.${YEAR_MONTH}.log" cat ${ARCHIVE_FILE} ${TMP1_FILE} 2>/dev/null | sort -u >${TMP2_FILE} 2>/dev/null mv ${TMP2_FILE} ${ARCHIVE_FILE} 2>/dev/null || { - warn "failed to move archive file, aborting" - return 2 + warn "failed to move archive file, aborting" + return 2 } LOG_COUNT=$(wc -l ${ARCHIVE_FILE} 2>/dev/null | cut -f1 -d' ' 2>/dev/null) log "# of entries in ${ARCHIVE_FILE} now: ${LOG_COUNT}" @@ -108,17 +108,17 @@ do # only messages from one single HC plugin before archival) if [[ -s ${TMP2_FILE} ]] || (( PRE_LOG_COUNT == TODO_LOG_COUNT )) then - mv ${TMP2_FILE} ${HC_LOG} 2>/dev/null || { - warn "failed to move HC log file, aborting" - return 2 - } - LOG_COUNT=$(wc -l ${HC_LOG} 2>/dev/null | cut -f1 -d' ' 2>/dev/null) - log "# entries in ${HC_LOG} now: ${LOG_COUNT}" - ARCHIVE_RC=1 + mv ${TMP2_FILE} ${HC_LOG} 2>/dev/null || { + warn "failed to move HC log file, aborting" + return 2 + } + LOG_COUNT=$(wc -l ${HC_LOG} 2>/dev/null | cut -f1 -d' ' 2>/dev/null) + log "# entries in ${HC_LOG} now: ${LOG_COUNT}" + ARCHIVE_RC=1 else - warn "a problem occurred. Rolling back archival" - mv ${SAVE_HC_LOG} ${HC_LOG} 2>/dev/null - ARCHIVE_RC=2 + warn "a problem occurred. Rolling back archival" + mv ${SAVE_HC_LOG} ${HC_LOG} 2>/dev/null + ARCHIVE_RC=2 fi done @@ -145,12 +145,13 @@ function count_log_errors typeset LOG_STASH="${1}" typeset ERROR_COUNT=0 +# shellcheck disable=SC2002 ERROR_COUNT=$(cat ${LOG_STASH} 2>/dev/null | awk -F"${LOG_SEP}" ' BEGIN { num = 0 } { - if (NF>'"${NUM_LOG_FIELDS}"' || $0 == "") { - num++; - } + if (NF>'"${NUM_LOG_FIELDS}"' || $0 == "") { + num++; + } } END { print num }' 2>/dev/null) @@ -193,15 +194,15 @@ if [[ -n "${1}" ]] then if (( ARG_LOG > 0 )) then - print - "$*" | while read -r LOG_LINE - do - # shellcheck disable=SC2153 - print "${NOW}: ERROR: [$$]:" "${LOG_LINE}" >>${LOG_FILE} - done + print - "$*" | while read -r LOG_LINE + do + # shellcheck disable=SC2153 + print "${NOW}: ERROR: [$$]:" "${LOG_LINE}" >>${LOG_FILE} + done fi print - "$*" | while read -r LOG_LINE do - print -u2 "ERROR:" "${LOG_LINE}" + print -u2 "ERROR:" "${LOG_LINE}" done fi @@ -267,79 +268,79 @@ HAS_REPORT_STD=0 for FFILE in $(ls -1 ${FPATH_PARENT}/core/*.sh 2>/dev/null | grep -v "include_" 2>/dev/null) do case "${FFILE}" in - *display_csv.sh) - HAS_DISPLAY_CSV=1 - (( ARG_DEBUG > 0 )) && debug "display_csv plugin is available" - ;; - *display_init.sh) - HAS_DISPLAY_INIT=1 - (( ARG_DEBUG > 0 )) && debug "display_init plugin is available" - ;; - *display_json.sh) - HAS_DISPLAY_JSON=1 - (( ARG_DEBUG > 0 )) && debug "display_json plugin is available" - ;; - *display_terse.sh) - HAS_DISPLAY_TERSE=1 - (( ARG_DEBUG > 0 )) && debug "display_terse plugin is available" - ;; - *display_zenoss.sh) - HAS_DISPLAY_ZENOSS=1 - (( ARG_DEBUG > 0 )) && debug "display_zenoss plugin is available" - ;; - *display_custom1.sh) - HAS_DISPLAY_CUSTOM1=1 - (( ARG_DEBUG > 0 )) && debug "display_custom1 plugin is available" - ;; - *display_custom2.sh) - HAS_DISPLAY_CUSTOM2=1 - (( ARG_DEBUG > 0 )) && debug "display_custom2 plugin is available" - ;; - *display_custom3.sh) - HAS_DISPLAY_CUSTOM3=1 - (( ARG_DEBUG > 0 )) && debug "display_custom3 plugin is available" - ;; - *display_custom4.sh) - HAS_DISPLAY_CUSTOM4=1 - (( ARG_DEBUG > 0 )) && debug "display_custom4 plugin is available" - ;; - *display_custom5.sh) - HAS_DISPLAY_CUSTOM5=1 - (( ARG_DEBUG > 0 )) && debug "display_custom5 plugin is available" - ;; - *display_custom6.sh) - HAS_DISPLAY_CUSTOM6=1 - (( ARG_DEBUG > 0 )) && debug "display_custom6 plugin is available" - ;; - *display_custom7.sh) - HAS_DISPLAY_CUSTOM7=1 - (( ARG_DEBUG > 0 )) && debug "display_custom7 plugin is available" - ;; - *display_custom8.sh) - HAS_DISPLAY_CUSTOM8=1 - (( ARG_DEBUG > 0 )) && debug "display_custom8 plugin is available" - ;; - *display_custom9.sh) - HAS_DISPLAY_CUSTOM9=1 - (( ARG_DEBUG > 0 )) && debug "display_custom9 plugin is available" - ;; - *notify_mail.sh) - HAS_NOTIFY_MAIL=1 - (( ARG_DEBUG > 0 )) && debug "notify_mail plugin is available" - ;; - *notify_sms.sh) - HAS_NOTIFY_SMS=1 - (( ARG_DEBUG > 0 )) && debug "notify_sms plugin is available" - ;; - *notify_eif.sh) - HAS_NOTIFY_EIF=1 - (( ARG_DEBUG > 0 )) && debug "notify_eif plugin is available" - ;; - *report_std.sh) - # shellcheck disable=SC2034 - HAS_REPORT_STD=1 - (( ARG_DEBUG > 0 )) && debug "report_std plugin is available" - ;; + *display_csv.sh) + HAS_DISPLAY_CSV=1 + (( ARG_DEBUG > 0 )) && debug "display_csv plugin is available" + ;; + *display_init.sh) + HAS_DISPLAY_INIT=1 + (( ARG_DEBUG > 0 )) && debug "display_init plugin is available" + ;; + *display_json.sh) + HAS_DISPLAY_JSON=1 + (( ARG_DEBUG > 0 )) && debug "display_json plugin is available" + ;; + *display_terse.sh) + HAS_DISPLAY_TERSE=1 + (( ARG_DEBUG > 0 )) && debug "display_terse plugin is available" + ;; + *display_zenoss.sh) + HAS_DISPLAY_ZENOSS=1 + (( ARG_DEBUG > 0 )) && debug "display_zenoss plugin is available" + ;; + *display_custom1.sh) + HAS_DISPLAY_CUSTOM1=1 + (( ARG_DEBUG > 0 )) && debug "display_custom1 plugin is available" + ;; + *display_custom2.sh) + HAS_DISPLAY_CUSTOM2=1 + (( ARG_DEBUG > 0 )) && debug "display_custom2 plugin is available" + ;; + *display_custom3.sh) + HAS_DISPLAY_CUSTOM3=1 + (( ARG_DEBUG > 0 )) && debug "display_custom3 plugin is available" + ;; + *display_custom4.sh) + HAS_DISPLAY_CUSTOM4=1 + (( ARG_DEBUG > 0 )) && debug "display_custom4 plugin is available" + ;; + *display_custom5.sh) + HAS_DISPLAY_CUSTOM5=1 + (( ARG_DEBUG > 0 )) && debug "display_custom5 plugin is available" + ;; + *display_custom6.sh) + HAS_DISPLAY_CUSTOM6=1 + (( ARG_DEBUG > 0 )) && debug "display_custom6 plugin is available" + ;; + *display_custom7.sh) + HAS_DISPLAY_CUSTOM7=1 + (( ARG_DEBUG > 0 )) && debug "display_custom7 plugin is available" + ;; + *display_custom8.sh) + HAS_DISPLAY_CUSTOM8=1 + (( ARG_DEBUG > 0 )) && debug "display_custom8 plugin is available" + ;; + *display_custom9.sh) + HAS_DISPLAY_CUSTOM9=1 + (( ARG_DEBUG > 0 )) && debug "display_custom9 plugin is available" + ;; + *notify_mail.sh) + HAS_NOTIFY_MAIL=1 + (( ARG_DEBUG > 0 )) && debug "notify_mail plugin is available" + ;; + *notify_sms.sh) + HAS_NOTIFY_SMS=1 + (( ARG_DEBUG > 0 )) && debug "notify_sms plugin is available" + ;; + *notify_eif.sh) + HAS_NOTIFY_EIF=1 + (( ARG_DEBUG > 0 )) && debug "notify_eif plugin is available" + ;; + *report_std.sh) + # shellcheck disable=SC2034 + HAS_REPORT_STD=1 + (( ARG_DEBUG > 0 )) && debug "report_std plugin is available" + ;; esac done @@ -348,134 +349,134 @@ done if [[ -n "${ARG_DISPLAY}" ]] then case "${ARG_DISPLAY}" in - csv) # csv format - if (( HAS_DISPLAY_CSV == 1 )) - then - DO_DISPLAY_CSV=1 - ARG_VERBOSE=0 - else - warn "csv plugin for '--display' not present" - fi - ;; - init) # init/boot format - if (( HAS_DISPLAY_INIT == 1 )) - then - DO_DISPLAY_INIT=1 - ARG_VERBOSE=0 - else - warn "init plugin for '--display' not present" - fi - ;; - json) # json format - if (( HAS_DISPLAY_JSON == 1 )) - then - DO_DISPLAY_JSON=1 - ARG_VERBOSE=0 - else - warn "json plugin for '--display' not present" - fi - ;; - terse) # terse format - if (( HAS_DISPLAY_TERSE == 1 )) - then - DO_DISPLAY_TERSE=1 - ARG_VERBOSE=0 - else - warn "terse plugin for '--display' not present" - fi - ;; - zenoss) # zenoss format - if (( HAS_DISPLAY_ZENOSS == 1 )) - then - DO_DISPLAY_ZENOSS=1 - ARG_VERBOSE=0 - else - warn "zenoss plugin for '--display' not present" - fi - ;; - custom1) # custom1 format - if (( HAS_DISPLAY_CUSTOM1 == 1 )) - then - DO_DISPLAY_CUSTOM1=1 - ARG_VERBOSE=0 - else - warn "custom1 plugin for '--display' not present" - fi - ;; - custom2) # custom2 format - if (( HAS_DISPLAY_CUSTOM2 == 1 )) - then - DO_DISPLAY_CUSTOM2=1 - ARG_VERBOSE=0 - else - warn "custom2 plugin for '--display' not present" - fi - ;; - custom3) # custom3 format - if (( HAS_DISPLAY_CUSTOM3 == 1 )) - then - DO_DISPLAY_CUSTOM3=1 - ARG_VERBOSE=0 - else - warn "custom3 plugin for '--display' not present" - fi - ;; - custom4) # custom4 format - if (( HAS_DISPLAY_CUSTOM4 == 1 )) - then - DO_DISPLAY_CUSTOM4=1 - ARG_VERBOSE=0 - else - warn "custom4 plugin for '--display' not present" - fi - ;; - custom5) # custom5 format - if (( HAS_DISPLAY_CUSTOM5 == 1 )) - then - DO_DISPLAY_CUSTOM5=1 - ARG_VERBOSE=0 - else - warn "custom5 plugin for '--display' not present" - fi - ;; - custom6) # custom6 format - if (( HAS_DISPLAY_CUSTOM6 == 1 )) - then - DO_DISPLAY_CUSTOM6=1 - ARG_VERBOSE=0 - else - warn "custom6 plugin for '--display' not present" - fi - ;; - custom7) # custom7 format - if (( HAS_DISPLAY_CUSTOM7 == 1 )) - then - DO_DISPLAY_CUSTOM7=1 - ARG_VERBOSE=0 - else - warn "custom7 plugin for '--display' not present" - fi - ;; - custom8) # custom8 format - if (( HAS_DISPLAY_CUSTOM8 == 1 )) - then - DO_DISPLAY_CUSTOM8=1 - ARG_VERBOSE=0 - else - warn "custom8 plugin for '--display' not present" - fi - ;; - custom9) # custom9 format - if (( HAS_DISPLAY_CUSTOM9 == 1 )) - then - DO_DISPLAY_CUSTOM9=1 - ARG_VERBOSE=0 - else - warn "custom9 plugin for '--display' not present" - fi - ;; - *) # stdout default - ;; + csv) # csv format + if (( HAS_DISPLAY_CSV == 1 )) + then + DO_DISPLAY_CSV=1 + ARG_VERBOSE=0 + else + warn "csv plugin for '--display' not present" + fi + ;; + init) # init/boot format + if (( HAS_DISPLAY_INIT == 1 )) + then + DO_DISPLAY_INIT=1 + ARG_VERBOSE=0 + else + warn "init plugin for '--display' not present" + fi + ;; + json) # json format + if (( HAS_DISPLAY_JSON == 1 )) + then + DO_DISPLAY_JSON=1 + ARG_VERBOSE=0 + else + warn "json plugin for '--display' not present" + fi + ;; + terse) # terse format + if (( HAS_DISPLAY_TERSE == 1 )) + then + DO_DISPLAY_TERSE=1 + ARG_VERBOSE=0 + else + warn "terse plugin for '--display' not present" + fi + ;; + zenoss) # zenoss format + if (( HAS_DISPLAY_ZENOSS == 1 )) + then + DO_DISPLAY_ZENOSS=1 + ARG_VERBOSE=0 + else + warn "zenoss plugin for '--display' not present" + fi + ;; + custom1) # custom1 format + if (( HAS_DISPLAY_CUSTOM1 == 1 )) + then + DO_DISPLAY_CUSTOM1=1 + ARG_VERBOSE=0 + else + warn "custom1 plugin for '--display' not present" + fi + ;; + custom2) # custom2 format + if (( HAS_DISPLAY_CUSTOM2 == 1 )) + then + DO_DISPLAY_CUSTOM2=1 + ARG_VERBOSE=0 + else + warn "custom2 plugin for '--display' not present" + fi + ;; + custom3) # custom3 format + if (( HAS_DISPLAY_CUSTOM3 == 1 )) + then + DO_DISPLAY_CUSTOM3=1 + ARG_VERBOSE=0 + else + warn "custom3 plugin for '--display' not present" + fi + ;; + custom4) # custom4 format + if (( HAS_DISPLAY_CUSTOM4 == 1 )) + then + DO_DISPLAY_CUSTOM4=1 + ARG_VERBOSE=0 + else + warn "custom4 plugin for '--display' not present" + fi + ;; + custom5) # custom5 format + if (( HAS_DISPLAY_CUSTOM5 == 1 )) + then + DO_DISPLAY_CUSTOM5=1 + ARG_VERBOSE=0 + else + warn "custom5 plugin for '--display' not present" + fi + ;; + custom6) # custom6 format + if (( HAS_DISPLAY_CUSTOM6 == 1 )) + then + DO_DISPLAY_CUSTOM6=1 + ARG_VERBOSE=0 + else + warn "custom6 plugin for '--display' not present" + fi + ;; + custom7) # custom7 format + if (( HAS_DISPLAY_CUSTOM7 == 1 )) + then + DO_DISPLAY_CUSTOM7=1 + ARG_VERBOSE=0 + else + warn "custom7 plugin for '--display' not present" + fi + ;; + custom8) # custom8 format + if (( HAS_DISPLAY_CUSTOM8 == 1 )) + then + DO_DISPLAY_CUSTOM8=1 + ARG_VERBOSE=0 + else + warn "custom8 plugin for '--display' not present" + fi + ;; + custom9) # custom9 format + if (( HAS_DISPLAY_CUSTOM9 == 1 )) + then + DO_DISPLAY_CUSTOM9=1 + ARG_VERBOSE=0 + else + warn "custom9 plugin for '--display' not present" + fi + ;; + *) # stdout default + ;; esac fi # --notify @@ -485,20 +486,20 @@ then # variables back from the sub shell (only works for true ksh88/ksh93) for NOTIFY_OPTS in $(print "${ARG_NOTIFY}" | tr ',' ' ' 2>/dev/null) do - case "${NOTIFY_OPTS}" in - *eif*) # by ITM - DO_NOTIFY_EIF=1 - ;; - *mail*) # by mail - DO_NOTIFY_MAIL=1 - ;; - *sms*) # by sms - DO_NOTIFY_SMS=1 - ;; - *) # no valid option - die "you have specified an invalid option for '--notify'" - ;; - esac + case "${NOTIFY_OPTS}" in + *eif*) # by ITM + DO_NOTIFY_EIF=1 + ;; + *mail*) # by mail + DO_NOTIFY_MAIL=1 + ;; + *sms*) # by sms + DO_NOTIFY_SMS=1 + ;; + *) # no valid option + die "you have specified an invalid option for '--notify'" + ;; + esac done fi # --report @@ -508,14 +509,14 @@ then # variables back from the sub shell (only works for true ksh88/ksh93) for REPORT_OPTS in $(print "${ARG_REPORT}" | tr ',' ' ' 2>/dev/null) do - case "${REPORT_OPTS}" in - *std*) # STDOUT - DO_REPORT_STD=1 - ;; - *) # no valid option - die "you have specified an invalid option for '--report'" - ;; - esac + case "${REPORT_OPTS}" in + *std*) # STDOUT + DO_REPORT_STD=1 + ;; + *) # no valid option + die "you have specified an invalid option for '--report'" + ;; + esac done fi # --mail-to/--notify @@ -549,63 +550,63 @@ if (( DO_REPORT_STD > 0 )) then if (( ARG_DETAIL > 0 )) && [[ -z "${ARG_FAIL_ID}" ]] then - die "you must specify an unique value for '--id' when using '--detail'" + die "you must specify an unique value for '--id' when using '--detail'" fi if (( ARG_LAST > 0 )) && (( ARG_TODAY > 0 )) then - die "you cannot specify '--last' with '--today'" + die "you cannot specify '--last' with '--today'" fi if (( ARG_LAST > 0 )) && (( ARG_DETAIL > 0 )) then - die "you cannot specify '--last' with '--detail'" + die "you cannot specify '--last' with '--detail'" fi if (( ARG_LAST > 0 )) && (( ARG_REVERSE > 0 )) then - die "you cannot specify '--last' with '--detail'" + die "you cannot specify '--last' with '--detail'" fi if (( ARG_LAST > 0 )) && [[ -n "${ARG_FAIL_ID}" ]] then - die "you cannot specify '--last' with '--id'" + die "you cannot specify '--last' with '--id'" fi if (( ARG_LAST > 0 )) && [[ -n "${ARG_OLDER}" ]] then - die "you cannot specify '--last' with '--older'" + die "you cannot specify '--last' with '--older'" fi if (( ARG_LAST > 0 )) && [[ -n "${ARG_NEWER}" ]] then - die "you cannot specify '--last' with '--newer'" + die "you cannot specify '--last' with '--newer'" fi if (( ARG_TODAY > 0 )) && (( ARG_DETAIL > 0 )) then - die "you cannot specify '--today' with '--detail'" + die "you cannot specify '--today' with '--detail'" fi if (( ARG_TODAY > 0 )) && (( ARG_REVERSE > 0 )) then - die "you cannot specify '--today' with '--detail'" + die "you cannot specify '--today' with '--detail'" fi if (( ARG_TODAY > 0 )) && [[ -n "${ARG_FAIL_ID}" ]] then - die "you cannot specify '--today' with '--id'" + die "you cannot specify '--today' with '--id'" fi if (( ARG_TODAY > 0 )) && [[ -n "${ARG_OLDER}" ]] then - die "you cannot specify '--today' with '--older" + die "you cannot specify '--today' with '--older" fi if (( ARG_TODAY > 0 )) && [[ -n "${ARG_NEWER}" ]] then - die "you cannot specify '--today' with '--newer'" + die "you cannot specify '--today' with '--newer'" fi if [[ -n "${ARG_OLDER}" ]] && [[ -n "${ARG_NEWER}" ]] then - die "you cannot use '--older' with '--newer'" + die "you cannot use '--older' with '--newer'" fi if [[ -n "${ARG_FAIL_ID}" ]] && [[ -n "${ARG_OLDER}" ]] then - die "you cannot use '--id' with '--older'" + die "you cannot use '--id' with '--older'" fi if [[ -n "${ARG_FAIL_ID}" ]] && [[ -n "${ARG_NEWER}" ]] then - die "you cannot use '--id' with '--newer'" + die "you cannot use '--id' with '--newer'" fi fi if (( DO_REPORT_STD == 0 )) && (( ARG_LAST > 0 )) @@ -678,7 +679,7 @@ do # shellcheck disable=SC2181 if (( $? == 0 )) then - ls "${FDIR}/${EXISTS_HC}" >/dev/null 2>&1 && EXISTS_RC=1 + ls "${FDIR}/${EXISTS_HC}" >/dev/null 2>&1 && EXISTS_RC=1 fi done @@ -756,119 +757,119 @@ do # rewrite if needed if (( ERROR_COUNT > 0 )) then - : >${TMP_FILE} 2>/dev/null - cat ${FIX_FILE} 2>/dev/null | awk -F"${LOG_SEP}" -v OFS="${LOG_SEP}" ' + : >${TMP_FILE} 2>/dev/null + awk -F"${LOG_SEP}" -v OFS="${LOG_SEP}" ' - BEGIN { max_log_fields = '"${NUM_LOG_FIELDS}"' - max_fields = (max_log_fields - 1) * 2 - glue_field = max_log_fields - 1 - } + BEGIN { max_log_fields = '"${NUM_LOG_FIELDS}"' + max_fields = (max_log_fields - 1) * 2 + glue_field = max_log_fields - 1 + } - # Fix log lines that were smashed together because of unatomic appends - # This can lead to 4 distinct cases that we need to rewrite based on - # whether a FAIL_ID is present in each part of the log line. - # Following examples are based on a log file with 5 standard fields: - # case 1: NO (FAIL_ID) + NO (FAIL_ID) -> 9 fields - # case 2: NO (FAIL_ID) + YES (FAIL_ID) -> 10 fields - # case 3: YES (FAIL_ID) + NO (FAIL_ID) -> 10 fields - # case 4: YES (FAIL_ID) + YES (FAIL_ID) -> 11 fields + # Fix log lines that were smashed together because of unatomic appends + # This can lead to 4 distinct cases that we need to rewrite based on + # whether a FAIL_ID is present in each part of the log line. + # Following examples are based on a log file with 5 standard fields: + # case 1: NO (FAIL_ID) + NO (FAIL_ID) -> 9 fields + # case 2: NO (FAIL_ID) + YES (FAIL_ID) -> 10 fields + # case 3: YES (FAIL_ID) + NO (FAIL_ID) -> 10 fields + # case 4: YES (FAIL_ID) + YES (FAIL_ID) -> 11 fields - { - if (NF > max_log_fields) { - # rogue line that needs rewriting - if (NF < max_fields) { - # case 1 - for (i=1;i${TMP_FILE} 2>/dev/null + { + if (NF > max_log_fields) { + # rogue line that needs rewriting + if (NF < max_fields) { + # case 1 + for (i=1;i${TMP_FILE} 2>/dev/null - # count after rewrite (include empty lines again in the count) - TMP_COUNT=$(wc -l ${TMP_FILE} 2>/dev/null | cut -f1 -d' ' 2>/dev/null) - TMP_COUNT=$(( TMP_COUNT + EMPTY_COUNT )) + # count after rewrite (include empty lines again in the count) + TMP_COUNT=$(wc -l ${TMP_FILE} 2>/dev/null | cut -f1 -d' ' 2>/dev/null) + TMP_COUNT=$(( TMP_COUNT + EMPTY_COUNT )) - # bail out when we do not have enough records - if (( TMP_COUNT < STASH_COUNT )) - then - warn "found inconsistent record count (${TMP_COUNT}<${STASH_COUNT}), aborting" - return 2 - fi + # bail out when we do not have enough records + if (( TMP_COUNT < STASH_COUNT )) + then + warn "found inconsistent record count (${TMP_COUNT}<${STASH_COUNT}), aborting" + return 2 + fi - # swap log file (but create a backup first!) - cp -p ${FIX_FILE} ${SAVE_TMP_FILE} 2>/dev/null - # shellcheck disable=SC2181 - if (( $? == 0 )) - then - mv ${TMP_FILE} ${FIX_FILE} 2>/dev/null - # shellcheck disable=SC2181 - if (( $? > 0 )) - then - warn "failed to move/update log file, rolling back" - mv ${SAVE_TMP_FILE} ${FIX_FILE} 2>/dev/null - return 2 - fi - FIX_RC=1 - else - warn "failed to create a backup of original log file, aborting" - return 2 - fi - - # clean up temporary file(s) - rm -f ${SAVE_TMP_FILE} ${TMP_FILE} >/dev/null 2>&1 + # swap log file (but create a backup first!) + cp -p ${FIX_FILE} ${SAVE_TMP_FILE} 2>/dev/null + # shellcheck disable=SC2181 + if (( $? == 0 )) + then + mv ${TMP_FILE} ${FIX_FILE} 2>/dev/null + # shellcheck disable=SC2181 + if (( $? > 0 )) + then + warn "failed to move/update log file, rolling back" + mv ${SAVE_TMP_FILE} ${FIX_FILE} 2>/dev/null + return 2 + fi + FIX_RC=1 else - log "no fixing needed for ${FIX_FILE}" + warn "failed to create a backup of original log file, aborting" + return 2 + fi + + # clean up temporary file(s) + rm -f ${SAVE_TMP_FILE} ${TMP_FILE} >/dev/null 2>&1 + else + log "no fixing needed for ${FIX_FILE}" fi ERROR_COUNT=0 @@ -882,7 +883,8 @@ return ${FIX_RC} # DOES: handle HC results # EXPECTS: 1=HC name [string], $HC_MSG_FILE temporary file # RETURNS: 0 or $HC_STC_RC -# REQUIRES: die(), display_*(), notify_*(), warn() +# REQUIRES: data_contains_string(), data_is_numeric(), die(), display_*(), +# notify_*(), warn() function handle_hc { (( ARG_DEBUG > 0 && ARG_DEBUG_LEVEL > 0 )) && set "${DEBUG_OPTS}" @@ -896,6 +898,15 @@ typeset ONE_MSG_TEXT="" typeset ONE_MSG_CUR_VAL="" typeset ONE_MSG_EXP_VAL="" typeset ALL_MSG_STC=0 +typeset HC_CACHE_LAST_DATE="" +typeset HC_CACHE_TODAY_DATE="" +typeset HC_CACHE_LAST_NOW="$(date '+%Y-%m-%d %H:%M:%S' 2>/dev/null)" # see also $HC_NOW +typeset HC_CACHE_TODAY_NOW="$(date '+%Y-%m-%d' 2>/dev/null)" # see also $HC_NOW +typeset HC_REPORT_CACHE_LAST_STUB="${STATE_PERM_DIR}/cache.report-last" +typeset HC_REPORT_CACHE_LAST_FILE="" +typeset HC_REPORT_CACHE_TODAY_FILE="${STATE_PERM_DIR}/cache.report-today" +typeset LOG_STRING_GOOD="" +typeset LOG_STRING_FAIL="" if [[ -s ${HC_MSG_FILE} ]] then @@ -906,9 +917,9 @@ then # DEBUG: dump TMP file if (( ARG_DEBUG > 0 )) then - debug "begin dumping plugin messages file (${HC_MSG_FILE})" - print "${HC_MSG_VAR}" - debug "end dumping plugin messages file (${HC_MSG_FILE})" + debug "begin dumping plugin messages file (${HC_MSG_FILE})" + print "${HC_MSG_VAR}" + debug "end dumping plugin messages file (${HC_MSG_FILE})" fi # determine ALL_MSG_STC (sum of all STCs) @@ -919,9 +930,9 @@ else # nothing to do, respect current EXIT_CODE if (( EXIT_CODE > 0 )) then - return ${EXIT_CODE} + return ${EXIT_CODE} else - return 0 + return 0 fi fi @@ -930,175 +941,175 @@ if [[ -n "${HC_MSG_VAR}" ]] then if (( DO_DISPLAY_CSV == 1 )) then - if (( HAS_DISPLAY_CSV == 1 )) - then - # call plugin - display_csv "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_csv plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_CSV == 1 )) + then + # call plugin + display_csv "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_csv plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_INIT == 1 )) then - if (( HAS_DISPLAY_INIT == 1 )) - then - # call plugin - display_init "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_init plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_INIT == 1 )) + then + # call plugin + display_init "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_init plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_JSON == 1 )) then - if (( HAS_DISPLAY_JSON == 1 )) - then - # call plugin - display_json "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_json plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_JSON == 1 )) + then + # call plugin + display_json "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_json plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_TERSE == 1 )) then - if (( HAS_DISPLAY_TERSE == 1 )) - then - # call plugin - display_terse "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_terse plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_TERSE == 1 )) + then + # call plugin + display_terse "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_terse plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_ZENOSS == 1 )) then - if (( HAS_DISPLAY_ZENOSS == 1 )) - then - # call plugin - display_zenoss "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_zenoss plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_ZENOSS == 1 )) + then + # call plugin + display_zenoss "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_zenoss plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_CUSTOM1 == 1 )) then - if (( HAS_DISPLAY_CUSTOM1 == 1 )) - then - # call plugin - display_custom1 "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_custom1 plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_CUSTOM1 == 1 )) + then + # call plugin + display_custom1 "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_custom1 plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_CUSTOM2 == 1 )) then - if (( HAS_DISPLAY_CUSTOM2 == 1 )) - then - # call plugin - display_custom2 "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_custom2 plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_CUSTOM2 == 1 )) + then + # call plugin + display_custom2 "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_custom2 plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_CUSTOM3 == 1 )) then - if (( HAS_DISPLAY_CUSTOM3 == 1 )) - then - # call plugin - display_custom3 "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_custom3 plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_CUSTOM3 == 1 )) + then + # call plugin + display_custom3 "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_custom3 plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_CUSTOM4 == 1 )) then - if (( HAS_DISPLAY_CUSTOM4 == 1 )) - then - # call plugin - display_custom4 "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_custom4 plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_CUSTOM4 == 1 )) + then + # call plugin + display_custom4 "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_custom4 plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_CUSTOM5 == 1 )) then - if (( HAS_DISPLAY_CUSTOM5 == 1 )) - then - # call plugin - display_custom5 "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_custom5 plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_CUSTOM5 == 1 )) + then + # call plugin + display_custom5 "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_custom5 plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_CUSTOM6 == 1 )) then - if (( HAS_DISPLAY_CUSTOM6 == 1 )) - then - # call plugin - display_custom6 "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_custom6 plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_CUSTOM6 == 1 )) + then + # call plugin + display_custom6 "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_custom6 plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_CUSTOM7 == 1 )) then - if (( HAS_DISPLAY_CUSTOM7 == 1 )) - then - # call plugin - display_custom7 "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_custom7 plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_CUSTOM7 == 1 )) + then + # call plugin + display_custom7 "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_custom7 plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_CUSTOM8 == 1 )) then - if (( HAS_DISPLAY_CUSTOM8 == 1 )) - then - # call plugin - display_custom8 "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_custom8 plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_CUSTOM8 == 1 )) + then + # call plugin + display_custom8 "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "display_custom8 plugin is not available, cannot display_results!" + fi elif (( DO_DISPLAY_CUSTOM9 == 1 )) then - if (( HAS_DISPLAY_CUSTOM9 == 1 )) - then - # call plugin - display_custom9 "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "display_custom9 plugin is not available, cannot display_results!" - fi + if (( HAS_DISPLAY_CUSTOM9 == 1 )) + then + # call plugin + display_custom9 "${HC_NAME}" "${HC_FAIL_ID}" else - # default STDOUT - if (( ARG_VERBOSE > 0 )) - then - print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read -r ONE_MSG_STC ONE_MSG_TIME ONE_MSG_TEXT ONE_MSG_CUR_VAL ONE_MSG_EXP_VAL - do - # magically unquote if needed - if [[ -n "${ONE_MSG_TEXT}" ]] - then - data_contains_string "${ONE_MSG_TEXT}" "${MAGIC_QUOTE}" - # shellcheck disable=SC2181 - if (( $? > 0 )) - then - ONE_MSG_TEXT=$(data_magic_unquote "${ONE_MSG_TEXT}") - fi - fi - if [[ -n "${ONE_MSG_CUR_VAL}" ]] - then - data_contains_string "${ONE_MSG_CUR_VAL}" "${MAGIC_QUOTE}" - # shellcheck disable=SC2181 - if (( $? > 0 )) - then - ONE_MSG_CUR_VAL=$(data_magic_unquote "${ONE_MSG_CUR_VAL}") - fi - fi - if [[ -n "${ONE_MSG_EXP_VAL}" ]] - then - data_contains_string "${ONE_MSG_EXP_VAL}" "${MAGIC_QUOTE}" - # shellcheck disable=SC2181 - if (( $? > 0 )) - then - ONE_MSG_EXP_VAL=$(data_magic_unquote "${ONE_MSG_EXP_VAL}") - fi - fi - printf "%s" "INFO: ${HC_NAME} [STC=${ONE_MSG_STC}]: ${ONE_MSG_TEXT}" - if (( ONE_MSG_STC > 0 )) - then - # shellcheck disable=SC1117 - printf " %s\n" "[FAIL_ID=${HC_FAIL_ID}]" - else - # shellcheck disable=SC1117 - printf "\n" - fi - done - fi + warn "display_custom9 plugin is not available, cannot display_results!" + fi + else + # default STDOUT + if (( ARG_VERBOSE > 0 )) + then + print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read -r ONE_MSG_STC ONE_MSG_TIME ONE_MSG_TEXT ONE_MSG_CUR_VAL ONE_MSG_EXP_VAL + do + # magically unquote if needed + if [[ -n "${ONE_MSG_TEXT}" ]] + then + data_contains_string "${ONE_MSG_TEXT}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 + if (( $? > 0 )) + then + ONE_MSG_TEXT=$(data_magic_unquote "${ONE_MSG_TEXT}") + fi + fi + if [[ -n "${ONE_MSG_CUR_VAL}" ]] + then + data_contains_string "${ONE_MSG_CUR_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 + if (( $? > 0 )) + then + ONE_MSG_CUR_VAL=$(data_magic_unquote "${ONE_MSG_CUR_VAL}") + fi + fi + if [[ -n "${ONE_MSG_EXP_VAL}" ]] + then + data_contains_string "${ONE_MSG_EXP_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 + if (( $? > 0 )) + then + ONE_MSG_EXP_VAL=$(data_magic_unquote "${ONE_MSG_EXP_VAL}") + fi + fi + printf "%s" "INFO: ${HC_NAME} [STC=${ONE_MSG_STC}]: ${ONE_MSG_TEXT}" + if (( ONE_MSG_STC > 0 )) + then + # shellcheck disable=SC1117 + printf " %s\n" "[FAIL_ID=${HC_FAIL_ID}]" + else + # shellcheck disable=SC1117 + printf "\n" + fi + done + fi fi fi @@ -1108,132 +1119,212 @@ then # log routine (combined STC=0 or <>0) print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read -r ONE_MSG_STC ONE_MSG_TIME ONE_MSG_TEXT ONE_MSG_CUR_VAL ONE_MSG_EXP_VAL do - # magically unquote if needed - if [[ -n "${ONE_MSG_TEXT}" ]] - then - data_contains_string "${ONE_MSG_TEXT}" "${MAGIC_QUOTE}" - # shellcheck disable=SC2181 - if (( $? > 0 )) - then - ONE_MSG_TEXT=$(data_magic_unquote "${ONE_MSG_TEXT}") - fi - fi - if [[ -n "${ONE_MSG_CUR_VAL}" ]] - then - data_contains_string "${ONE_MSG_CUR_VAL}" "${MAGIC_QUOTE}" - # shellcheck disable=SC2181 - if (( $? > 0 )) - then - ONE_MSG_CUR_VAL=$(data_magic_unquote "${ONE_MSG_CUR_VAL}") - fi - fi - if [[ -n "${ONE_MSG_EXP_VAL}" ]] - then - data_contains_string "${ONE_MSG_EXP_VAL}" "${MAGIC_QUOTE}" - # shellcheck disable=SC2181 - if (( $? > 0 )) - then - ONE_MSG_EXP_VAL=$(data_magic_unquote "${ONE_MSG_EXP_VAL}") - fi - fi - if (( ONE_MSG_STC > 0 )) - then - # do atomic log update - # shellcheck disable=SC1117 - printf "%s${LOG_SEP}%s${LOG_SEP}%s${LOG_SEP}%s${LOG_SEP}%s${LOG_SEP}\n" \ - "${ONE_MSG_TIME}" \ - "${HC_NAME}" \ - ${ONE_MSG_STC} \ - "${ONE_MSG_TEXT}" \ - "${HC_FAIL_ID}" >>${HC_LOG} - # RC handling (max/sum/count) - if (( ARG_FLIP_RC > 0 )) - then - case "${ARG_WITH_RC}" in - max|MAX|Max) - (( ONE_MSG_STC > HC_STC_RC )) && HC_STC_RC=${ONE_MSG_STC} - ;; - sum|SUM|Sum) - HC_STC_RC=$(( HC_STC_RC + ONE_MSG_STC )) - ;; - *) - # count option (default) - HC_STC_RC=$(( HC_STC_RC + 1 )) - ;; - esac - else - HC_STC_RC=$(( HC_STC_RC + 1 )) - fi - else - # do atomic log update - # shellcheck disable=SC1117 - printf "%s${LOG_SEP}%s${LOG_SEP}%s${LOG_SEP}%s${LOG_SEP}\n" \ - "${ONE_MSG_TIME}" \ - "${HC_NAME}" \ - ${ONE_MSG_STC} \ - "${ONE_MSG_TEXT}" >>${HC_LOG} - fi + # magically unquote if needed + if [[ -n "${ONE_MSG_TEXT}" ]] + then + data_contains_string "${ONE_MSG_TEXT}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 + if (( $? > 0 )) + then + ONE_MSG_TEXT=$(data_magic_unquote "${ONE_MSG_TEXT}") + fi + fi + if [[ -n "${ONE_MSG_CUR_VAL}" ]] + then + data_contains_string "${ONE_MSG_CUR_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 + if (( $? > 0 )) + then + ONE_MSG_CUR_VAL=$(data_magic_unquote "${ONE_MSG_CUR_VAL}") + fi + fi + if [[ -n "${ONE_MSG_EXP_VAL}" ]] + then + data_contains_string "${ONE_MSG_EXP_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 + if (( $? > 0 )) + then + ONE_MSG_EXP_VAL=$(data_magic_unquote "${ONE_MSG_EXP_VAL}") + fi + fi + + if (( ONE_MSG_STC > 0 )) + then + # build log string + LOG_STRING_FAIL=$(printf "%s${LOG_SEP}%s${LOG_SEP}%s${LOG_SEP}%s${LOG_SEP}%s${LOG_SEP}" "${ONE_MSG_TIME}" "${HC_NAME}" ${ONE_MSG_STC} "${ONE_MSG_TEXT}" "${HC_FAIL_ID}") + + # do atomic log update + # shellcheck disable=SC1117 + print "${LOG_STRING_FAIL}" >>${HC_LOG} + + # cache report (--report --last) + HC_REPORT_CACHE_LAST_FILE="${HC_REPORT_CACHE_LAST_STUB}-${HC_NAME}" + case "${HC_REPORT_CACHE_LAST}" in + Yes|yes|YES) + # fetch date of last cache entry (did we rollover from last HC event?) + HC_CACHE_LAST_DATE=$(tail -n 1 ${HC_REPORT_CACHE_LAST_FILE} 2>/dev/null | cut -f1 -d${LOG_SEP} 2>/dev/null) + if [[ -z "${HC_CACHE_LAST_DATE}" ]] || [[ "${HC_CACHE_LAST_DATE}" != "${HC_CACHE_LAST_NOW}" ]] + then + # set and update cache file + print "${LOG_STRING_FAIL}" >${HC_REPORT_CACHE_LAST_FILE} + else + # append cache file + print "${LOG_STRING_FAIL}" >>${HC_REPORT_CACHE_LAST_FILE} + fi + ;; + *) + # remove cache file if it exists + [[ -f ${HC_REPORT_CACHE_LAST_FILE} ]] && rm -f ${HC_REPORT_CACHE_LAST_FILE} >/dev/null 2>/dev/null + ;; + esac + # cache report (--report --today) + case "${HC_REPORT_CACHE_TODAY}" in + Yes|yes|YES) + # fetch date of last cache entry (did we rollover midnight?) + HC_CACHE_TODAY_DATE=$(tail -n 1 ${HC_REPORT_CACHE_TODAY_FILE} 2>/dev/null | cut -f1 -d${LOG_SEP} 2>/dev/null | awk '{ print $1 }' 2>/dev/null) + if [[ -z "${HC_CACHE_TODAY_DATE}" ]] || [[ "${HC_CACHE_TODAY_DATE}" != "${HC_CACHE_TODAY_NOW}" ]] + then + # rotate and update cache file + (( ARG_DEBUG > 0 )) && debug "rotating today's cache file at ${HC_REPORT_CACHE_TODAY_FILE}" + print "${LOG_STRING_FAIL}" >${HC_REPORT_CACHE_TODAY_FILE} + else + # append cache file + print "${LOG_STRING_FAIL}" >>${HC_REPORT_CACHE_TODAY_FILE} + fi + ;; + *) + # remove cache file if it exists + [[ -f ${HC_REPORT_CACHE_TODAY_FILE} ]] && rm -f ${HC_REPORT_CACHE_TODAY_FILE} >/dev/null 2>/dev/null + ;; + esac + # RC handling (max/sum/count) + if (( ARG_FLIP_RC > 0 )) + then + case "${ARG_WITH_RC}" in + max|MAX|Max) + (( ONE_MSG_STC > HC_STC_RC )) && HC_STC_RC=${ONE_MSG_STC} + ;; + sum|SUM|Sum) + HC_STC_RC=$(( HC_STC_RC + ONE_MSG_STC )) + ;; + *) + # count option (default) + HC_STC_RC=$(( HC_STC_RC + 1 )) + ;; + esac + else + HC_STC_RC=$(( HC_STC_RC + 1 )) + fi + else + # build log string + LOG_STRING_GOOD=$(printf "%s${LOG_SEP}%s${LOG_SEP}%s${LOG_SEP}%s${LOG_SEP}" "${ONE_MSG_TIME}" "${HC_NAME}" ${ONE_MSG_STC} "${ONE_MSG_TEXT}") + + # do atomic log update + # shellcheck disable=SC1117 + print "${LOG_STRING_GOOD}" >>${HC_LOG} + + # cache report (--report --last) + HC_REPORT_CACHE_LAST_FILE="${HC_REPORT_CACHE_LAST_STUB}-${HC_NAME}" + case "${HC_REPORT_CACHE_LAST}" in + Yes|yes|YES) + # fetch date of last cache entry (did we rollover from last HC event?) + HC_CACHE_LAST_DATE=$(tail -n 1 ${HC_REPORT_CACHE_LAST_FILE} 2>/dev/null | cut -f1 -d${LOG_SEP} 2>/dev/null) + if [[ -z "${HC_CACHE_LAST_DATE}" ]] || [[ "${HC_CACHE_LAST_DATE}" != "${HC_CACHE_LAST_NOW}" ]] + then + # set and update cache file + print "${LOG_STRING_GOOD}" >${HC_REPORT_CACHE_LAST_FILE} + else + # append cache file + print "${LOG_STRING_GOOD}" >>${HC_REPORT_CACHE_LAST_FILE} + fi + ;; + *) + # remove cache file if it exists + [[ -f ${HC_REPORT_CACHE_LAST_FILE} ]] && rm -f ${HC_REPORT_CACHE_LAST_FILE} >/dev/null 2>/dev/null + ;; + esac + # cache report (--report --today) + case "${HC_REPORT_CACHE_TODAY}" in + Yes|yes|YES) + # fetch date of last cache last_entry (did we rollover midnight?) + HC_CACHE_TODAY_DATE=$(tail -n 1 ${HC_REPORT_CACHE_TODAY_FILE} 2>/dev/null | cut -f1 -d${LOG_SEP} 2>/dev/null | awk '{ print $1 }' 2>/dev/null) + if [[ -z "${HC_CACHE_TODAY_DATE}" ]] || [[ "${HC_CACHE_TODAY_DATE}" != "${HC_CACHE_TODAY_NOW}" ]] + then + # rotate and update cache file + (( ARG_DEBUG > 0 )) && debug "rotating today's cache file at ${HC_REPORT_CACHE_TODAY_FILE}" + print "${LOG_STRING_GOOD}" >${HC_REPORT_CACHE_TODAY_FILE} + else + # append cache file + print "${LOG_STRING_GOOD}" >>${HC_REPORT_CACHE_TODAY_FILE} + fi + ;; + *) + # remove cache file if it exists + [[ -f ${HC_REPORT_CACHE_TODAY_FILE} ]] && rm -f ${HC_REPORT_CACHE_TODAY_FILE} >/dev/null 2>/dev/null + ;; + esac + fi done # notify routine (combined STC > 0) if (( ALL_MSG_STC > 0 )) then - # save stdout/stderr to HC events location - if [[ -s ${HC_STDOUT_LOG} ]] || [[ -s ${HC_STDERR_LOG} ]] - then - # organize logs in sub-directories: YYYY/MM - mkdir -p "${EVENTS_DIR}/${DIR_PREFIX}/${HC_FAIL_ID}" >/dev/null 2>&1 || \ - die "failed to create event directory at ${1}" - if [[ -f ${HC_STDOUT_LOG} ]] - then - # cut off the path and the .$$ part from the file location - HC_STDOUT_LOG_SHORT="${HC_STDOUT_LOG##*/}" - mv ${HC_STDOUT_LOG} "${EVENTS_DIR}/${DIR_PREFIX}/${HC_FAIL_ID}/${HC_STDOUT_LOG_SHORT%.*}" >/dev/null 2>&1 || \ - die "failed to move ${HC_STDOUT_LOG} to event directory at ${1}" - fi - if [[ -f ${HC_STDERR_LOG} ]] - then - # cut off the path and the .$$ part from the file location - HC_STDERR_LOG_SHORT="${HC_STDERR_LOG##*/}" - mv ${HC_STDERR_LOG} "${EVENTS_DIR}/${DIR_PREFIX}/${HC_FAIL_ID}/${HC_STDERR_LOG_SHORT%.*}" >/dev/null 2>&1 || \ - die "failed to move ${HC_STDERR_LOG} to event directory at ${1}" - fi - fi + # save stdout/stderr to HC events location + if [[ -s ${HC_STDOUT_LOG} ]] || [[ -s ${HC_STDERR_LOG} ]] + then + # organize logs in sub-directories: YYYY/MM + mkdir -p "${EVENTS_DIR}/${DIR_PREFIX}/${HC_FAIL_ID}" >/reportdev/null 2>&1 || \ + die "failed to create event directory at ${1}" + if [[ -f ${HC_STDOUT_LOG} ]] + then + # cut off the path and the .$$ part from the file location + HC_STDOUT_LOG_SHORT="${HC_STDOUT_LOG##*/}" + mv ${HC_STDOUT_LOG} "${EVENTS_DIR}/${DIR_PREFIX}/${HC_FAIL_ID}/${HC_STDOUT_LOG_SHORT%.*}" >/dev/null 2>&1 || \ + die "failed to move ${HC_STDOUT_LOG} to event directory at ${1}" + fi + if [[ -f ${HC_STDERR_LOG} ]] + then + # cut off the path and the .$$ part from the file location + HC_STDERR_LOG_SHORT="${HC_STDERR_LOG##*/}" + mv ${HC_STDERR_LOG} "${EVENTS_DIR}/${DIR_PREFIX}/${HC_FAIL_ID}/${HC_STDERR_LOG_SHORT%.*}" >/dev/null 2>&1 || \ + die "failed to move ${HC_STDERR_LOG} to event directory at ${1}" + fi + fi - # notify if needed (i.e. when we have HC failures) - # by mail? - if (( DO_NOTIFY_MAIL == 1 )) - then - if (( HAS_NOTIFY_MAIL == 1 )) - then - # call plugin (pick up HC failure/stdout/stderr files in notify_mail()) - notify_mail "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "notify_mail plugin is not avaible, cannot send alert via e-mail!" - fi - fi - # by sms? - if (( DO_NOTIFY_SMS == 1 )) - then - if (( HAS_NOTIFY_SMS == 1 )) - then - # call plugin - notify_sms "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "notify_sms plugin is not avaible, cannot send alert via sms!" - fi - fi - # by EIF? - if (( DO_NOTIFY_EIF == 1 )) - then - if (( HAS_NOTIFY_EIF == 1 )) - then - # call plugin - notify_eif "${HC_NAME}" "${HC_FAIL_ID}" - else - warn "notify_sms plugin is not avaible, cannot send alert via sms!" - fi - fi + # notify if needed (i.e. when we have HC failures) + # by mail? + if (( DO_NOTIFY_MAIL == 1 )) + then + if (( HAS_NOTIFY_MAIL == 1 )) + then + # call plugin (pick up HC failure/stdout/stderr files in notify_mail()) + notify_mail "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "notify_mail plugin is not avaible, cannot send alert via e-mail!" + fi + fi + # by sms? + if (( DO_NOTIFY_SMS == 1 )) + then + if (( HAS_NOTIFY_SMS == 1 )) + then + # call plugin + notify_sms "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "notify_sms plugin is not avaible, cannot send alert via sms!" + fi + fi + # by EIF? + if (( DO_NOTIFY_EIF == 1 )) + then + if (( HAS_NOTIFY_EIF == 1 )) + then + # call plugin + notify_eif "${HC_NAME}" "${HC_FAIL_ID}" + else + warn "notify_sms plugin is not avaible, cannot send alert via sms!" + fi + fi fi fi @@ -1284,111 +1375,111 @@ typeset DISPLAY_STYLE="" DISPLAY_STYLE=$(_CONFIG_FILE="${HOST_CONFIG_FILE}" data_get_lvalue_from_config 'display_style') case "${DISPLAY_STYLE}" in csv|CSV) # csv format - if (( HAS_DISPLAY_CSV == 1 )) - then - DO_DISPLAY_CSV=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_CSV == 1 )) + then + DO_DISPLAY_CSV=1 + ARG_VERBOSE=0 + fi + ;; json|JSON) # json format - if (( HAS_DISPLAY_JSON == 1 )) - then - DO_DISPLAY_JSON=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_JSON == 1 )) + then + DO_DISPLAY_JSON=1 + ARG_VERBOSE=0 + fi + ;; terse|TERSE) # terse format - if (( HAS_DISPLAY_TERSE == 1 )) - then - DO_DISPLAY_TERSE=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_TERSE == 1 )) + then + DO_DISPLAY_TERSE=1 + ARG_VERBOSE=0 + fi + ;; zenoss|ZENOSS) # zenoss format - if (( HAS_DISPLAY_ZENOSS == 1 )) - then - DO_DISPLAY_ZENOSS=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_ZENOSS == 1 )) + then + DO_DISPLAY_ZENOSS=1 + ARG_VERBOSE=0 + fi + ;; custom1|CUSTOM1) # custom1 format - if (( HAS_DISPLAY_CUSTOM1 == 1 )) - then - DO_DISPLAY_CUSTOM1=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_CUSTOM1 == 1 )) + then + DO_DISPLAY_CUSTOM1=1 + ARG_VERBOSE=0 + fi + ;; custom2|CUSTOM2) # custom2 format - if (( HAS_DISPLAY_CUSTOM2 == 1 )) - then - DO_DISPLAY_CUSTOM2=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_CUSTOM2 == 1 )) + then + DO_DISPLAY_CUSTOM2=1 + ARG_VERBOSE=0 + fi + ;; custom3|CUSTOM3) # custom3 format - if (( HAS_DISPLAY_CUSTOM3 == 1 )) - then - DO_DISPLAY_CUSTOM3=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_CUSTOM3 == 1 )) + then + DO_DISPLAY_CUSTOM3=1 + ARG_VERBOSE=0 + fi + ;; custom4|CUSTOM4) # custom4 format - if (( HAS_DISPLAY_CUSTOM4 == 1 )) - then - DO_DISPLAY_CUSTOM4=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_CUSTOM4 == 1 )) + then + DO_DISPLAY_CUSTOM4=1 + ARG_VERBOSE=0 + fi + ;; custom5|CUSTOM5) # custom5 format - if (( HAS_DISPLAY_CUSTOM5 == 1 )) - then - DO_DISPLAY_CUSTOM5=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_CUSTOM5 == 1 )) + then + DO_DISPLAY_CUSTOM5=1 + ARG_VERBOSE=0 + fi + ;; custom6|CUSTOM6) # custom6 format - if (( HAS_DISPLAY_CUSTOM6 == 1 )) - then - DO_DISPLAY_CUSTOM6=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_CUSTOM6 == 1 )) + then + DO_DISPLAY_CUSTOM6=1 + ARG_VERBOSE=0 + fi + ;; custom7|CUSTOM7) # custom7 format - if (( HAS_DISPLAY_CUSTOM7 == 1 )) - then - DO_DISPLAY_CUSTOM7=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_CUSTOM7 == 1 )) + then + DO_DISPLAY_CUSTOM7=1 + ARG_VERBOSE=0 + fi + ;; custom8|CUSTOM8) # custom8 format - if (( HAS_DISPLAY_CUSTOM8 == 1 )) - then - DO_DISPLAY_CUSTOM8=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_CUSTOM8 == 1 )) + then + DO_DISPLAY_CUSTOM8=1 + ARG_VERBOSE=0 + fi + ;; custom9|CUSTOM9) # custom9 format - if (( HAS_DISPLAY_CUSTOM9 == 1 )) - then - DO_DISPLAY_CUSTOM9=1 - ARG_VERBOSE=0 - fi - ;; + if (( HAS_DISPLAY_CUSTOM9 == 1 )) + then + DO_DISPLAY_CUSTOM9=1 + ARG_VERBOSE=0 + fi + ;; *) # init/boot default, stdout fallback - if (( HAS_DISPLAY_INIT == 1 )) - then - DO_DISPLAY_INIT=1 - ARG_VERBOSE=0 - else - ARG_VERBOSE=1 - warn "default boot/init display plugin not present" - fi + if (( HAS_DISPLAY_INIT == 1 )) + then + DO_DISPLAY_INIT=1 + ARG_VERBOSE=0 + else + ARG_VERBOSE=1 + warn "default boot/init display plugin not present" + fi esac # mangle $ARG_HC to build the full list of HCs to be executed ARG_HC="" grep -i '^hc:' ${HOST_CONFIG_FILE} 2>/dev/null |\ - while IFS=':' read _ HC_EXEC _ _ + while IFS=':' read -r _ HC_EXEC _ _ do ARG_HC="${ARG_HC},${HC_EXEC}" done @@ -1416,12 +1507,12 @@ HC_OK=$(print "${HC_PLATFORMS}" | grep -c "${OS_NAME}" 2>/dev/null) # check version of HC plugin case "${HC_VERSION}" in [0-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]) - # OK - (( ARG_DEBUG > 0 )) && debug "HC plugin ${1} has version ${HC_VERSION}" - ;; + # OK + (( ARG_DEBUG > 0 )) && debug "HC plugin ${1} has version ${HC_VERSION}" + ;; *) - die "version of the HC plugin ${1} is not in YYYY-MM-DD format (${HC_VERSION})" - ;; + die "version of the HC plugin ${1} is not in YYYY-MM-DD format (${HC_VERSION})" + ;; esac return 0 @@ -1438,28 +1529,30 @@ function is_scheduled (( ARG_DEBUG > 0 && ARG_DEBUG_LEVEL > 0 )) && set "${DEBUG_OPTS}" typeset CRON_HC="${1}" typeset CRON_COUNT=0 -typeset CRON_SYS_LOCATIONS='/etc/crontab /etc/cron.d/*' -typeset CRON_ANACRON_LOCATIONS='/etc/anacrontab /etc/cron.*' +typeset CRON_SYS_LOCATIONS="/etc/crontab /etc/cron.d/*" +typeset CRON_ANACRON_LOCATIONS="/etc/anacrontab /etc/cron.*" # check for a scheduled job case "${OS_NAME}" in "Linux") - # check default root crontab - CRON_COUNT=$(crontab -l 2>/dev/null | grep -c -E -e "^[^#].*${CRON_HC}" 2>/dev/null) - # check system crontabs - if (( CRON_COUNT == 0 )) - then - CRON_COUNT=$(cat ${CRON_SYS_LOCATIONS} 2>/dev/null | grep -c -E -e "^[^#].*${CRON_HC}" 2>/dev/null) - fi - # check anacron - if (( CRON_COUNT == 0 )) - then - CRON_COUNT=$(cat ${CRON_ANACRON_LOCATIONS} 2>/dev/null | grep -c -E -e "^[^#].*${CRON_HC}" 2>/dev/null) - fi - ;; + # check default root crontab + CRON_COUNT=$(crontab -l 2>/dev/null | grep -c -E -e "^[^#].*${CRON_HC}" 2>/dev/null) + # check system crontabs + if (( CRON_COUNT == 0 )) + then + # shellcheck disable=SC2002 + CRON_COUNT=$(cat ${CRON_SYS_LOCATIONS} 2>/dev/null | grep -c -E -e "^[^#].*${CRON_HC}" 2>/dev/null) + fi + # check anacron + if (( CRON_COUNT == 0 )) + then + # shellcheck disable=SC2002 + CRON_COUNT=$(cat ${CRON_ANACRON_LOCATIONS} 2>/dev/null | grep -c -E -e "^[^#].*${CRON_HC}" 2>/dev/null) + fi + ;; *) - # use default root crontab - CRON_COUNT=$(crontab -l 2>/dev/null | grep -c -E -e "^[^#].*${CRON_HC}" 2>/dev/null) + # use default root crontab + CRON_COUNT=$(crontab -l 2>/dev/null | grep -c -E -e "^[^#].*${CRON_HC}" 2>/dev/null) esac return ${CRON_COUNT} @@ -1496,40 +1589,40 @@ do # shellcheck disable=SC2010 ls -1 ${FDIR}/*.sh 2>/dev/null | grep -v "include_" | sort 2>/dev/null | while read -r FFILE do - # cache script contents in memory - FSCRIPT=$(<${FFILE}) + # cache script contents in memory + FSCRIPT=$(<${FFILE}) - # reset state - FSTATE="enabled" - # find function name but skip helper functions in the plug-in file (function _name) - FNAME=$(print -R "${FSCRIPT}" | grep -E -e "^function[[:space:]]+[^_]" 2>/dev/null) - # look for version string (cut off comments but don't use [:space:] in tr) - FVERSION=$(print -R "${FSCRIPT}" | grep '^typeset _VERSION=' 2>/dev/null |\ - awk 'match($0,/[0-9]+-[0-9]+-[0-9]+/){print substr($0, RSTART, RLENGTH)}' 2>/dev/null) - # look for configuration file string - HAS_FCONFIG=$(print -R "${FSCRIPT}" | grep -c '^typeset _CONFIG_FILE=' 2>/dev/null) - if (( HAS_FCONFIG > 0 )) - then - FCONFIG="Yes" - else - FCONFIG="No" - fi - # check state (only for unlinked) - [[ -h ${FFILE%%.*} ]] || FSTATE="unlinked" + # reset state + FSTATE="enabled" + # find function name but skip helper functions in the plug-in file (function _name) + FNAME=$(print -R "${FSCRIPT}" | grep -E -e "^function[[:space:]]+[^_]" 2>/dev/null) + # look for version string (cut off comments but don't use [:space:] in tr) + FVERSION=$(print -R "${FSCRIPT}" | grep '^typeset _VERSION=' 2>/dev/null |\ + awk 'match($0,/[0-9]+-[0-9]+-[0-9]+/){print substr($0, RSTART, RLENGTH)}' 2>/dev/null) + # look for configuration file string + HAS_FCONFIG=$(print -R "${FSCRIPT}" | grep -c '^typeset _CONFIG_FILE=' 2>/dev/null) + if (( HAS_FCONFIG > 0 )) + then + FCONFIG="Yes" + else + FCONFIG="No" + fi + # check state (only for unlinked) + [[ -h ${FFILE%%.*} ]] || FSTATE="unlinked" - # show results - if [[ "${FACTION}" != "list" ]] - then - # shellcheck disable=SC1117 - printf "%-30s\t%-8s\t%s\t%s\n" \ - "${FNAME#function *}" \ - "${FSTATE}" \ - "${FVERSION#typeset _VERSION=*}" \ - "${FCONFIG}" - else - # shellcheck disable=SC1117 - printf "%s\n" "${FNAME#function *}" - fi + # show results + if [[ "${FACTION}" != "list" ]] + then + # shellcheck disable=SC1117 + printf "%-30s\t%-8s\t%s\t%s\n" \ + "${FNAME#function *}" \ + "${FSTATE}" \ + "${FVERSION#typeset _VERSION=*}" \ + "${FCONFIG}" + else + # shellcheck disable=SC1117 + printf "%s\n" "${FNAME#function *}" + fi done done @@ -1542,10 +1635,10 @@ do # shellcheck disable=SC2010,SC1117 ls ${FDIR} 2>/dev/null | grep -v "\." 2>/dev/null | while read -r FFILE do - if [[ -h "${FDIR}/${FFILE}" ]] && [[ ! -f "${FDIR}/${FFILE}" ]] - then - printf "%s " ${FFILE##*/} - fi + if [[ -h "${FDIR}/${FFILE}" ]] && [[ ! -f "${FDIR}/${FFILE}" ]] + then + printf "%s " ${FFILE##*/} + fi done done print @@ -1596,139 +1689,139 @@ if [[ "${FACTION}" != "list" ]] then if (( ARG_LIST_DETAILS > 0 )) then - # shellcheck disable=SC1117 - printf "%-40s\t%-8s\t%s\t\t%s\t%s\t%s\t%s\n" "Health Check" "State" "Version" "Config?" "Sched?" "H+?" "Fix?" - # shellcheck disable=SC2183,SC1117 - printf "%110s\n" | tr ' ' - + # shellcheck disable=SC1117 + printf "%-40s\t%-8s\t%s\t\t%s\t%s\t%s\t%s\n" "Health Check" "State" "Version" "Config?" "Sched?" "H+?" "Fix?" + # shellcheck disable=SC2183,SC1117 + printf "%110s\n" | tr ' ' - else - # shellcheck disable=SC1117 - printf "%-40s\t%-8s\n" "Health Check" "State" - # shellcheck disable=SC2183,SC1117 - printf "%60s\n" | tr ' ' - + # shellcheck disable=SC1117 + printf "%-40s\t%-8s\n" "Health Check" "State" + # shellcheck disable=SC2183,SC1117 + printf "%60s\n" | tr ' ' - fi fi print "${FPATH}" | tr ':' '\n' 2>/dev/null | grep -v "core$" 2>/dev/null | sort 2>/dev/null |\ while read -r FDIR do - ls -1 ${FDIR}/${FNEEDLE} 2>/dev/null | sort 2>/dev/null | while read -r FFILE + find ${FDIR} -name "${FNEEDLE}" 2>/dev/null | sort 2>/dev/null | while read -r FFILE do - # cache script contents in memory - FSCRIPT=$(<${FFILE}) + # cache script contents in memory + FSCRIPT=$(<${FFILE}) - # --list (basic) - # find function name but skip helper functions in the plug-in file (function _name) - FNAME=$(print -R "${FSCRIPT}" | grep -E -e "^function[[:space:]]+[^_]" 2>/dev/null) + # --list (basic) + # find function name but skip helper functions in the plug-in file (function _name) + FNAME=$(print -R "${FSCRIPT}" | grep -E -e "^function[[:space:]]+[^_]" 2>/dev/null) - # check state - DISABLE_FFILE="$(print ${FFILE##*/} | sed 's/\.sh$//')" - if [[ -f "${STATE_PERM_DIR}/${DISABLE_FFILE}.disabled" ]] - then - FSTATE="disabled" - else - FSTATE="enabled" - fi + # check state + DISABLE_FFILE="$(print ${FFILE##*/} | sed 's/\.sh$//')" + if [[ -f "${STATE_PERM_DIR}/${DISABLE_FFILE}.disabled" ]] + then + FSTATE="disabled" + else + FSTATE="enabled" + fi - # --list-details - if (( ARG_LIST_DETAILS > 0 )) - then - # look for version string (cut off comments but don't use [:space:] in tr) - FVERSION=$(print -R "${FSCRIPT}" | grep '^typeset _VERSION=' 2>/dev/null |\ - awk 'match($0,/[0-9]+-[0-9]+-[0-9]+/){print substr($0, RSTART, RLENGTH)}' 2>/dev/null) - # look for configuration file string - HAS_FCONFIG=$(print -R "${FSCRIPT}" | grep -c '^typeset _CONFIG_FILE=' 2>/dev/null) - if (( HAS_FCONFIG > 0 )) - then - FCONFIG="Yes" - # *.conf.dist first - if [[ -r ${CONFIG_DIR}/${FNAME#function *}.conf.dist ]] - then - # check for log_healthy parameter (config file) - HAS_FHEALTHY=$(_CONFIG_FILE="${CONFIG_DIR}/${FNAME#function *}.conf.dist" data_get_lvalue_from_config 'log_healthy') - case "${HAS_FHEALTHY}" in - no|NO|No) - FHEALTHY="No" - ;; - yes|YES|Yes) - FHEALTHY="Yes" - ;; - *) - FHEALTHY="N/S" - ;; - esac - else - FHEALTHY="N/S" - fi - # *.conf next - if [[ -r ${CONFIG_DIR}/${FNAME#function *}.conf ]] - then - # check for log_healthy parameter (config file) - HAS_FHEALTHY=$(_CONFIG_FILE="${CONFIG_DIR}/${FNAME#function *}.conf" data_get_lvalue_from_config 'log_healthy') - case "${HAS_FHEALTHY}" in - no|NO|No) - FHEALTHY="No" - ;; - yes|YES|Yes) - FHEALTHY="Yes" - ;; - *) - FHEALTHY="N/S" - ;; - esac - fi - # check for log_healthy support through --hc-args (plugin) - elif (( $(print -R "${FSCRIPT}" | grep -c -E -e "_LOG_HEALTHY" 2>/dev/null) > 0 )) - then - FCONFIG="No" - FHEALTHY="S" - else - FCONFIG="No" - FHEALTHY="N/S" - fi - # check fix - if (( $(print -R "${FSCRIPT}" | grep -c -E -e "_HC_CAN_FIX=1" 2>/dev/null) > 0 )) - then - FFIX="Yes" - else - FFIX="No" - fi + # --list-details + if (( ARG_LIST_DETAILS > 0 )) + then + # look for version string (cut off comments but don't use [:space:] in tr) + FVERSION=$(print -R "${FSCRIPT}" | grep '^typeset _VERSION=' 2>/dev/null |\ + awk 'match($0,/[0-9]+-[0-9]+-[0-9]+/){print substr($0, RSTART, RLENGTH)}' 2>/dev/null) + # look for configuration file string + HAS_FCONFIG=$(print -R "${FSCRIPT}" | grep -c '^typeset _CONFIG_FILE=' 2>/dev/null) + if (( HAS_FCONFIG > 0 )) + then + FCONFIG="Yes" + # *.conf.dist first + if [[ -r ${CONFIG_DIR}/${FNAME#function *}.conf.dist ]] + then + # check for log_healthy parameter (config file) + HAS_FHEALTHY=$(_CONFIG_FILE="${CONFIG_DIR}/${FNAME#function *}.conf.dist" data_get_lvalue_from_config 'log_healthy') + case "${HAS_FHEALTHY}" in + no|NO|No) + FHEALTHY="No" + ;; + yes|YES|Yes) + FHEALTHY="Yes" + ;; + *) + FHEALTHY="N/S" + ;; + esac + else + FHEALTHY="N/S" + fi + # *.conf next + if [[ -r ${CONFIG_DIR}/${FNAME#function *}.conf ]] + then + # check for log_healthy parameter (config file) + HAS_FHEALTHY=$(_CONFIG_FILE="${CONFIG_DIR}/${FNAME#function *}.conf" data_get_lvalue_from_config 'log_healthy') + case "${HAS_FHEALTHY}" in + no|NO|No) + FHEALTHY="No" + ;; + yes|YES|Yes) + FHEALTHY="Yes" + ;; + *) + FHEALTHY="N/S" + ;; + esac + fi + # check for log_healthy support through --hc-args (plugin) + elif (( $(print -R "${FSCRIPT}" | grep -c -E -e "_LOG_HEALTHY" 2>/dev/null) > 0 )) + then + FCONFIG="No" + FHEALTHY="S" + else + FCONFIG="No" + FHEALTHY="N/S" + fi + # check fix + if (( $(print -R "${FSCRIPT}" | grep -c -E -e "_HC_CAN_FIX=1" 2>/dev/null) > 0 )) + then + FFIX="Yes" + else + FFIX="No" + fi - # reset state when unlinked - [[ -h ${FFILE%%.*} ]] || FSTATE="unlinked" - # check scheduling - is_scheduled "${FNAME#function *}" - # shellcheck disable=SC2181 - if (( $? == 0 )) - then - FSCHEDULED="No" - else - FSCHEDULED="Yes" - fi - fi + # reset state when unlinked + [[ -h ${FFILE%%.*} ]] || FSTATE="unlinked" + # check scheduling + is_scheduled "${FNAME#function *}" + # shellcheck disable=SC2181 + if (( $? == 0 )) + then + FSCHEDULED="No" + else + FSCHEDULED="Yes" + fi + fi - # show results - if [[ "${FACTION}" != "list" ]] - then - if (( ARG_LIST_DETAILS > 0 )) - then - # shellcheck disable=SC1117 - printf "%-40s\t%-8s\t%s\t%s\t%s\t%s\t%s\n" \ - "${FNAME#function *}" \ - "${FSTATE}" \ - "${FVERSION#typeset _VERSION=*}" \ - "${FCONFIG}" \ - "${FSCHEDULED}" \ - "${FHEALTHY}" \ - "${FFIX}" - else - # shellcheck disable=SC1117 - printf "%-40s\t%-8s\n" \ - "${FNAME#function *}" \ - "${FSTATE}" - fi - else - # shellcheck disable=SC1117 - printf "%s\n" "${FNAME#function *}" - fi + # show results + if [[ "${FACTION}" != "list" ]] + then + if (( ARG_LIST_DETAILS > 0 )) + then + # shellcheck disable=SC1117 + printf "%-40s\t%-8s\t%s\t%s\t%s\t%s\t%s\n" \ + "${FNAME#function *}" \ + "${FSTATE}" \ + "${FVERSION#typeset _VERSION=*}" \ + "${FCONFIG}" \ + "${FSCHEDULED}" \ + "${FHEALTHY}" \ + "${FFIX}" + else + # shellcheck disable=SC1117 + printf "%-40s\t%-8s\n" \ + "${FNAME#function *}" \ + "${FSTATE}" + fi + else + # shellcheck disable=SC1117 + printf "%s\n" "${FNAME#function *}" + fi done done @@ -1739,15 +1832,15 @@ then print -n "Dead links: " print "${FPATH}" | tr ':' '\n' 2>/dev/null | grep -v "core" 2>/dev/null | while read -r FDIR do - # do not use 'find -type l' here! - # shellcheck disable=SC2010,SC1117 - ls ${FDIR} 2>/dev/null | grep -v "\." 2>/dev/null | while read -r FFILE - do - if [[ -h "${FDIR}/${FFILE}" ]] && [[ ! -f "${FDIR}/${FFILE}" ]] - then - printf "%s " ${FFILE##*/} - fi - done + # do not use 'find -type l' here! + # shellcheck disable=SC2010,SC1117 + ls ${FDIR} 2>/dev/null | grep -v "\." 2>/dev/null | while read -r FFILE + do + if [[ -h "${FDIR}/${FFILE}" ]] && [[ ! -f "${FDIR}/${FFILE}" ]] + then + printf "%s " ${FFILE##*/} + fi + done done print @@ -1761,14 +1854,14 @@ if [[ "${FACTION}" != "list" ]] then if (( ARG_LIST_DETAILS > 0 )) then - print - print "Config?: plugin has a default configuration file (Yes/No)" - print "Sched? : plugin is scheduled through cron (Yes/No)" - print "H+? : plugin can choose whether to log/show passed health checks (Yes/No/Supported/Not supported)" - print "Fix? : plugin contains fix/healing logic (Yes/No) -- not used by default!" + print + print "Config?: plugin has a default configuration file (Yes/No)" + print "Sched? : plugin is scheduled through cron (Yes/No)" + print "H+? : plugin can choose whether to log/show passed health checks (Yes/No/Supported/Not supported)" + print "Fix? : plugin contains fix/healing logic (Yes/No) -- not used by default!" else - print - print "Tip: use --list-details to see a list of health checks with more details" + print + print "Tip: use --list-details to see a list of health checks with more details" fi fi @@ -1806,31 +1899,31 @@ do # shellcheck disable=SC2010 ls -1 ${FDIR}/*.sh 2>/dev/null | grep "include_" 2>/dev/null | sort 2>/dev/null | while read -r FFILE do - # cache script contents in memory - FSCRIPT=$(<${FFILE}) + # cache script contents in memory + FSCRIPT=$(<${FFILE}) - # find function name - FNAME=$(print -R "${FSCRIPT}" | grep -E -e "^function[[:space:]].*version_" 2>/dev/null) - # look for version string (cut off comments but don't use [:space:] in tr) - FVERSION=$(print -R "${FSCRIPT}" | grep '^typeset _VERSION=' 2>/dev/null |\ - awk 'match($0,/[0-9]+-[0-9]+-[0-9]+/){print substr($0, RSTART, RLENGTH)}' 2>/dev/null) + # find function name + FNAME=$(print -R "${FSCRIPT}" | grep -E -e "^function[[:space:]].*version_" 2>/dev/null) + # look for version string (cut off comments but don't use [:space:] in tr) + FVERSION=$(print -R "${FSCRIPT}" | grep '^typeset _VERSION=' 2>/dev/null |\ + awk 'match($0,/[0-9]+-[0-9]+-[0-9]+/){print substr($0, RSTART, RLENGTH)}' 2>/dev/null) - # get list of functions - FFUNCTIONS=$(print -R "${FSCRIPT}" | grep -E -e "^function[[:space:]]+" 2>/dev/null | awk '{ print $2}' 2>/dev/null) + # get list of functions + FFUNCTIONS=$(print -R "${FSCRIPT}" | grep -E -e "^function[[:space:]]+" 2>/dev/null | awk '{ print $2}' 2>/dev/null) - # check state (only for unlinked) - [[ -h ${FFILE%%.*} ]] || FSTATE="unlinked" + # check state (only for unlinked) + [[ -h ${FFILE%%.*} ]] || FSTATE="unlinked" - # show results - # shellcheck disable=SC1117 - printf "%-20s\t%-8s\t%12s\n" \ - "${FNAME#function version_*}" \ - "${FSTATE}" \ - "${FVERSION#typeset _VERSION=*}" - print "${FFUNCTIONS}" | while read -r FFUNCTION - do - printf "%64s%s\n" "" "${FFUNCTION}" - done + # show results + # shellcheck disable=SC1117 + printf "%-20s\t%-8s\t%12s\n" \ + "${FNAME#function version_*}" \ + "${FSTATE}" \ + "${FVERSION#typeset _VERSION=*}" + print "${FFUNCTIONS}" | while read -r FFUNCTION + do + printf "%64s%s\n" "" "${FFUNCTION}" + done done done @@ -1843,10 +1936,10 @@ do # shellcheck disable=SC2010,SC1117 ls ${FDIR} 2>/dev/null | grep -v "\." 2>/dev/null | while read -r FFILE do - if [[ -h "${FDIR}/${FFILE}" ]] && [[ ! -f "${FDIR}/${FFILE}" ]] - then - printf "%s " ${FFILE##*/} - fi + if [[ -h "${FDIR}/${FFILE}" ]] && [[ ! -f "${FDIR}/${FFILE}" ]] + then + printf "%s " ${FFILE##*/} + fi done done print @@ -1874,17 +1967,17 @@ if [[ -n "${1}" ]] then if (( ARG_LOG > 0 )) then - print - "$*" | while read -r LOG_LINE - do - print "${NOW}: INFO: [$$]:" "${LOG_LINE}" >>${LOG_FILE} - done + print - "$*" | while read -r LOG_LINE + do + print "${NOW}: INFO: [$$]:" "${LOG_LINE}" >>${LOG_FILE} + done fi if (( ARG_VERBOSE > 0 )) then - print - "$*" | while read -r LOG_LINE - do - print "INFO:" "${LOG_LINE}" - done + print - "$*" | while read -r LOG_LINE + do + print "INFO:" "${LOG_LINE}" + done fi fi @@ -1915,9 +2008,9 @@ then # shellcheck disable=SC2181 if (( $? > 0 )) then - HC_MSG_TEXT=$(data_magic_quote "${3}") + HC_MSG_TEXT=$(data_magic_quote "${3}") else - HC_MSG_TEXT="${3}" + HC_MSG_TEXT="${3}" fi fi if [[ -n "${4}" ]] @@ -1926,9 +2019,9 @@ then # shellcheck disable=SC2181 if (( $? > 0 )) then - HC_MSG_CUR_VAL=$(data_magic_quote "${4}") + HC_MSG_CUR_VAL=$(data_magic_quote "${4}") else - HC_MSG_CUR_VAL="${4}" + HC_MSG_CUR_VAL="${4}" fi fi if [[ -n "${5}" ]] @@ -1937,9 +2030,9 @@ then # shellcheck disable=SC2181 if (( $? > 0 )) then - HC_MSG_EXP_VAL=$(data_magic_quote "${5}") + HC_MSG_EXP_VAL=$(data_magic_quote "${5}") else - HC_MSG_EXP_VAL="${5}" + HC_MSG_EXP_VAL="${5}" fi fi @@ -1967,40 +2060,40 @@ print -R "--- CURRENT events --" print print "${HC_LOG}:" awk -F"${LOG_SEP}" '{ - # all entries - total_count[$2]++ - # set zero when empty - if (ok_count[$2] == "") { ok_count[$2]=0 } - if (nok_count[$2] == "") { nok_count[$2]=0 } - # count STCs - if ($3 == 0) { - ok_count[$2]++ - } else { - nok_count[$2]++ - } - # record first entry - if (first_entry[$2] == "" ) { - first_entry[$2]=$1 - } - # pile up last entry - last_entry[$2]=$1 - last_failid[$2]=$5 - } + # all entries + total_count[$2]++ + # set zero when empty + if (ok_count[$2] == "") { ok_count[$2]=0 } + if (nok_count[$2] == "") { nok_count[$2]=0 } + # count STCs + if ($3 == 0) { + ok_count[$2]++ + } else { + nok_count[$2]++ + } + # record first entry + if (first_entry[$2] == "" ) { + first_entry[$2]=$1 + } + # pile up last entry + last_entry[$2]=$1 + last_failid[$2]=$5 + } - END { - for (hc in total_count) { - # empty hc variable means count of empty lines in log file - if (hc != "") { - printf ("\t%s:\n", hc) - printf ("\t\t# entries: %d\n", total_count[hc]) - printf ("\t\t# STC==0 : %d\n", ok_count[hc]) - printf ("\t\t# STC<>0 : %d\n", nok_count[hc]) - printf ("\t\tfirst : %s\n", first_entry[hc]) - printf ("\t\tlast : %s\n", last_entry[hc]) - } - } - } - ' ${HC_LOG} 2>/dev/null + END { + for (hc in total_count) { + # empty hc variable means count of empty lines in log file + if (hc != "") { + printf ("\t%s:\n", hc) + printf ("\t\t# entries: %d\n", total_count[hc]) + printf ("\t\t# STC==0 : %d\n", ok_count[hc]) + printf ("\t\t# STC<>0 : %d\n", nok_count[hc]) + printf ("\t\tfirst : %s\n", first_entry[hc]) + printf ("\t\tlast : %s\n", last_entry[hc]) + } + } + } + ' ${HC_LOG} 2>/dev/null # archived events print; print @@ -2010,39 +2103,39 @@ find ${ARCHIVE_DIR} -type f -name "hc.*.log" 2>/dev/null | while read -r _ARCHIV do print "${_ARCHIVE_FILE}:" awk -F"${LOG_SEP}" '{ - # all entries - total_count[$2]++ - # set zero when empty - if (ok_count[$2] == "") { ok_count[$2]=0 } - if (nok_count[$2] == "") { nok_count[$2]=0 } - # count STCs - if ($3 == 0) { - ok_count[$2]++; - } else { - nok_count[$2]++ - } - # record first entry - if (first_entry[$2] == "" ) { - first_entry[$2]=$1 - } - # pile up last entry - last_entry[$2]=$1 - } + # all entries + total_count[$2]++ + # set zero when empty + if (ok_count[$2] == "") { ok_count[$2]=0 } + if (nok_count[$2] == "") { nok_count[$2]=0 } + # count STCs + if ($3 == 0) { + ok_count[$2]++; + } else { + nok_count[$2]++ + } + # record first entry + if (first_entry[$2] == "" ) { + first_entry[$2]=$1 + } + # pile up last entry + last_entry[$2]=$1 + } - END { - for (hc in total_count) { - # empty hc variable means count of empty lines in log file - if (hc != "") { - printf ("\t%s:\n", hc) - printf ("\t\t# entries: %d\n", total_count[hc]) - printf ("\t\t# STC==0 : %d\n", ok_count[hc]) - printf ("\t\t# STC<>0 : %d\n", nok_count[hc]) - printf ("\t\tfirst : %s\n", first_entry[hc]) - printf ("\t\tlast : %s\n", last_entry[hc]) - } - } - } - ' ${_ARCHIVE_FILE} 2>/dev/null + END { + for (hc in total_count) { + # empty hc variable means count of empty lines in log file + if (hc != "") { + printf ("\t%s:\n", hc) + printf ("\t\t# entries: %d\n", total_count[hc]) + printf ("\t\t# STC==0 : %d\n", ok_count[hc]) + printf ("\t\t# STC<>0 : %d\n", nok_count[hc]) + printf ("\t\tfirst : %s\n", first_entry[hc]) + printf ("\t\tlast : %s\n", last_entry[hc]) + } + } + } + ' ${_ARCHIVE_FILE} 2>/dev/null done return 0 @@ -2081,17 +2174,17 @@ if [[ -n "${1}" ]] then if (( ARG_LOG > 0 )) then - print - "$*" | while read -r LOG_LINE - do - print "${NOW}: WARN: [$$]:" "${LOG_LINE}" >>${LOG_FILE} - done + print - "$*" | while read -r LOG_LINE + do + print "${NOW}: WARN: [$$]:" "${LOG_LINE}" >>${LOG_FILE} + done fi if (( ARG_VERBOSE > 0 )) then - print - "$*" | while read -r LOG_LINE - do - print "WARN:" "${LOG_LINE}" - done + print - "$*" | while read -r LOG_LINE + do + print "WARN:" "${LOG_LINE}" + done fi fi diff --git a/opt/hc/lib/core/report_std.sh b/opt/hc/lib/core/report_std.sh index b020a01..86c2c5c 100755 --- a/opt/hc/lib/core/report_std.sh +++ b/opt/hc/lib/core/report_std.sh @@ -30,7 +30,7 @@ function report_std { # ------------------------- CONFIGURATION starts here ------------------------- -typeset _VERSION="2019-05-19" # YYYY-MM-DD +typeset _VERSION="2020-04-07" # YYYY-MM-DD typeset _SUPPORTED_PLATFORMS="AIX,HP-UX,Linux" # uname -s match # ------------------------- CONFIGURATION ends here --------------------------- @@ -59,8 +59,13 @@ typeset _OLDER_MONTH="" typeset _OLDER_YEAR="" typeset _NEWER_MONTH="" typeset _NEWER_YEAR="" +typeset _HC_REPORT_CACHE_LAST_STUB="${STATE_PERM_DIR}/cache.report-last" +typeset _HC_REPORT_CACHE_LAST_FILE="" +typeset _HC_REPORT_CACHE_TODAY_FILE="${STATE_PERM_DIR}/cache.report-today" +typeset _USE_CACHE=0 +typeset _CACHE_NOTE_BIT="" -# set archive log stash +# set archive log stash (never use cache files) if (( ARG_HISTORY > 0 )) || [[ -n "${ARG_OLDER}" ]] || [[ -n "${ARG_NEWER}" ]] then set +f # file globbing must be on @@ -148,10 +153,45 @@ then _HC_LAST_TIME="" _HC_LAST_STC=0 _HC_LAST_FAIL_ID="-" - # find last event or block of events (same timestamp) - # (but unfortunately this is only accurate to events within the SAME second!) - # shellcheck disable=SC2086 - _HC_LAST_TIME="$(grep -h ${_HC_LAST} ${_LOG_STASH} 2>/dev/null | sort -n 2>/dev/null | cut -f1 -d${LOG_SEP} 2>/dev/null | uniq 2>/dev/null | tail -1 2>/dev/null)" + _USE_CACHE=0 + + # check for cache usage + if (( ARG_HISTORY == 0 )) + then + case "${HC_REPORT_CACHE_LAST}" in + Yes|yes|YES) + _HC_REPORT_CACHE_LAST_FILE="${_HC_REPORT_CACHE_LAST_STUB}-${_HC_LAST}" + # check if cache file exists + if [[ -s "${_HC_REPORT_CACHE_LAST_FILE}" ]] + then + _LOG_STASH="${_HC_REPORT_CACHE_LAST_FILE}" + _USE_CACHE=1 + (( ARG_DEBUG > 0 )) && debug "setting log stash to cache file at ${_HC_REPORT_CACHE_LAST_FILE}" + else + (( ARG_DEBUG > 0 )) && debug "HC_REPORT_CACHE_LAST is enabled but unable to find cache file at ${_HC_REPORT_CACHE_LAST_FILE}" + # reset log stash to current log + _LOG_STASH="${HC_LOG} ${_LOG_STASH}" + fi + ;; + *) + # no caching: reset log stash to current log + (( ARG_DEBUG > 0 )) && debug "HC_REPORT_CACHE_LAST is disabled" + _LOG_STASH="${HC_LOG} ${_LOG_STASH}" + ;; + esac + fi + + # determine LAST_TIME from cache or log(s) + if (( ARG_HISTORY == 0 )) && (( _USE_CACHE > 1 )) + then + _HC_LAST_TIME="$(tail -n 1 ${_LOG_STASH} 2>/dev/null | cut -f1 -d${LOG_SEP} 2>/dev/null)" + else + # find last event or block of events (same timestamp) + # (but unfortunately this is only accurate to events within the SAME second!) + # shellcheck disable=SC2086 + _HC_LAST_TIME="$(grep -h ${_HC_LAST} ${_LOG_STASH} 2>/dev/null | sort -n 2>/dev/null | cut -f1 -d${LOG_SEP} 2>/dev/null | uniq 2>/dev/null | tail -1 2>/dev/null)" + fi + if [[ -z "${_HC_LAST_TIME}" ]] then _HC_LAST_TIME="-" @@ -181,12 +221,26 @@ then fi # report on findings # shellcheck disable=SC1117 - printf "| %-40s | %-20s | %-14s | %-4s\n" \ - "${_HC_LAST}" "${_HC_LAST_TIME}" "${_HC_LAST_FAIL_ID}" "${_HC_LAST_STC}" + if (( _USE_CACHE > 0 )) + then + printf "| %-40s | %-20s | %-14s | %-4s (C)\n" \ + "${_HC_LAST}" "${_HC_LAST_TIME}" "${_HC_LAST_FAIL_ID}" "${_HC_LAST_STC}" + else + printf "| %-40s | %-20s | %-14s | %-4s\n" \ + "${_HC_LAST}" "${_HC_LAST_TIME}" "${_HC_LAST_FAIL_ID}" "${_HC_LAST_STC}" + fi done - # disclaimer - print "NOTE: this report only shows the overall combined status of all events of each HC within exactly" - print " the *same* time stamp (seconds precise). It may therefore fail to report certain FAIL IDs." + # spacer + print + # disclaimer & note(s) + if (( _USE_CACHE > 0 )) + then + print "NOTE: entries suffixed by (C) indicate results were retrieved from a cache file. If you wish to use " + print " the real log files then disable HC_REPORT_CACHE_LAST in ${CONFIG_FILE}" + fi + (( ARG_HISTORY == 0 )) && _CACHE_NOTE_BIT="for non-cached entries: " + print "NOTE: ${_CACHE_NOTE_BIT}this report only shows the overall combined status of all events of each HC" + print " within exactly the *same* time stamp (seconds precise). It may therefore fail to report certain FAIL IDs." print " Use '--report' to get the exact list of failure events." # other reports else @@ -198,7 +252,31 @@ else (( _IS_VALID_ID > 0 )) || die "invalid ID specified" _ID_NEEDLE="${ARG_FAIL_ID}" fi - (( ARG_TODAY > 0 )) && _ID_NEEDLE="$(date '+%Y%m%d')" # refers to timestamp of HC FAIL_ID + # set today's needle and check cache usage + if (( ARG_TODAY > 0 )) + then + _ID_NEEDLE="$(date '+%Y%m%d')" # refers to timestamp of HC FAIL_ID + # do not use a cache file when --with-history + if (( ARG_HISTORY == 0 )) + then + case "${HC_REPORT_CACHE_TODAY}" in + Yes|yes|YES) + # check if cache file exists + if [[ -s "${_HC_REPORT_CACHE_TODAY_FILE}" ]] + then + _LOG_STASH="${_HC_REPORT_CACHE_TODAY_FILE}" + _USE_CACHE=1 + (( ARG_DEBUG > 0 )) && debug "setting log stash to today's cache file at ${_HC_REPORT_CACHE_TODAY_FILE}" + else + (( ARG_DEBUG > 0 )) && debug "HC_REPORT_CACHE_TODAY is enabled but unable to find cache file at ${_HC_REPORT_CACHE_TODAY_FILE}" + fi + ;; + *) + (( ARG_DEBUG > 0 )) && debug "HC_REPORT_CACHE_TODAY is disabled" + ;; + esac + fi + fi # reverse? if (( ARG_REVERSE == 0 )) @@ -262,9 +340,9 @@ else split (events[i], event, "|"); printf ("\n| %-20s | %-14s | %-40s | %-s", event[1], event[5], event[2], event[4]); } - printf ("\n\nSUMMARY: %s failed HC event(s) found.\n", event_count); + printf ("\n\nSUMMARY: %s failed HC event(s) found.\n\n", event_count); } else { - printf ("\nSUMMARY: 0 failed HC events found.\n"); + printf ("\nSUMMARY: 0 failed HC events found.\n\n"); } } ' 2>/dev/null @@ -316,14 +394,23 @@ else # shellcheck disable=SC2183,SC1117 printf "%80s\n" | tr ' ' - fi + + # add notes + # cache or not? + if (( _USE_CACHE > 0 )) + then + print "NOTE: results were retrieved from a cache file. If you wish to use the real log files then" + print " remove ${_HC_REPORT_CACHE_TODAY_FILE} and/or disable HC_REPORT_CACHE_TODAY in ${CONFIG_FILE}" + fi fi -# general note: history or not? +# add general notes +# history or not? if (( ARG_HISTORY > 0 )) then print "NOTE: showing results with all history (archive) included (--with-history)" else - print "NOTE: showing results only of current log entries (use --with-history to view all entries)" + print "NOTE: showing only results of current entries (use --with-history to view all entries)" fi # check consistency of log(s)