根据urlooker的推送数据,生成应用存活报表(反正感觉很傻~)
一、要求
最近公司大佬要求将应用每天的存活状态,输出成报表的形式,每天以邮件的方式发送给他们。报表里面要输出:应用名、应用所在服务器IP、应用挂掉的时间点、应用挂掉的持续时间。
二、环境介绍
我们公司用的监控系统,是小米的open-falcon,而app-alive的监控是用小米推荐的urlooker,urlooker监控的模式,是每分钟将应用状态推送到open-falcon。而我们这边又用自己拿框架开发的ops系统,ops直接调用open-falcon的接口,在ops里面,可以看到应用存活的状态,且ops.app_detail表记录了应用id(唯一标识)及应用名。所以一开始我的想法是:去ops记录应用状态的表直接查询。结果去查询才发现,ops有两张表是记录跟应用状态有关的数据。一张记录的是应用down掉持续时间聚合后的信息,一张记录的是1天、30天应用的存活率。。。。这根本跟我要的东西不一样,所以最后思考半天,我决定直接去urlooker拿取数据。
关于urlooker数据库:
有两张表跟app-alive有关:urlooker.strategy和 urlooker.item_status00,第一张表有两个字段有用:urlooker.strategy.ops_cp_app_id(与ops.app_detail.id一一对应)和urlooker.strategy.environment(区分测试、预发布、release环境),第二张表urlooker.item_status00即是urlooker每分钟push的数据,这张表默认保存12小时的数据。
三、查询urlooker数据库获取数据源
通过跨库联表查询,获取所需的数据源,我这里查询的结果是所有 result不为0即应用挂掉状态的信息,并通过组内排序输出。
SELECT ops.app_detail.app_name, urlooker.item_status00.sid AS sid, urlooker.strategy.ops_cp_app_id, urlooker.item_status00.ip, urlooker.strategy.note, urlooker.item_status00.result, ROUND( urlooker.item_status00.push_time ) AS down_time, FROM_UNIXTIME( urlooker.item_status00.push_time ) AS new_time FROM urlooker.item_status00 LEFT JOIN urlooker.strategy ON urlooker.item_status00.sid = urlooker.strategy.id LEFT JOIN ops.app_detail ON ops.app_detail.id = urlooker.strategy.ops_cp_app_id WHERE urlooker.strategy.environment = "release" AND urlooker.item_status00.result <> "0" ORDER BY sid DESC, down_time DESC;
本来我想直接通过sql取做定时任务,但是关于数据源的计算及处理,实在不知道咋整(吃了没技术的亏啊,应该用存储过程可以实现)。所以直接将数据源导出,用shell去处理。
四、处理数据源
编写shell脚本,处理数据源:
# cat send_app_alived.sh #!/bin/bashDataInputPath=/home/app-alive/source.txtDataOutputPath=/home/app-alive/$(date +%F)-output.csv#data mysql -uops_ro -pxxxx -e "source /home/app-alive/select.sql" > $DataInputPath 2>/dev/nullapp_id=$(awk '{ print $2}' $DataInputPath |grep -v sid|uniq)if [ ! -f "$DataOutputPath" ];then echo "应用名,服务器IP,应用停止时间,停止持续时间" > $DataOutputPathfifor id in $app_iddo down_time=$(awk '{if($2=='$id') print $7}' $DataInputPath) app_name=$(awk '{if($2=='$id') print $1}' $DataInputPath|uniq) app_ip=$(awk '{if($2=='$id') print $4}' $DataInputPath|uniq) down_time_num=$(awk '{if($2=='$id') print $7}' $DataInputPath|wc -l) if [ "$down_time_num" -eq "1" ]; then G_time=$(date -d "1970-01-01 UTC $down_time seconds" +"%Y-%m-%d %H:%M") echo "$app_name,$app_ip,$G_time,1分钟" >> $DataOutputPath else sum=0 count=0 for i in $down_time do sum=$((i-sum)) if [ $sum -ne -60 ] && [ $sum -ne $i ]; then G_time=$(date -d "1970-01-01 UTC $down_sum seconds" +"%Y-%m-%d %H:%M") echo "$app_name,$app_ip,$G_time,${count}分钟" >> $DataOutputPath count=0 fi if [ $count -eq 0 ]; then down_sum=$i fi count=$((count + 1)) sum=$i done if [ $count -eq 1 ]; then G_time=$(date -d "1970-01-01 UTC $down_sum seconds" +"%Y-%m-%d %H:%M") echo "$app_name,$app_ip,$G_time,1分钟" >> $DataOutputPath fi fidone
这个脚本处理完后,输出的结果为:
# cat 2019-10-24-output.csv
用名,服务器IP,应用停止时间,停止持续时间
app01,10.25.100.36,2019-10-24 02:21,1分钟
app01,10.81.126.19,2019-10-24 02:17,1分钟
app02,10.81.126.19,2019-10-24 10:43,14分钟
......
但是这里输出的只是12小时的数据,所以加个计划任务:
59 11,23 * * * /usr/bin/bash /home/app-alive/send_app_alived.sh
五、python脚本发送邮件
网上随便找个python脚本,修改下:
# cat sendmail.py# !/usr/bin/env python# -*- coding: utf-8 -*-import smtplibimport email.mime.multipartimport email.mime.textfrom email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipartfrom email.mime.application import MIMEApplicationfrom email.mime.multipart import MIMEMultipartfrom email.mime.base import MIMEBaseimport emailimport base64import timeimport osclass send_mail:def __init__(self, From, To, pw, file_path, file_header, file_body):# 发送人self.From = From# 收件人['aaa@a.com','bbb@a.com']self.To = list(To)#抄送人# self.Cc = list(Cc)# 登录邮件密码base64.encodestring('明文')加密后密码self.pw = pw# 文件具体路径(路径+文件名称)self.file_path = file_path# 标题头self.file_header = file_header# 内容self.file_body = file_bodydef login(self):server = smtplib.SMTP('smtp.qq.com')server.starttls()# pwd = base64.decodestring(self.pw)server.login(self.From, self.pw)try:receive = self.To#receive.extend(self.Cc)server.sendmail(self.From,self.To,self.atta())finally:server.quit()def atta(self):main_msg = MIMEMultipart()# 内容text_msg = MIMEText(self.file_body)main_msg.attach(text_msg)try:contype = 'application/octet-stream'maintype, subtype = contype.split('/', 1)data = open(self.file_path, 'rb')file_msg = MIMEBase(maintype, subtype)file_msg.set_payload(data.read())data.close()email.encoders.encode_base64(file_msg)basename = os.path.basename(self.file_path.split('/')[-1])file_msg.add_header('Content-Disposition', 'attachment', filename=basename)main_msg.attach(file_msg)except Exception as ret:print(ret)main_msg['From'] = self.Frommain_msg['To'] = ";".join(self.To)# main_msg['Cc'] = ";".join(self.Cc)# 标题头main_msg['Subject'] = self.file_headermain_msg['Date'] = email.utils.formatdate()fullText = main_msg.as_string()return fullTextif __name__ == '__main__':fileTime = time.strftime("%Y-%m-%d", time.localtime())s = send_mail('9426096@qq.com', ['1224877@qq.com','xiang.yi@ai.com'],'jshntbmbejj', "/home/app-alive/"+fileTime+"-output.csv", '应用存活记录', '')s.login() print('发送成功!')
好了,就完成了。。。。虽然实现了,但是感觉好傻的样子,open-falcon不好用啊,公司赶紧招个运维开发吧,我好难~~