您的位置:首页 > 运维架构 > Linux

Python2.7实现监控Linux内存、CPU并发送预警邮件

2017-11-22 10:27 1091 查看
#!/usr/bin/env python
# coding=utf-8
import os
import sched
import smtplib
import sys
import time
from email.header import Header
from email.mime.text import MIMEText

import psutil

from Daemon import Daemon

MEM_WARN_LINE = 85
CPU_WARN_LINE = 90
SCHED_TIME = 60*60*6  # 单位,秒
def sendmail(content):
subject = '[Python服务器监控]%s服务器监控预警' % '192.168.8.122'
username = 'username'
password = 'password'
smtp_server = 'smtp.126.com'
header = '您好!<br/> %s服务器性能预警<br/>' % '192.168.8.122'
footer = '--------------------------------------------------------<br/>此为系统邮件请勿回复'
content = '%s<br/>%s<br/>%s' % (header, content, footer)

msg = MIMEText(content, 'html', 'utf-8')  # 中文需参数‘utf-8',单字节字符不需要
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = "%s<username@126.com>" % Header('Python监控预警','utf-8')

msg['to'] = 'username@163.com'  # 单独收信人
msg_to_list = ["user1@qq.com", "user2@qq.com"]  # 多个收信人

smtp = smtplib.SMTP()
smtp.connect(smtp_server)
smtp.login(username, password)
smtp.sendmail(msg['From'], msg_to_list, msg.as_string())
smtp.quit()

def is_mem_warning():
mem = psutil.virtual_memory()
if mem.percent > MEM_WARN_LINE:
return [True, mem]
else:
return [False]

def is_cpu_warning():
cpupercent = psutil.cpu_percent()
if cpupercent > CPU_WARN_LINE:
return [True, cpupercent]
else:
return [False]

def check_status():
memwarn = is_mem_warning()
is_send_mail = False

if memwarn[0]:
mem = memwarn[1]
title = "内存预警[时间:%s]" % time.ctime()
memmsg = str("%s\n 占用率:%s%%\n 总数:%s\n 已使用:%s\n 空闲:%s\n" % (title, mem.percent, mem.total, mem.used, mem.free))
is_send_mail = True
else:
memmsg = ''

cpuwarn = is_cpu_warning()

if cpuwarn[0]:
title = "CPU预警[时间:%s]" % time.ctime()
cpumsg = str("%s\n 使用率 %s%%\n" % (title, cpuwarn[1]))
is_send_mail = True
else:
cpumsg = ''

if is_send_mail:
sendmail("%s\n%s" % (memmsg, cpumsg))
sys.stderr.write("[error]{%s} 监测异常\n %s\n%s" % (time.ctime(), memmsg, cpumsg))
sys.stderr.flush()
else:
sys.stderr.write("[info]{%s} 监测无异常\n" % time.ctime())
sys.stderr.flush()

schedule.enter(SCHED_TIME, 0, check_status, ())

class MyTestDaemon(Daemon):
def run(self):
sys.stdout.write('[info]{%s} Daemon started with pid {%s}\n' % (time.ctime(), os.getpid()))
sys.stdout.flush()
# while True:
schedule.enter(SCHED_TIME, 0, check_status, ())
schedule.run()

if __name__ == '__main__':
schedule = sched.scheduler(time.time, time.sleep)
PIDFILE = '/tmp/daemon-sysinfo.pid'
LOG = '/tmp/daemon-sysinfo.log'
daemon = MyTestDaemon(pidfile=PIDFILE, stdout=LOG, stderr=LOG)

if len(sys.argv) != 2:
print('Usage: {} [start|stop]'.format(sys.argv[0]))
raise SystemExit(1)

if 'start' == sys.argv[1]:
daemon.start()
elif 'stop' == sys.argv[1]:
daemon.stop()
elif 'restart' == sys.argv[1]:
daemon.restart()
else:
print('Unknown command {!r}'.format(sys.argv[1]))
raise SystemExit(1)
#!/usr/bin/env python

import atexit
import os
import sys
import time
from signal import SIGTERM

class Daemon:
"""
A generic daemon class.

Usage: subclass the Daemon class and override the run() method
"""

def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
self.pidfile = pidfile

def daemonize(self):
"""
do the UNIX double-fork magic, see Stevens' "Advanced
Programming in the UNIX Environment" for details (ISBN 0201563177) http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 """
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)

# decouple from parent environment
os.chdir("/")
os.setsid()
os.umask(0)

# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)

# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = file(self.stdin, 'r')
so = file(self.stdout, 'a+')
se = file(self.stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())

# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
file(self.pidfile, 'w+').write("%s\n" % pid)

def delpid(self):
os.remove(self.pidfile)

def start(self):
"""
Start the daemon
"""
# Check for a pidfile to see if the daemon already runs
try:
pf = file(self.pidfile, 'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None

if pid:
message = "pidfile %s already exist. Daemon already running?\n"
sys.stderr.write(message % self.pidfile)
sys.exit(1)

# Start the daemon
self.daemonize()
self.run()

def stop(self):
"""
Stop the daemon
"""
# Get the pid from the pidfile
try:
pf = file(self.pidfile, 'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None

if not pid:
message = "pidfile %s does not exist. Daemon not running?\n"
sys.stderr.write(message % self.pidfile)
return  # not an error in a restart

# Try killing the daemon process
try:
while 1:
os.kill(pid, SIGTERM)
time.sleep(0.1)
except OSError, err:
err = str(err)
if err.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print str(err)
sys.exit(1)

def restart(self):
"""
Restart the daemon
"""
self.stop()
self.start()

def run(self):
"""
You should override this method when you subclass Daemon. It will be called after the process has been
daemonized by start() or restart().
"""


参考资料:
http://www.jianshu.com/p/e3f3d49093ca http://blog.csdn.net/zm2714/article/details/8134118
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python 邮件 运维