转自http://blog.youkuaiyun.com/lovomap151/article/details/53141174。
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import re
import datetime
import urllib2
import traceback
from bs4 import BeautifulSoup
from email.mime.text import MIMEText
import smtplib
from email.header import Header
mail_to_list=["xx@xx.com"] #邮件收件人,多个用逗号隔开
mail_host="192.31.15.117" #邮件服务器
mail_user="xx@xx.com" #邮箱账户名(建议用公司内部邮箱,以免其他邮箱泄露服务器机器信息)
#线上环境spark页面
spark_url_master_1 = "http://192.168.141.145:8090/" #spark集群主服务地址
spark_url_master_2 = "http://192.168.141.144:8090/" #spark集群备服务地址
task_names = ["AD_SSP_STAT_OLAP","AD_SDK_DISTRIBUTE_STAT_OLAP"] # 任务名称,多个任务用逗号分隔
time_delayed = 60*30
#发送邮件
def send_mail(content):
text = ''+content
message = MIMEText(text,'html','utf-8')
message['From'] = Header(mail_user,'utf-8')
message['To'] = Header(";".join(mail_to_list),'utf-8')
message['Subject'] = Header("Spark Streaming 统计监控",'utf-8')
try:
server = smtplib.SMTP()
server.connect(mail_host)
server.sendmail(mail_user,mail_to_list,message.as_string())
server.quit()
print '发送成功'
except Exception,e:
print "Error:无法发送邮件",str(e)
#根据任务名称获取任务跳转地址href
def getHref(url,task_name):
html = ''
href = ''
try:
html = urllib2.urlopen(url)
except Exception , e:
print "打开url出错",str(e),str(url)
try:
bsObj = BeautifulSoup(html.read())
href = bsObj.findAll("a",{"href":re.compile("^http:.*")},text=task_name)[0].attrs["href"]
except Exception ,e :
print "解析标签出错",str(e)
return href
#获取任务运行地址任务运行时间状态
def getTaskStatus(url):
url = url +"/streaming/"
html = ''
time = ''
try:
html = urllib2.urlopen(url)
except Exception , e:
print "打开url出错",str(e),str(url)
try:
bsObj = BeautifulSoup(html.read())
time = bsObj.findAll("table",{"id":"completed-batches-table"})[0].find("tbody").findAll("tr")[0].findAll("td")[0].findAll("a")[0].get_text()
except Exception ,e :
print "解析标签出错",str(e)
return time
#指定的时间与当前时间差
def get_time_diff(t_str):
starttime = datetime.datetime.now()
endtime = datetime.datetime.strptime(t_str, '%Y/%m/%d %H:%M:%S')
return dateDiffInSeconds(starttime,endtime)时间相差的秒数
def dateDiffInSeconds(date1, date2):
timedelta = abs(date2 - date1)
return timedelta.days*24*3600 + timedelta.seconds
#检测是否延时过长,超过了指定的阀值
def checkDelayed(time,url,task_name):
#延时一个小时则发送报警邮件
if time != '':
delayed = get_time_diff(time.strip())
if(delayed>time_delayed ):
url = url+"/streaming/"
content = "任务延时:"+str(delayed)+str("秒,任务url:")+str(url)
send_mail(content)
else:
print "任务:"+str(task_name)+"检测正常"
else:
passtaks url
#根据任务名称获取任务地址
def getTaskUrl(task_name):
url = ''
if getHref(spark_url_master_1,task_name) != '':
url = getHref(spark_url_master_1,task_name)
else:
url = getHref(spark_url_master_2,task_name)
return url
#执行主方法
if __name__ == '__main__':
for task_name in task_names:
taskUrl = getTaskUrl(task_name)
if taskUrl == '':
content = "spark master任务中没有找到运行的任务:"+str("master 地址1:")+spark_url_master_1+str(" , master 地址2:")+spark_url_master_2
send_mail(content)
else:
runTime = getTaskStatus(taskUrl)
checkDelayed(runTime,taskUrl,task_name)
上面是完整的脚本,只要在Linux中加个定时任务就可以进行监控了,这里面用了python提供的爬虫库BeautifulSoup,BeautifulSoup提供了find、 findAll等方法可以和正则表达式进行结合使用,让我们方便的对html文档中的标签进行查找定位获取。
之所以用任务名称进行查找任务运行地址,是因为,spark 集群会进行主备切换,如果写hard code,当主备切换的时候,地址发生了变化,脚本会找不到任务,或者任务重新启动的时候,任务运行的节点地址也会随机变化的,这样我们就不得不每次启动一次就修改一次监控脚本很繁琐,所以使用任务名称进行查找任务运行地址,我们只要通过配置spark 集群的访问地址,然后通过爬虫自动查找任务运行的节点地址,找到任务地址进行后做相应的延时等监控处理就可以了,这大大增加了脚本的灵活性,当然脚本也有很多的不足之处,例如:我们把spark 集群主备地址、任务名称、收件人都hard code代码里,这些度可以进行相应的改进,如通过web页面进行配置上面的hard code,并通过任务名称进行分组,不同的任务名称发送给不同的收件人,这样就能各负其职呢。