柿食えば鐘が鳴るなり法隆寺
#!/bin/bash
# execCheckLog.sh
#
#-----------------------------------------------------
# Purpose : 指定ファイルに指定文字列が出力された場合チャットワークで報知するシェルスクリプト
#-----------------------------------------------------
# USAGE
if [ "$1" = "help" ]; then
echo "USAGE:"
echo " $0"
echo ""
exit 0
fi
readonly MSG_FILE_PATH="/tmp/execCheckLog_msg.txt"
readonly CHATWORK_TOKEN=$1
readonly CHATWORK_ROOMID=$2
#-----------------------------------------------------
# チャットワークAPIを利用しメッセージを送る関数です
#
# @param チャットワークに送るメッセージを記述したファイルのパス
#-----------------------------------------------------
send_chatwork() {
local -r TARGET_PATH=$1
local -r MESSAGE=$(cat "${TARGET_PATH}")
curl -X POST -H "X-ChatWorkToken: ${CHATWORK_TOKEN}" -d "body=${MESSAGE}" "https://api.chatwork.com/v2/rooms/${CHATWORK_ROOMID}/messages"
}
#-----------------------------------------------------
# 所定のフォーマットで記述されたファイルを作成する関数です(指定文字列を検知した際に使用)
#
# ファイルを作成する理由は、チャートワークAPIにメッセージを送る際改行がスムーズにいくためです。
#
# @param 検査したファイルのパス(文字列)
# @param 検知した文字列(文字列)
# @param エラーの詳細(文字列)
# @param 検査した行情報(文字列)
#-----------------------------------------------------
create_message() {
local -r SERVER_NAME=$(hostname)
local -r MY_IP=$(hostname -I | cut -f1 -d' ')
local -r FILE_PATH=$1
local -r TOKEN=$2
local -r CONTENTS=$3
local -r ROW_INFO=$4
cat <<_EOT_ >${MSG_FILE_PATH}
[info]
[title]
【ログ異常検知】${SERVER_NAME}(${MY_IP})
[/title]
ファイルパス:${FILE_PATH}
検査行:${ROW_INFO}
検知文字列:${TOKEN}
詳細:${CONTENTS}
[/info]
_EOT_
}
#-----------------------------------------------------
# 本スクリプトの生存確認の為、所定の時間にチャットワークにメッセージを送る関数です
#-----------------------------------------------------
check_alive() {
local -r CURRENT_TIME=$(date -d '0 second ago' '+%H%M')
local -r TARGET_TIME="0700"
if [ "${CURRENT_TIME}" != "${TARGET_TIME}" ]; then
return 1
fi
cat <<_EOT_ >${MSG_FILE_PATH}
[info]
[title]
【ログ異常検知】${SERVER_NAME}($MY_IP)
[/title]
これは本プログラム自身の稼働チェックです。本日も監視処理を実施中です。
[/info]
_EOT_
send_chatwork "${MSG_FILE_PATH}"
}
#-----------------------------------------------------
# 指定ファイルに指定文字列が出力された場合チャットワークで報知する関数です
#
# @param 検査ファイルのPATH
# @param 検知文字列
# @param 検査した行をFIXさせるかどうかを判断するための値(boolean)
# @param 処理番号(int)。FIX行を管理するファイルの名前の一意性を担保するのに使います
#-----------------------------------------------------
check_log() {
local -r TARGET_FILE_PATH=$1
local -r CHECK_TOKEN=$2
local -r IS_UPDATE_LAST_LOG=$3
local -r LAST_LOG_LINE_NUM_PATH="/tmp/last_log_line_""$4"".txt"
if [ -e "${TARGET_FILE_PATH}" ]; then
echo "PATH:""${TARGET_FILE_PATH}""、に対し処理を開始します..."
else
return 1
fi
# ログの最新行数を取得して、前回からの出力変化をチェック。
if [ -e "${LAST_LOG_LINE_NUM_PATH}" ]; then
# 前回検査時の最終行数を取得
local -r LAST_LOG_LINE_NUM=$(cat "${LAST_LOG_LINE_NUM_PATH}")
else
# 今回の最終行数を取得。0でも良いけどそれだと問題ありそうだからやめぴ
local -r LAST_LOG_LINE_NUM=$(tr <"${TARGET_FILE_PATH}" ' ' _ | wc -l)
fi
local -r CURRENT_LOG_LINE_NUM=$(tr <"${TARGET_FILE_PATH}" ' ' _ | wc -l) # 今回の最終行数を取得
# 最終行数に変化がある場合、前回最終行数から今回最終行数の範囲で、検知文字列を確認。
if [ "$CURRENT_LOG_LINE_NUM" -gt "$LAST_LOG_LINE_NUM" ]; then
local -r LAST_LOG=$(tail -n $DIFF_LOG_COUNT "${TARGET_FILE_PATH}" | nl -v "${LAST_LOG_LINE_NUM}")
# 検知文字列を確認
echo "文字列[""${CHECK_TOKEN}""]が見つかりました。"
create_message "${TARGET_FILE_PATH}" "${CHECK_TOKEN}" "${CONTENTS}" "${LAST_LOG_LINE_NUM}行から${CURRENT_LOG_LINE_NUM}行"
send_chatwork "${MSG_FILE_PATH}"
else
echo "文字列[""${CHECK_TOKEN}""]が見つかりませんでした。"
fi
fi
# 今回の最終行数を$LAST_LOG_LINE_NUM_PATHファイルに上書き
if "${IS_UPDATE_LAST_LOG}"; then
echo "${CURRENT_LOG_LINE_NUM}" >"${LAST_LOG_LINE_NUM_PATH}"
fi
}
#-----------------------------------------------------
# check_alive関数を実行します
#-----------------------------------------------------
check_alive
#-----------------------------------------------------
# nginxのaccess.logに対し、指定文字列を格納した配列でループさせて、check_log関数を実行します
#-----------------------------------------------------
readonly CHECK_NGINX_TOKENS=("fluent" "Fluent" "fatal" "Fatal")
readonly CHECK_NGINX_TOKENS_NUM=${#CHECK_NGINX_TOKENS[*]}
_check_nginx_cnt=0
for _nginx_token in "${CHECK_NGINX_TOKENS[@]}"; do
_check_nginx_cnt=$*2
if [ "${_check_nginx_cnt}" -eq "$CHECK_NGINX_TOKENS_NUM" ]; then
check_log "${CHECK_NGINX_ACCESSLOG_PATH}" "${_nginx_token}" true 100
else
check_log "${CHECK_NGINX_ACCESSLOG_PATH}" "${_nginx_token}" false 100
fi
done
#-----------------------------------------------------
# syslogに対し、指定文字列を格納した配列でループさせて、check_log関数を実行します
#-----------------------------------------------------
readonly CHECK_SYSLOG_PATH="/var/log/messages"
readonly CHECK_SYSLOG_NUM=${#CHECK_SYSLOG_TOKENS[*]}
_check_syslog_cnt=0
for _syslog_token in "${CHECK_SYSLOG_TOKENS[@]}"; do
_check_syslog_cnt=$*3
if [ "${_check_syslog_cnt}" -eq "$CHECK_SYSLOG_NUM" ]; then
check_log "${CHECK_SYSLOG_PATH}" "${_syslog_token}" true 101
else
check_log "${CHECK_SYSLOG_PATH}" "${_syslog_token}" false 101
fi
done
readonly CURRENT_YEAR=$(date -d '0 second ago' '+%Y') # fuelのログのパスを作る用
readonly CURRENT_MONTH=$(date -d '0 second ago' '+%m') # fuelのログのパスを作る用
readonly CURRENT_DAY=$(date -d '0 second ago' '+%d') # fuelのログのパスを作る用
#-----------------------------------------------------
# fuelphpのtasksのlogに対し、指定文字列を格納した配列でループさせて、check_log関数を実行します
#-----------------------------------------------------
readonly CHECK_FUEL_TASKS_LOG_PATH="/home/appname/fuel/app/logs/tasks/""${CURRENT_YEAR}""/""${CURRENT_MONTH}""/""${CURRENT_DAY}"".php"
readonly CHECK_FUEL_TASKS_LOG_TOKENS=("Notice" "fatal" "Fatal")
readonly CHECK_FUEL_TASKS_LOG_TOKENS_NUM=${#CHECK_FUEL_TASKS_LOG_TOKENS[*]}
_check_fuel_tasks_cnt=0
for _fuel_tasks_token in "${CHECK_FUEL_TASKS_LOG_TOKENS[@]}"; do
_check_fuel_tasks_cnt=$*4
if [ "${_check_fuel_tasks_cnt}" -eq "$CHECK_FUEL_TASKS_LOG_TOKENS_NUM" ]; then
check_log "${CHECK_FUEL_TASKS_LOG_PATH}" "${_fuel_tasks_token}" true 102
else
check_log "${CHECK_FUEL_TASKS_LOG_PATH}" "${_fuel_tasks_token}" false 102
fi
done