郵件告警系統

需求: 使用shell定製各種個性化告警工具,但需要統一化管理、規範化管理。

思路:指定一個腳本包,包含主程序、子程序、配置文件、郵件引擎、輸出日誌等。
主程序:作爲整個腳本的入口,是整個系統的命脈。
配置文件:是一個控制中心,用它來開關各個子程序,指定各個相關聯的日誌文件。
子程序:這個纔是真正的監控腳本,用來監控各個指標。
郵件引擎:是由一個php程序來實現,它可以定義發郵件的服務器、發郵件人以及收郵件人。
輸出日誌:整個監控系統要有日誌輸出。

要求:我們的機器角色多種多樣,但是所有機器上都要部署同樣的監控系統,也就說所有機器不管什麼角色,整個程序框架都是一致的,不同的地方在於根據不同的角色,定製不同的配置文件。

程序架構:   

                                         (主目錄 mon)
                 ____________________|_______________________________
                |              |                    |                       |                             |
               bin          conf            shares                  mail                         log
                |              |                    |                       |                             |
           [main.sh] [ mon.conf] [load.sh 502.sh]  [mail.php mail.sh] [  mon.log  err.log ]

bin下是主程序
conf下是配置文件
shares下是各個監控腳本
mail下是郵件引擎
log下是日誌。
1. main.sh

  1. #!/bin/bash

  2. #Written by aming.


  3. # 是否發送郵件的開關

  4. export send=1     //對send進行環境變量賦值:1爲開,0爲關。如果關閉則郵件不會發送,當你已經知道並着手時可以將此設置爲0

  5. # 過濾ip地址

  6. export addr=`/sbin/ifconfig |grep -A1 'eth0' |grep addr: |awk '{print $2}'|awk -F: '{print $2}'`      //對addr進行環境變量賦值:addr=本機IP

  7. dir=`pwd`        //dir爲當前目錄路徑

  8. # 只需要最後一級目錄名

  9. last_dir=`echo $dir|awk -F'/' '{print $NF}'`  //awk出最後一段內容即當前目錄


  10. # 下面的判斷目的是,保證執行腳本的時候,我們在bin目錄裏,不然監控腳本、郵件和日誌很有可能找不(但是我覺得這裏有bug,萬一main.sh的bin目錄是在其它路徑下呢)

  11. if [ $last_dir == "bin" ] || [ $last_dir == "bin/" ]; then

  12.     conf_file="../conf/mon.conf"    //如果目錄存在則進行變量賦值(這裏我們需要將各個配置和腳本放在指定的目錄下

  13. else

  14.     echo "you shoud cd bin dir //如果目錄不對則在窗口打印出提示,退出主程

  15.     exit

  16. fi

  17. #目錄正確條件下

  18. exec 1>>../log/mon.log 2>>../log/err.log //標準輸出追加重定向到mon.log;錯誤追加到err.lo


  19. echo "`date +"%F %T"` load average"  //打印出 時間 ,執行load.sh腳

  20. /bin/bash ../shares/load.sh


  21. #先檢查配置文件中是否需要監控502

  22. if grep -q 'to_mon_502=1' $conf_file; then  //grep -q 只作爲判斷條件,若1則對log進行環境變量賦值,即mon.conf中的/data/log/xxx.xxx.com/access.log,執行502.sh腳本

  23.     export log=`grep 'logfile=' $conf_file |awk -F '=' '{print $2}' |sed 's/ //g'`

  24.     /bin/bash  ../shares/502.sh

  25. fi


主程序只添加了502監控,根據需求我們可以在mon.conf和main.sh中按模板添加監控項目。但是需要將整個告警系統copy過去,保證系統的完整性。
2.  配置文件   mon.conf

  1. ## to config the options if to monitor


  2. ## cdb  主要定義mysql的服務器地址、端口以及user、password

  3. to_mon_cdb=0   ##0 or 1, default 0,0 not monitor, 1 monitor

  4. cdb_ip=10.20.3.13

  5. cdb_port=3315

  6. cdb_user=username

  7. cdb_pass=passwd


  8. ## httpd   如果是1則監控,爲0不監控

  9. to_mon_httpd=0


  10. ## php 如果是1則監控,爲0不監控

  11. to_mon_php_socket=0


  12. ## http_code_502  需要定義訪問日誌的路徑

  13. to_mon_502=1

  14. logfile=/data/log/xxx.xxx.com/access.log


  15. ## request_count   定義日誌路徑以及域名

  16. to_mon_request_count=0

  17. req_log=/data/log/www.discuz.net/access.log

  18. domainname=www.discuz.net



mon.conf配置文件還是很好理解的。
3. load.sh

  1. #! /bin/bash


  2. ##Writen by aming##


  3. load=`uptime |awk -F 'average:' '{print $2}'|cut -d',' -f1|sed 's/ //g' |cut -d. -f1`   //load是1分鐘負載的整數部分數值

  4. if [ $load -gt 20 ] && [ $send -eq "1" ]   //如果負載大於20(具體看自己系統硬件條件)且開啓發送郵件則將“時間+負載”重定向到load.tmp,執行發送郵件腳本“$1 $2” $3,“$1 $2”是主題,$3是內容,跟mail.sh格式相同

  5.     echo "$addr `date +%T` load is $load" >../log/load.tmp

  6.     /bin/bash ../mail/mail.sh $addr\_load $load ../log/load.tmp

  7. fi

  8. echo "`date +%T` load is $load"    //打印“時間+負載”


4. 502.sh

  1. #! /bin/bash

  2. d=`date -d "-1 min" +%H:%M`     //將一分鐘前的時間賦值給d

  3. c_502=`grep :$d:  $log  |grep ' 502 '|wc -l`   //過濾統計/data/log/xxx.xxx.com/access.log中502的次數

  4. if [ $c_502 -gt 10 ] && [ $send == 1 ]; then       //如果一分鐘前日誌中502的次數超過10次,且郵件開,則將“IP+時間+502次數”重定向到502.tmp,發送郵件

  5.      echo "$addr $d 502 count is $c_502">../log/502.tmp

  6.      /bin/bash ../mail/mail.sh $addr\_502 $c_502  ../log/502.tmp

  7. fi

  8. echo "`date +%T` 502 $c_502"    //打印“時間+502次數”


*擴展disk.sh

  1. #! /bin/bash


  2. ##Writen by aming##


  3. rm -f ../log/disk.tmp

  4. for r in `df -h |awk -F '[ %]+' '{print $5}'|grep -v Use`   //過濾出磁盤Use的三個數據

  5. do

  6.     if [ $r -gt 90 ] && [ $send -eq "1" ]      //如果有數據大於90,且郵件開,則將“時間+Use值追加重定向到disk.tmp(遺憾的是不清楚是哪個盤Use大於90)

  7. then

  8.     echo "$addr `date +%T` disk useage is $r" >>../log/disk.tmp

  9. fi


  10. if [ -f ../log/disk.tmp ]

  11. then

  12.     df -h >> ../log/disk.tmp

  13.     /bin/bash ../mail/mail.sh $addr\_disk $r ../log/disk.tmp

  14.     echo "`date +%T` disk useage is nook"

  15. else

  16.     echo "`date +%T` disk useage is ok"

  17. fi


5. mail.php

  1. <?php

  2. class Smtp

  3. {

  4.     /* Public Variables */

  5.     var $smtp_port;

  6.     var $time_out;

  7.     var $host_name;

  8.     var $log_file;

  9.     var $relay_host;

  10.     var $debug;

  11.     var $auth;

  12.     var $user;

  13.     var $pass;

  14.     /* Private Variables */

  15.     var $sock;

  16.     /* Constractor */

  17.     function Smtp($relay_host = "", $smtp_port = 25,$auth = false,$user,$pass)

  18.     {

  19.         $this->debug = FALSE;

  20.         $this->smtp_port = $smtp_port;

  21.         $this->relay_host = $relay_host;

  22.         $this->time_out = 30; //is used in fsockopen()

  23.         #

  24.         $this->auth = $auth;//auth

  25.         $this->user = $user;

  26.         $this->pass = $pass;

  27.         #

  28.         $this->host_name = "localhost"; //is used in HELO command

  29.         $this->log_file = "";

  30.         $this->sock = FALSE;

  31.     }

  32.     /* Main Function */

  33.     function sendmail($to, $from, $subject = "", $body = "", $mailtype, $cc = "", $bcc = "", $additional_headers = "")

  34.     {

  35.         $mail_from = $this->get_address($this->strip_comment($from));

  36.         $body = ereg_replace("(^|(\r\n))(\.)", "\1.\3", $body);

  37.         $header = "MIME-Version:1.0\r\n";

  38.         if($mailtype=="HTML"){

  39.             $header .= "Content-Type:text/html\r\n";

  40.         }

  41.         $header .= "To: ".$to."\r\n";

  42.         if ($cc != "") {

  43.             $header .= "Cc: ".$cc."\r\n";

  44.         }

  45.         $header .= "From: $from<".$from.">\r\n";

  46.         $header .= "Subject: ".$subject."\r\n";

  47.         $header .= $additional_headers;

  48.         $header .= "Date: ".date("r")."\r\n";

  49.         $header .= "X-Mailer:By Redhat (PHP/".phpversion().")\r\n";

  50.         list($msec, $sec) = explode(" ", microtime());

  51.         $header .= "Message-ID: <".date("YmdHis", $sec).".".($msec*1000000).".".$mail_from.">\r\n";

  52.         $TO = explode(",", $this->strip_comment($to));

  53.         if ($cc != "") {

  54.             $TO = array_merge($TO, explode(",", $this->strip_comment($cc)));

  55.         }


  56.         if ($bcc != "") {

  57.             $TO = array_merge($TO, explode(",", $this->strip_comment($bcc)));

  58.         }

  59.         $sent = TRUE;

  60.         foreach ($TO as $rcpt_to) {

  61.             $rcpt_to = $this->get_address($rcpt_to);


  62.             if (!$this->smtp_sockopen($rcpt_to)) {

  63.                 $this->log_write("Error: Cannot send email to ".$rcpt_to."\n");

  64.                 $sent = FALSE;

  65.                 continue;

  66.             }

  67.             if ($this->smtp_send($this->host_name, $mail_from, $rcpt_to, $header, $body)) {

  68.                 $this->log_write("E-mail has been sent to <".$rcpt_to.">\n");

  69.             } else {

  70.                 $this->log_write("Error: Cannot send email to <".$rcpt_to.">\n");

  71.                 $sent = FALSE;

  72.             }

  73.             fclose($this->sock);

  74.             $this->log_write("Disconnected from remote host\n");

  75.         }

  76.         return $sent;

  77.     }

  78. /* Private Functions */

  79.    function smtp_send($helo, $from, $to, $header, $body = "")

  80.     {

  81.         if (!$this->smtp_putcmd("HELO", $helo)) {

  82.             return $this->smtp_error("sending HELO command");

  83.         }

  84.         #auth

  85.         if($this->auth){

  86.             if (!$this->smtp_putcmd("AUTH LOGIN", base64_encode($this->user))) {

  87.                 return $this->smtp_error("sending HELO command");

  88.             }

  89.             if (!$this->smtp_putcmd("", base64_encode($this->pass))) {

  90.                 return $this->smtp_error("sending HELO command");

  91.             }

  92.         }

  93.         #

  94.         if (!$this->smtp_putcmd("MAIL", "FROM:<".$from.">")) {

  95.             return $this->smtp_error("sending MAIL FROM command");

  96.         }

  97.         if (!$this->smtp_putcmd("RCPT", "TO:<".$to.">")) {

  98.             return $this->smtp_error("sending RCPT TO command");

  99.         }

  100.         if (!$this->smtp_putcmd("DATA")) {

  101.             return $this->smtp_error("sending DATA command");

  102.         }

  103.         if (!$this->smtp_message($header, $body)) {

  104.             return $this->smtp_error("sending message");

  105.         }

  106.         if (!$this->smtp_eom()) {

  107.             return $this->smtp_error("sending . [EOM]");

  108.         }

  109.         if (!$this->smtp_putcmd("QUIT")) {

  110.             return $this->smtp_error("sending QUIT command");

  111.         }

  112.         return TRUE;

  113.     }


  114.     function smtp_sockopen($address)

  115.     {

  116.         if ($this->relay_host == "") {

  117.             return $this->smtp_sockopen_mx($address);

  118.         } else {

  119.             return $this->smtp_sockopen_relay();

  120.         }

  121.     }

  122.     function smtp_sockopen_relay()

  123.     {

  124.         $this->log_write("Trying to ".$this->relay_host.":".$this->smtp_port."\n");

  125.         $this->sock = @fsockopen($this->relay_host, $this->smtp_port, $errno, $errstr, $this->time_out);

  126.         if (!($this->sock && $this->smtp_ok())) {

  127.             $this->log_write("Error: Cannot connenct to relay host ".$this->relay_host."\n");

  128.             $this->log_write("Error: ".$errstr." (".$errno.")\n");

  129.             return FALSE;

  130.         }

  131.         $this->log_write("Connected to relay host ".$this->relay_host."\n");

  132.         return TRUE;

  133.     }

  134.     function smtp_sockopen_mx($address)

  135.     {

  136.         $domain = ereg_replace("^.+@([^@]+)[        DISCUZ_CODE_5        ]quot;, "\1", $address);

  137.         if (!@getmxrr($domain, $MXHOSTS)) {

  138.             $this->log_write("Error: Cannot resolve MX \"".$domain."\"\n");

  139.             return FALSE;

  140.         }

  141.         foreach ($MXHOSTS as $host) {

  142.             $this->log_write("Trying to ".$host.":".$this->smtp_port."\n");

  143.            $this->sock = @fsockopen($host, $this->smtp_port, $errno, $errstr, $this->time_out);

  144.             if (!($this->sock && $this->smtp_ok())) {

  145.                 $this->log_write("Warning: Cannot connect to mx host ".$host."\n");

  146.                 $this->log_write("Error: ".$errstr." (".$errno.")\n");

  147.                continue;

  148.             }

  149.             $this->log_write("Connected to mx host ".$host."\n");

  150.             return TRUE;

  151.         }

  152.         $this->log_write("Error: Cannot connect to any mx hosts (".implode(", ", $MXHOSTS).")\n");

  153.        return FALSE;

  154.     }

  155.     function smtp_message($header, $body)

  156.     {

  157.       fputs($this->sock, $header."\r\n".$body);

  158.         $this->smtp_debug("> ".str_replace("\r\n", "\n"."> ", $header."\n> ".$body."\n> "));

  159.         return TRUE;

  160.     }

  161.     function smtp_eom()

  162.    {

  163.         fputs($this->sock, "\r\n.\r\n");

  164.         $this->smtp_debug(". [EOM]\n");

  165.         return $this->smtp_ok();

  166.     }

  167.     function smtp_ok()

  168.    {

  169.         $response = str_replace("\r\n", "", fgets($this->sock, 512));

  170.         $this->smtp_debug($response."\n");

  171.         if (!ereg("^[23]", $response)) {

  172.             fputs($this->sock, "QUIT\r\n");

  173.             fgets($this->sock, 512);

  174.             $this->log_write("Error: Remote host returned \"".$response."\"\n");

  175.             return FALSE;

  176.         }

  177.         return TRUE;

  178.     }

  179.     function smtp_putcmd($cmd, $arg = "")

  180.     {

  181.         if ($arg != "") {

  182.            if($cmd=="") $cmd = $arg;

  183.             else $cmd = $cmd." ".$arg;

  184.         }

  185.         fputs($this->sock, $cmd."\r\n");

  186.         $this->smtp_debug("> ".$cmd."\n");

  187.         return $this->smtp_ok();

  188.     }

  189.     function smtp_error($string)

  190.     {

  191.         $this->log_write("Error: Error occurred while ".$string.".\n");

  192.         return FALSE;

  193.     }

  194.     function log_write($message)

  195.     {

  196.         $this->smtp_debug($message);

  197.         if ($this->log_file == "") {

  198.                 return TRUE;

  199.         }

  200.         $message = date("M d H:i:s ").get_current_user()."[".getmypid()."]: ".$message;

  201.         if (!@file_exists($this->log_file) || !($fp = @fopen($this->log_file, "a"))) {

  202.             $this->smtp_debug("Warning: Cannot open log file \"".$this->log_file."\"\n");

  203.             return FALSE;;

  204.         }

  205.         flock($fp, LOCK_EX);

  206.         fputs($fp, $message);

  207.         fclose($fp);

  208.         return TRUE;

  209.     }

  210.     function strip_comment($address)

  211.    {

  212.         $comment = "\([^()]*\)";

  213.        while (ereg($comment, $address)) {

  214.             $address = ereg_replace($comment, "", $address);

  215.         }

  216.         return $address;

  217.     }

  218.     function get_address($address)

  219.     {

  220.         $address = ereg_replace("([ \t\r\n])+", "", $address);

  221.         $address = ereg_replace("^.*<(.+)>.*[        DISCUZ_CODE_5        ]quot;, "\1", $address);

  222.         return $address;

  223.     }

  224.     function smtp_debug($message)

  225.     {

  226.         if ($this->debug) {

  227.         echo $message;

  228.         }

  229.     }

  230. }

  231. $file = $argv[2];

  232. $smtpserver = "smtp.qq.com";//SMTP服務器

  233. $smtpserverport = "25";//SMTP服務器端口

  234. $smtpusermail = "[email protected]";//SMTP服務器的用戶郵箱

  235. $smtpemailto = "[email protected]";//發送給誰

  236. $smtpuser = "1198658";//SMTP服務器的用戶帳號

  237. $smtppass = "1212lss";//SMTP服務器的用戶密碼   (注意的是:這個密碼是郵箱的獨立祕密,而不是郵箱的登陸密碼)

  238. $mailsubject = $argv[1];//郵件主題

  239. $mailbody = file_get_contents($file);//郵件內容

  240. $mailtype = "HTML";//郵件格式(HTML/TXT),TXT爲文本郵件

  241. $smtp = new smtp($smtpserver,$smtpserverport,true,$smtpuser,$smtppass);//這裏面的一個true是表示使用身份驗證,否則不使用身份驗證.

  242. //$smtp->debug = TRUE;//是否顯示發送的調試信息

  243. $smtp->sendmail($smtpemailto, $smtpusermail, $mailsubject, $mailbody, $mailtype);

  244. ?>


好吧,不懂php,只能將參數理一理。
要想發郵件的話,首先要有php支持,若你沒有安裝過lamp或者lnmp,則需要運行yum install -y php 安裝。
然後運行  php  mail.php  "郵箱主題寫在這裏" "/tmp/test.txt"   。其中,/tmp/test.txt 內容爲郵件內容。
6. mail.sh
   
  

  1. log=$1   //$1是發送郵件時的$1,比如502.sh中的$addr\_502

  2.     t_s=`date +%s`   //記錄當前時間

  3.     t_s2=`date -d "2 hours ago" +%s`   //記錄2個小時之前的時間

  4.     if [ ! -f /tmp/$log ]    //如果文件不存在,則將2個小時之前的時間重定向到這個文件

  5.     then

  6.         echo $t_s2 > /tmp/$log

  7.     fi

  8.     t_s2=`tail -1 /tmp/$log|awk '{print $1}'`   //如果文件存在,將這個文件最後一個時間賦值給ts_2

  9.     echo $t_s>>/tmp/$log   //將當前時間追加重定向到這個文件中

  10.     v=$[$t_s-$t_s2]           //記錄倆次時間的間隔

  11.         echo $v

  12.     if [ $v -gt 3600 ]     //第一次執行這個腳本時,因爲/tmp/$log的最後一個時間是2個小時之前,相當於7200,肯定是大於3600的,所以會先發送一份郵件;但如果後面一直報警(要注意的是我們在crontab任務計劃中是1分鐘執行一次main.sh),$v會小於3600也就是1小時,則腳本會不發送郵件,而對$log.txt裏的數值從0進行累加,直到大於10,再發送一封郵件,並重新將0重定向到$log.txt,等待下一輪10

  13.     then   

  14.         /dir/to/php ../mail/mail.php "$1 $2" "$3"

  15.         echo "0" > /tmp/$log.txt

  16.     else   

  17.         if [ ! -f /tmp/$log.txt ]

  18.         then

  19.             echo "0" > /tmp/$log.txt

  20.         fi

  21.         nu=`cat /tmp/$log.txt`

  22.         nu2=$[$nu+1]

  23.         echo $nu2>/tmp/$log.txt

  24.         if [ $nu2 -gt 10 ]

  25.         then   

  26.             /dir/to/php ../mail/mail.php "trouble continue 10 min $1  $2 " "$3"

  27.              echo "0" > /tmp/$log.txt

  28.         fi      

  29.     fi


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章