20.23-20.25 告警系統郵件引擎(上)(中)(下)
shell項目-告警系統mail.sh
1 編寫mail.py在/mon/mail/下
[root@centos7-01 mon]# cd /usr/local/sbin/mon/mail/ [root@centos7-01 mon]# vim /usr/local/sbin/mon/mail/mail.py #!/usr/bin/env python #-*- coding: UTF-8 -*- import os,sys reload(sys) sys.setdefaultencoding('utf8') import getopt import smtplib from email.MIMEText import MIMEText from email.MIMEMultipart import MIMEMultipart from subprocess import * def sendqqmail(username,password,mailfrom,mailto,subject,content): gserver = 'smtp.163.com' gport = 25 try: msg = MIMEText(unicode(content).encode('utf-8')) msg['from'] = mailfrom msg['to'] = mailto msg['Reply-To'] = mailfrom msg['Subject'] = subject smtp = smtplib.SMTP(gserver, gport) smtp.set_debuglevel(0) smtp.ehlo() smtp.login(username,password) smtp.sendmail(mailfrom, mailto, msg.as_string()) smtp.close() except Exception,err: print "Send mail failed. Error: %s" % err def main(): to=sys.argv[1] subject=sys.argv[2] content=sys.argv[3] ##定義QQ郵箱的賬號和密碼,你需要修改成你自己的賬號和密碼(請不要把真實的用戶名和密碼放到網上公開,否則你會死的很慘) sendqqmail('[email protected]','此處定義郵箱客戶端授權密碼','[email protected]',to,subject,content) if __name__ == "__main__": main()
參數解釋:
注意幾個地方:
gserver 發郵件的服務器的域名
sendqqmail 郵件的地址,密碼
2 編寫mail.sh
log=$1 t_s=`date +%s` t_s2=`date -d "2 hours ago" +%s` if [ ! -f /tmp/$log ] then echo $t_s2 > /tmp/$log fi t_s2=`tail -1 /tmp/$log|awk '{print $1}'` echo $t_s>>/tmp/$log v=$[$t_s-$t_s2] echo $v if [ $v -gt 3600 ] then ./mail.py $1 $2 $3 echo "0" > /tmp/$log.txt else if [ ! -f /tmp/$log.txt ] then echo "0" > /tmp/$log.txt fi nu=`cat /tmp/$log.txt` nu2=$[$nu+1] echo $nu2>/tmp/$log.txt if [ $nu2 -gt 10 ] then ./mail.py $1 "trouble continue 10 min $2" "$3" echo "0" > /tmp/$log.txt fi fi
參數解釋:(中文解釋上面的參數)
log=$1 t_s=`date +%s` #當前時間的時間戳 t_s2=`date -d "2 hours ago" +%s` #2個小時以前的時間戳 #執行腳本第二次以上會是上一分鐘的時間戳,因爲腳本是每分鐘執行一次。 定義時間戳目的是爲了後面時間差值的告警條件執行 if [ ! -f /tmp/$log ] #判斷/tmp/$log是否存在,如果這個文件不存在 then echo $t_s2 > /tmp/$log #然後創建這個日誌文件 fi t_s2=`tail -1 /tmp/$log|awk '{print $1}'` #截取時間戳(日誌最後一行就是時間戳),最後一行就是這個參數echo $t_s2 > /tmp/$log ,兩個小時的時間戳,賦值t_s2 echo $t_s>>/tmp/$log #把當前時間的時間戳寫入到對應日誌裏,打開計時器。 #即使第一次執行腳本,沒有報警,也會把當前時間的時間戳寫入到日誌裏面 v=$[$t_s-$t_s2] #v兩個時間戳的比值差,假如日誌每分鐘執行一次,那麼兩次時間戳的相差就是60s #這裏相當於一個計時器 echo $v if [ $v -gt 3600 ] #如果$v>3600s,進行告警 #如果$v=60s,不滿足條件,執行else then ./mail.py $1 $2 $3 #然後調用執行mail.py腳本的第一個第二個第三個參數,mail.py在這用處就是發郵件給對應聯繫人 echo "0" > /tmp/$log.txt #第一次告警完畢後,計數器打開,寫入記錄計數器的文件裏,在前面的$log基礎上加多了後綴.txt 目的是爲了計數,記錄告警次數 else #少於3600s的判斷,嵌套判斷 if [ ! -f /tmp/$log.txt ] #如果計數器/tmp/$log.txt不存在 then echo "0" > /tmp/$log.txt #然後寫入0進去/tmp/$log.txt。 fi nu=`cat /tmp/$log.txt` #查看計算器裏面的數字,如果此文件不存在的話此時nu會是0 nu2=$[$nu+1] #在計數器的輸出結果+1,應該是0+1=1 echo $nu2>/tmp/$log.txt #把$nu2重置到計數器裏面,所以這個計數器的值會是1 if [ $nu2 -gt 10 ] #判斷計數器是否>10,如果計算器>10,則執行mail.py告警發送郵件 then ./mail.py $1 "trouble continue 10 min $2" "$3" #郵件告警通知, echo "0" > /tmp/$log.txt #當告警完成後,重新計數 fi fi
過程分析:
腳本每分鐘執行一次,當執行到第二次腳本以上,腳本會循環執行以下的命令
當計數器=1時,再次執行腳本。
計時器開始,當前時間戳至上一分鐘的時間戳,時間差=60,
60小於3600,不需要告警。
不需要告警的話,繼續判斷,
判斷/tmp/$log.txt是否存在,
存在繼續執行計數器,
nu=1
nu2=nu+1=2
計數器少於10的話,不需要進行告警,然後再1分鐘後繼續執行腳本。
反覆執行以上腳本,當執行到nu2>10的時候,發送告警郵件。
當發送郵件後,計數器(echo "0" > /tmp/$log.txt)會被清空置零。
(下)
情景:
監控502,告警持續兩分鐘,第三分鐘恢復正常。那麼第三分鐘恢復之後無須再執行mail.sh腳本,此時計數器記錄在2,一直到第8分鐘,開始告警,502次數大於預設預值,再次執行mail.sh。那麼502監控恢復了6分鐘的正常監控時間,此時mail.sh的執行過程是怎樣?
過程分析:
t_s當前時間戳,t_s2是6分鐘(360)以前,此時他們時間差的值($v)<3600,
360<3600,不需要告警,繼續執行下面條件,
判斷/tmp/$log.txt是否存在,存在的話執行計數器運算
nu=2(因爲從計算器爲2開始出現問題)
nu2=2+1=3,3<10,所以不告警
在計數器週期內恢復正常了,但計算器並沒有清空(一個小時候後才清空),
那就是一個小時之後告警了,清零了,然後過2分鐘之後,在這2分鐘內再次告警,但是這2分鐘內是不會發郵件
第三分鐘開始,業務恢復正常,恢復完成後,持續時間超過一個小時,
超過一個小時候,發現異常,這時候會直接再發一封郵件(因爲一小時後就是>3600s),因爲>3600,計數器從0開始計算,此時又會重新進入一個計時週期,10分鐘以內連續發告警,然後就去收斂,哪怕10分鐘以內不連續告警,每隔一兩分鐘都需要去收斂。
****mail.sh 目的是爲了做告警收斂的
mail.sh 核心部分:
時間週期3600s(一個小時)
計數器,10分鐘計數,超過10分鐘就發告警,沒超過10分鐘就不發告警
20.26 運行告警系統
1 添加計劃任務:執行告警系統,每分鐘一次
[root@centos7-01 mon]# crontab -e * * * * * cd /usr/local/sbin/mon/bin; bash main.sh
根據實際情況添加.
2 或者可以手動執行告警系統腳本
[root@centos7-01 mon]# cd /usr/local/sbin/mon/bin/ [root@centos7-01 bin]# sh -x main.sh + export send=1 + send=1 ++ /sbin/ifconfig ++ grep -A1 'ens33: ' ++ awk '/inet/ {print $2}' + export addr=192.168.189.128 + addr=192.168.189.128 ++ pwd + dir=/usr/local/sbin/mon/bin ++ echo /usr/local/sbin/mon/bin ++ awk -F/ '{print $NF}' + last_dir=bin + '[' bin == bin ']' + conf_file=../conf/mon.conf + exec
2.1 執行出錯,查看日誌文件
[root@centos7-01 bin]# cat ../log/err.log ++ date '+%F %T' + echo '2018-06-05 17:17:09 load average' + /bin/bash ../shares/load.sh + grep -q to_mon_502=1 ../conf/mon.conf ++ grep logfile= ../conf/mon.conf ++ awk -F = '{print $2}' ++ sed 's/ //g' + export log=/data/log/xxx.xxx.com/access.log + log=/data/log/xxx.xxx.com/access.log + $'/bin/bash\302\240\302\240../shares/502.sh' mail.sh:行23: /bin/bash ../shares/502.sh: 沒有那個文件或目錄 [root@centos7-01 bin]# ls ../shares/502.sh ../shares/502.sh
2.2 查看日誌是502腳本出錯了,
取消對502的監控,針對load.sh的監控
[root@centos7-01 bin]# vim ../conf/mon.conf
找到to_mon_502=1修改to_mon_502=0
2.3 調試期間,還不太需要把錯誤與正確的輸出寫入日誌裏面,so把寫入信息到日誌的輸出命令註釋
找到exec 1>>../log/mon.log 2>>../log/err.log 前面添加#把其命令註釋掉,使其不生效
3 修改後,繼續執行監控主腳本main.sh
[root@centos7-01 bin]# sh -x main.sh -x + export send=1 + send=1 ++ /sbin/ifconfig ++ grep -A1 'ens33: ' ++ awk '/inet/ {print $2}' + export addr=192.168.189.128 + addr=192.168.189.128 ++ pwd + dir=/usr/local/sbin/mon/bin ++ echo /usr/local/sbin/mon/bin ++ awk -F/ '{print $NF}' + last_dir=bin + '[' bin == bin ']' + conf_file=../conf/mon.conf ++ date '+%F %T' + echo '2018-06-05 17:26:07 load average' 2018-06-05 17:26:07 load average + /bin/bash ../shares/load.sh 17:26:07 load is 0 + grep -q to_mon_502=1 ../conf/mon.conf
腳本執行輸出load=0,執行腳本沒問題
3.1 覈實結果,執行腳本測試,輸出正常
[root@centos7-01 bin]# bash ../shares/load.sh
17:36:45 load is 0
4 告警
告警測試此處不做測試了,可以創建告警環境來進行測試。