一、要求
最近公司大佬要求将应用每天的存活状态,输出成报表的形式,每天以邮件的方式发送给他们。报表里面要输出:应用名、应用所在服务器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/bash DataInputPath=/home/app-alive/source.txt DataOutputPath=/home/app-alive/$(date +%F)-output.csv #data mysql -uops_ro -pxxxx -e "source /home/app-alive/select.sql" > $DataInputPath 2>/dev/null app_id=$(awk '{ print $2}' $DataInputPath |grep -v sid|uniq) if [ ! -f "$DataOutputPath" ]; then echo "应用名,服务器IP,应用停止时间,停止持续时间" > $DataOutputPath fi for id in $app_id do 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 fi done
这个脚本处理完后,输出的结果为:
# 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 smtplib import email.mime.multipart import email.mime.text from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase import email import base64 import time import os class send_mail: def __init__(self, From, To, pw, file_path, file_header, file_body): # 发送人 self.From = From # 收件人['[email protected]','[email protected]'] 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_body def 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.From main_msg['To'] = ";".join(self.To) # main_msg['Cc'] = ";".join(self.Cc) # 标题头 main_msg['Subject'] = self.file_header main_msg['Date'] = email.utils.formatdate() fullText = main_msg.as_string() return fullText if __name__ == '__main__': fileTime = time.strftime("%Y-%m-%d", time.localtime()) s = send_mail('[email protected]', ['[email protected]','[email protected]'],'jshntbmbejj', "/home/app-alive/"+fileTime+"-output.csv", '应用存活记录', '') s.login() print('发送成功!')
好了,就完成了。。。。虽然实现了,但是感觉好傻的样子,open-falcon不好用啊,公司赶紧招个运维开发吧,我好难~~