笔记内容:使用shell编写一个简单的告警系统php
笔记日期:2017-11-28python
<br>mysql
<br>sql
在这以前的笔记里,将大部分的经常使用shell基本语法已经介绍完了,在这以后就是实战一些小项目了。这个项目是作一个简单的告警系统,用于完成一些简单个性化的需求。shell
目录结构与要求:vim
<br>
<br>bash
首先咱们要编写一个告警系统的主脚本,我这里是放在了/usr/local/sbin/目录下,这个主脚本的文件名称为main.sh,在编写脚本以前咱们还须要建立一个完整的目录结构:服务器
[root@localhost ~]# cd /usr/local/sbin/ [root@localhost /usr/local/sbin]# mkdir mon [root@localhost /usr/local/sbin]# cd mon [root@localhost /usr/local/sbin/mon]# mkdir bin conf shares log mail [root@localhost /usr/local/sbin/mon]# cd bin [root@localhost /usr/local/sbin/mon/bin]#vim main.sh
而后进入到以上建立的bin目录下,编辑main.sh脚本, main.sh内容以下:dom
#!/bin/bash #Written by aming. # 是否打开发送邮件的开关,1为打开 export send=1 # 过滤ip地址,为了告诉咱们发送邮件的IP,注意这里的网卡名称要改成你的网卡名称 export addr=`/sbin/ifconfig |grep -A1 "eth0: " |awk '/inet/ {print $2}'` # 把当前路径拿出来 dir=`pwd` # 只须要最后一级目录名 last_dir=`echo $dir|awk -F'/' '{print $NF}'` # 下面的判断目的是,保证执行脚本的时候,咱们在bin目录里,否则监控脚本、邮件和日志颇有可能找不到 if [ $last_dir == "bin" ] || [ $last_dir == "bin/" ]; then # 定义配置文件所在的路径 conf_file="../conf/mon.conf" else # 若是不在bin目录下就退出整个脚本 echo "you shoud cd bin dir" exit fi # 输出正确日志和错误日志 exec 1>>../log/mon.log 2>>../log/err.log # 给日志记录标记一个时间,还有系统负载 echo "`date +"%F %T"` load average" # 执行load.sh子脚本 /bin/bash ../shares/load.sh #先检查配置文件中是否须要监控502.sh if grep -q 'to_mon_502=1' $conf_file; then # 过滤出在配置文件中定义的日志文件路径 export log=`grep 'logfile=' $conf_file |awk -F '=' '{print $2}' |sed 's/ //g'` /bin/bash ../shares/502.sh fi
<br>socket
主脚本编写完以后,就是编写配置文件,配置文件比较简单里面主要就是一些定义开关的开启关闭状态和日志文件路径等内容。配置文件要放在/usr/local/sbin/mon/conf/下,文件名称必须为mon.conf,由于在主脚本里已经定义了:
[root@localhost ~]# cd /usr/local/sbin/mon/conf/ [root@localhost /usr/local/sbin/mon/conf]# vim mon.conf
mon.conf文件的内容以下:
## to config the options if to monitor ## 定义mysql的服务器地址、端口以及user、password to_mon_cdb=0 ##0 or 1, default 0,0 not monitor, 1 monitor db_ip=10.20.3.13 db_port=3315 db_user=username db_pass=passwd ## httpd 若是是1则监控,为0不监控 to_mon_httpd=0 ## php 若是是1则监控,为0不监控 to_mon_php_socket=0 ## http_code_502 须要定义访问日志的路径 to_mon_502=1 # 定义日志文件路径 logfile=/data/log/xxx.xxx.com/access.log ## request_count 定义是否监控请求数量 to_mon_request_count=0 # 定义请求日志的路径 req_log=/data/log/www.discuz.net/access.log # 定义域名 domainname=www.discuz.net
配置文件的参数能够自定义,自己配置文件就是用来给用户定义的。
<br>
编写子脚本,也就是监控项目,这个load.sh子脚本是必需要有的,这个脚本用来监控系统负载,由于在主脚本里已经定义了须要执行这个子脚原本进行监控系统负载。这个脚本须要放在/usr/local/sbin/mon/shares/ 目录下,并且之后的子脚本都是放在这个目录下,由于主脚本里已经定义了:
[root@localhost ~]# cd /usr/local/sbin/mon/shares/ [root@localhost /usr/local/sbin/mon/shares]# vim load.sh
load.sh内容以下:
#! /bin/bash # 定义load的值 load=`uptime |awk -F 'average:' '{print $2}'|cut -d',' -f1|sed 's/ //g' |cut -d. -f1` # 判断系统负载是否高于预设值和发送邮件的开关是否打开 if [ $load -gt 10 ] && [ $send -eq "1" ] then # 输出一条日志记录,这个日志会做为邮件内容 echo "$addr `date +%T` load is $load" >../log/load.tmp # 执行发邮件的脚本,这里的邮箱地址写你的邮箱地址 /bin/bash ../mail/mail.sh your_email@163.com "$addr\_load:$load" `cat ../log/load.tmp` fi # 输出日志到主脚本中指定的日志文件 echo "`date +%T` load is $load"
<br>
这个脚本用于监控502状态码发生的次数。
502.sh内容以下:
#! /bin/bash # 截取一分钟之前的时间 d=`date -d "-1 min" +%H:%M` # 得到502状态码发生的次数 c_502=`grep :$d: $log |grep ' 502 '|wc -l` # 次数大于预设值,而且发送邮件的开关为打开状态,就发送告警邮件 if [ $c_502 -gt 10 ] && [ $send == 1 ]; then # 记录日志信息做为告警邮件的内容 echo "$addr $d 502 count is $c_502">../log/502.tmp # 调用发送邮件的脚本 /bin/bash ../mail/mail.sh $addr\_502 $c_502 ../log/502.tmp fi # 记录日志 echo "`date +%T` 502 $c_502"
<br>
这个脚本是用来监控磁盘使用率的,这个脚本会把每一个磁盘分区挨个看一下。
disk.sh内容以下:
#! /bin/bash # 先删除以前记录的日志文件 rm -f ../log/disk.tmp # 先把环境语言改成英文,由于是按照英文来进行过滤的 LANG=en # 遍历出df -h 命令结果中为已用那一列的百分比数字 for r in `df -h |awk -F '[ %]+' '{print $5}'|grep -v Use` do # 若是有分区的已用率大于90就记录日志 if [ $r -gt 90 ] && [ $send -eq "1" ] then echo "$addr `date +%T` disk useage is $r" >>../log/disk.tmp fi # 判断日志文件是否存在 if [ -f ../log/disk.tmp ] then # 文件存在就发送邮件 df -h >> ../log/disk.tmp /bin/bash ../mail/mail.sh $addr\_disk $r ../log/disk.tmp echo "`date +%T` disk useage is nook" else # 不存在则记录日志 echo "`date +%T` disk useage is ok" fi
<br>
在编写mail.sh以前,先得准备一个发送邮件的功能性脚本,由于这个告警系统会在监控项出现问题的时候发送告警邮件,因此还须要编写一个可以发送邮件的脚本,我这里使用的脚本是python编写的,这个脚本放在/usr/local/sbin/mon/mail 目录下:
[root@localhost ~]# cd /usr/local/sbin/mon/mail [root@localhost /usr/local/sbin/mon/mail]# vim mail.py
脚本内容以下:
#!/usr/bin/env python #-*- coding: UTF-8 -*- import os,sys reload(sys) sys.setdefaultencoding('utf-8') 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): # 这里要修改成你邮箱的smtp服务地址,例如163邮箱的话,就是:smtp.163.com gserver = 'smtp.example.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] ##定义邮箱的帐号和密码,你须要修改为你本身的帐号和密码 sendqqmail('email@example.com','password','email@example.com',to,subject,content) if __name__ == "__main__": main() #####脚本使用说明###### #1. 首先定义好脚本中的邮箱帐号和密码 #2. 脚本执行命令为:python mail.py 目标邮箱 "邮件主题" "邮件内容"
而后再编写mail.sh脚本,这个脚本是作告警收敛的,由于以后会设定1分钟进行监控一次,因此主要用于控制当告警持续了10分钟后才发送告警邮件,这个脚本和mail.py同样也是放在mail/目录下,脚本内容以下:
#!/bin/bash # 拿到当前脚本的第一个参数,也就是以前在子脚本中定义的监控项的标识与机器IP 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 # 就发送告警邮件 /usr/bin/python /usr/local/sbin/mon/mail/mail.py $1 $2 $3 # 而且生成一个新的日志,用于记录告警持续的次数 echo "0" > /tmp/$log.txt else # 时间差小于一小时就表明不是第一次告警了,因此判断一下log.txt文件是否存在 if [ ! -f /tmp/$log.txt ] then # 不存在就生成一个 echo "0" > /tmp/$log.txt fi # 拿出log.txt文件的内容 nu=`cat /tmp/$log.txt` # 进行计数 nu2=$[$nu+1] # 而后再写入到log.txt中,其实这个文件就至关因而一个计数器 echo $nu2>/tmp/$log.txt # 判断计的数是否大于10 if [ $nu2 -gt 10 ] then # 是的话就发送一个告警邮件说明告警持续10分钟了 /usr/bin/python /usr/local/sbin/mon/mail/mail.py $1 "trouble continue 10 min $2" "$3" # 从新计数 echo "0" > /tmp/$log.txt fi fi
<br>
想要正常的运行这个告警系统你须要写一个任务计划,每分钟执行一次 main.sh 主脚本:
[root@localhost ~]# crontab -e * * * * * cd /usr/local/sbin/mon/bin; bash main.sh
不过,我这里因为只是作实验就不写以上这个任务计划了,直接手动运行,方便一会进行测试。在这以前须要修改一下配置文件,将to_mon_502改成0,由于本实验环境中并无502.sh脚本里定义的站点目录,因此打开这个监控项的话会报错,而后还须要注释掉 main.sh 主脚本中的写入日志那句代码:
[root@localhost ~]# cd /usr/local/sbin/mon/conf [root@localhost /usr/local/sbin/mon/conf]# vim mon.conf # 改成 0 to_mon_502=0 [root@localhost /usr/local/sbin/mon/conf]# cd ../bin [root@localhost /usr/local/sbin/mon/bin]# vim main.sh # 注释这一句代码 # exec 1>>../log/mon.log 2>>../log/err.log
完成以上操做后,执行 main.sh 主脚本:
[root@localhost /usr/local/sbin/mon/bin]# sh main.sh 2017-11-29 00:03:39 load average 00:03:39 load is 0 [root@localhost /usr/local/sbin/mon/bin]#
运行结果如上,没有出现报错信息,表明 load.sh 可以被正常执行。
以上已经验证load.sh 能够正常被执行了,接下来咱们再来测试一下可否正常发送邮件,首先修改一下load.sh中的判断条件,修改为小于10,由于要故意让它报警:
[root@localhost ~]# cd /usr/local/sbin/mon/shares/ [root@localhost /usr/local/sbin/mon/shares]# vim load.sh if [ $load -lt 10 ] && [ $send -eq "1" ]
而后到bin目录下执行11次主脚本,由于我没有定义任务计划,因此须要模拟一分钟执行一次的状况,执行到第11次的时候会停顿一下,这是由于在发送邮件中:
[root@localhost /usr/local/sbin/mon/shares]# cd ../bin/ [root@localhost /usr/local/sbin/mon/bin]# sh main.sh ......执行11次
测试结果是邮件可以正常收到,内容以下图:
<br>
完结:以上就是如何使用shell语言去编写一个简单监控系统,而且通过简单的测试证实可以正常使用,若是实验过程当中遇到问题欢迎私信。