一. Python 监控脚本说明
DB 服务器是Redhat 5.5. 系统上的Python 是2.4. 所以这套监控脚本也是基于Python 2.* 版本。 Python 3.0 版本的语法上有一定的出入。
1. 1 几点说明:
(1)Python 严格的区分格式的,所以,格式要对其。
(2)脚本里用到了dns.resolver包,脚本里有下载地址。 安装方法参考dns.resolver包的readme文档。
(3)脚本分成2部分,所有的配置信息,放到了healthcheck_config.py里面。 监控部分代码放在了healthcheck.py里了。 配置文件里设定了警告值,超过这个值就会发送报警信息。
(4)本打算把RMAN 的监控也放到里面的。 但是RMAN 每天只需要运行一次。 而这个监控脚本是10分钟执行一次。 所以RMAN 备份的log 会在单独弄个脚本来处理。
(5)脚本里面调用了一些系统命令。 如ifconfig,这个命令只有root用户能执行,所以这个监控脚本也必须使用root用户来部署。 在调试这个脚本的时候,浪费了很多的时间。
(6)脚本里使用了2种方式来发送警告信息,一个是使用smtp发送到邮箱,另一个是通过短信接口发送到手机。 现在一般公司都有自己的邮件服务器。 所以这些在内网就能直接搞定了。 如果说没有短信接口的话,可以发送到移动的139邮箱,或者qq 邮箱, 这2个邮箱都可以设置短信通知邮件。
(7) 这里把所有要监控的服务器,全部添加到脚本配置文件里。 这样在移植的时候,直接部署过去就可以了。 不需要进行其他的修改。
1.2 Python 的基础知识参考一下链接:
Python 基础语法知识一
http://blog.csdn.net/tianlesoftware/archive/2011/02/11/6179869.aspx
Python 基础语法知识二
http://blog.csdn.net/tianlesoftware/archive/2011/02/12/6181166.aspx
Python 执行 系统命令
http://blog.csdn.net/tianlesoftware/archive/2011/02/17/6192202.aspx
二. 监控脚本
2.1 . 参数文件 healthcheck_config.py
#!/usr/bin/python
# coding=gbk
#################################################
# Created by Tianlesoftware
# 2011/2/23
##################################################
# 注意, 如果需要换行时缩进需要跟原有的代码保持统一
##################################################
#CPU 使用率警戒值
#wa: Time spent waiting for IO. Prior to Linux 2.5.41, shown as zero.
MAX_CPU_USED = 70
MAX_WA = 20
FILTERS = ['/boot', '/dev/shm']
MIN_FREE_MB = 200
#磁盘空间使用率
MAX_USED_PCT = 80
#邮件服务器地址及发送邮件账户和密码
MAIL_FROM='[email protected]'
SMTP_SERVER='192.168.1.100'
EMAIL_USER='user'
EMAIL_PASSWD='pwd'
#监控的进程信息,以下进程都将被监控
PROCESS = {
'192.168.1.1': ['LISTENER','ora_pmon_wangou','ora_lgwr_wangou','ora_dbw0_wangou','ora_ckpt_wangou','ora_smon_wangou','ora_arc0_wangou'],
'192.168.1.2': ['LISTENER','ora_pmon_wangou','ora_lgwr_wangou','ora_dbw0_wangou','ora_ckpt_wangou','ora_smon_wangou','ora_arc0_wangou'],
'192.168.1.3': ['LISTENER','ora_pmon_xezf','ora_lgwr_xezf','ora_dbw0_xezf','ora_ckpt_xezf','ora_smon_xezf','ora_arc0_xezf'],
'192.168.1.4': ['LISTENER','ora_pmon_xezf','ora_lgwr_xezf','ora_dbw0_xezf','ora_ckpt_xezf','ora_smon_xezf','ora_arc0_xezf'],
'192.168.1.5': ['LISTENER','ora_pmon_XEZF','ora_lgwr_XEZF','ora_dbw0_XEZF','ora_ckpt_XEZF','ora_smon_XEZF','ora_arc0_XEZF'],
}
#监控的文件信息
FILES = {
'192.168.1.1': [
{'file':'/home/oracle_app/admin/XEZF/bdump/alert_XEZF.log', 'type':'ora-log'},
{'file':'/u01/backup/logs/rman.log', 'type':'rman-log'}],
'192.168.1.2': [
{'file':'/u01/scripts/rman_backup.sh.out','type':'rman-log'},
{'file':'/u01/app/oracle/admin/wangou/bdump/alert_wangou.log', 'type':'ora-log'}],
'192.168.1.3': [{'file':'/u01/app/oracle/admin/wangou/bdump/alert_wangou.log', 'type':'ora-log'}],
'192.168.1.4': [{'file':'/u01/app/oracle/admin/xezf/bdump/alert_xezf.log', 'type':'ora-log'}],
'192.168.1.5': [
{'file':'/u01/backup/logs/rman.log','type':'rman-log'},
{'file':'/u01/app/oracle/admin/xezf/bdump/alert_xezf.log', 'type':'ora-log'}]
}
#默认邮箱和手机是DBA的联系方式
DEFAULT_MAILS = ['[email protected]']
DEFAULT_MOBILES = '13888888888'
#对应服务器的邮件接收人
MAILS = {
'192.168.1.1': ['[email protected]',' [email protected]'],
'192.168.1.2': ['[email protected]'],
'192.168.1.3': ['[email protected]'],
'192.168.1.4': ['[email protected]'],
'192.168.1.5': ['[email protected]']
}
#对应服务器负责人手机号
MOBILES = {
'192.168.1.1': '13688888888,13888888888',
'192.168.1.2': '13688888888,13888888888',
'192.168.1.3': '13688888888,13888888888',
'192.168.1.4': '13688888888,13888888888',
'192.168.1.5': '13688888888,13888888888'
}
2.2. Python 监控脚本: healthcheck.py
#!/usr/bin/python
# coding=gbk
#################################################
# Created by Tianlesoftware
# 2011/2/23
########################################################
# require dns.resolver
# download url: http://www.dnspython.org/kits/1.6.0/
import os
import time
import datetime
import sys
import smtplib
import dns.resolver
import re
import random
import httplib
import urllib2
import urllib
import hc_config
MAX_CPU_USED = hc_config.MAX_CPU_USED
MAX_WA = hc_config.MAX_WA
FILTERS = hc_config.FILTERS
MIN_FREE_MB = hc_config.MIN_FREE_MB
MAX_USED_PCT = hc_config.MAX_USED_PCT
PROCESS = hc_config.PROCESS
MAILS = hc_config.DEFAULT_MAILS
MOBILES = hc_config.DEFAULT_MOBILES
httplib.HTTPConnection.debuglevel = 1
def uniqify(seq, idfun=None):
# order preserving
if idfun is None:
def idfun(x): return x
seen = {}
result = []
for item in seq:
marker = idfun(item)
# in old Python versions:
# if seen.has_key(marker)
# but in new ones:
if marker in seen: continue
seen[marker] = 1
result.append(item)
return result
def get_ip():
pipe = os.popen('/sbin/ifconfig')
data = pipe.read().strip()
p = re.compile(r'inet addr:([\.\d]+)')
r = p.findall(data)
if len(r) > 0:
return r[0]
ip = get_ip()
IP = ip
if hc_config.MAILS.has_key(ip):
MAILS = MAILS + hc_config.MAILS[ip]
MAILS = uniqify(MAILS)
if hc_config.MOBILES.has_key(ip):
MOBILES = MOBILES + ',' + hc_config.MOBILES[ip]
mobiles = MOBILES.split(',')
mobiles = [x.strip() for x in mobiles]
mobiles = uniqify(mobiles)
if len(mobiles) > 0:
MOBILES = mobiles[0]
if len(mobiles) > 1:
for x in mobiles[1:]:
MOBILES = MOBILES + ',' + x
FILES = []
if hc_config.FILES.has_key(ip):
FILES = hc_config.FILES[ip]
########################################################
def load(fname='warn.dat'):
import pickle
fp=open(fname)
d2=fp.read()
fp.close()
o=pickle.loads(d2)
return o
def save(obj,fname='warn.dat'):
# save to file
import pickle
d2 = pickle.dumps(obj)
fp=open(fname, 'w')
fp.write(d2)
fp.close()
########################################################
# for sms
def sendsms(dt,msg):
if len(msg) > 150:
message = msg[0:149]
else:
message = msg
print 'Send to %s %s' % (dt, msg)
f = { 'msg':message }
m = urllib.urlencode(f)
#这里是短信接口的地方,写上自己的短信接口就可以了
url = 'http://.../%s&%s' % (dt,m)
htm = urlget(url)
print htm
def sendsms_s(msg):
sendsms(MOBILES, msg)
def urlget2(url):
request = urllib2.Request(url)
handle = urllib2.urlopen(request)
htm = handle.read()
return htm
def urlget(url):
try:
request = urllib2.Request(url)
handle = urllib2.urlopen(request)
htm = handle.read()
except urllib2.URLError, err:
errno = err[0][0]
errmsg = err[0][1]
print errno, 'AAA', errmsg
if errno == -2:
request = urllib2.Request(url)
handle = urllib2.urlopen(request)
htm = handle.read()
else:
htm = str(err)
except:
htm = str(sys.exc_info())
return htm
########################################################
# Send mail ....
SMTP_SERVER=hc_config.SMTP_SERVER
EMAIL_USER=hc_config.EMAIL_USER
EMAIL_PASSWD=hc_config.EMAIL_PASSWD
def sendmail(fromaddr, toaddr, subject, body):
server=smtplib.SMTP(SMTP_SERVER)
server.login(EMAIL_USER,EMAIL_PASSWD)
#server.set_debuglevel(1)
#server.sendmail(fromaddr, toaddrs, msg)
msg = 'From: %s\nTo: %s\nSubject: %s\n\n%s\n' % (fromaddr, toaddr, subject, body)
server.sendmail(fromaddr, toaddr, msg)
server.quit()
def sendmail_s(fromaddr, toaddrs, subject, body):
for toaddr in toaddrs:
try:
sendmail(fromaddr, toaddr, subject, body)
except:
info = str(sys.exc_info())
print info
######################################
#
# Requirement:
# General:
# FS: free space < 5%,or < 200M
# CPU: Usage > 70%
# Log: dmesg / messages
#文件系统 1K-块 已用 可用 已用% 挂载点
#/dev/mapper/VolGroup00-LogVol00 14855176 3665468 10422940 27% /
#/dev/sda1 101086 10979 84888 12% /boot
#tmpfs 1037848 0 1037848 0% /dev/shm
#/dev/mapper/VolGroup00-Home 51735156 13732272 35374892 28% /home
def get_df_data():
cmd = "df -k | awk '(NF > 1){ printf \"%s\\n\", $0 }(NF==1){ printf \"%s \", $0}'"
pipe = os.popen(cmd)
data = pipe.read().strip()
lines = data.split('\n')
mps = []
for line in lines[1:]:
fields = line.split()
mp = {}
mp['mount_point'] = fields[-1].strip()
mp['used'] = int(fields[-2].strip().replace('%',''))
mp['free'] = int(fields[-3].strip())
mp['freeM'] = int(fields[-3].strip())/1024
mps.append(mp)
return mps
#procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
#r b swpd free buff cache si so bi bo in cs us sy id wa st
#2 0 0 692900 380608 803308 0 0 1 11 20 1 0 0 99 1 0
#0 0 0 692900 380608 803308 0 0 0 0 1012 94 0 0 100 0 0
def get_vmstat_data():
pipe = os.popen('vmstat -n 1 3')
data = pipe.read().strip()
lines = data.split('\n')
wa = 0
idle = 0
for line in lines[3:]:
fields = line.split()
wa = wa + int(fields[-2].strip())
idle = idle + int(fields[-3].strip())
wa = wa / len(lines[3:])
idle = idle / len(lines[3:])
used = 100-wa-idle
ret = {'wa':wa, 'idle':idle, 'used':used }
return ret
#print 'wa=%d idle=%d used=%d' % (wa, idle, used)
def file_data(fname):
cmd = 'cat "%s"' % (fname)
pipe = os.popen(cmd)
data = pipe.read().strip()
return data
def get_ps_data():
pipe = os.popen('ps -ef')
data = pipe.read().strip()
return data
mail_from =hc_config.MAIL_FROM
vmstat = get_vmstat_data()
mps = get_df_data()
#########################################
# FS: free space < 5%,or < 200M
#########################################
body = ''
ip=get_ip()
print ip
for item in mps:
#print item
mp = item['mount_point']
body = body + str(item) + '\n'
if mp not in FILTERS:
alarm = False
msg = '%s (%s) ' % (ip, mp)
if item['freeM'] < MIN_FREE_MB:
msg = msg + 'freeM(%dM)<%dM ' % (item['freeM'],MIN_FREE_MB)
font-size