从零开始应用Python开发进程监控程序

Python语言已经成为现在最受欢迎的程序设计语言之一。由于其简洁性、易读性以及可扩展性,Python 语言在系统运维工作中得到了广泛的应用。这里结合一个小程序,介绍一下在日常工作中是如何应用Python快速解决进程监控问题。

一、问题源起

前几天学习编写了一个微信机器人,但发现一个问题,是经常会死掉。该系统运行在一台树莓派上,本来应该是一个后台运行的进程,不过时常会出现进程自动退出的情况。
因为是使用现成的模块库,退出原因一时很难找到,好在只要重启就可以了。那我们就开发一个小的监控程序临时解决这个问题,以后再仔细研究机器人代码吧。
说明一下:树莓派的系统是基于Ubuntu,因此,本文也适用于其他Linux系统。

二、解决思路

  1. 编写一个进程监控程序,监控这个机器人进程是否存在。
  2. 进程不存在的话,就自动重启机器人进程。
  3. 在Linux下监控进程,可以使用ps -ef命令。
    机器人启动命令是:
nohup wx.py &

我们只要监控 wx.py在不在就可以了,使用如下命令:

ps -ef|grep wx.py|grep -v grep > wx.lock

说明:
第一个grep把包括wx.py的都列出来(包括机器人进程和grep进程自身),第二个grep把grep命令排除在外,把结果写到wx.lock文件中。
我们只要检查wx.lock文件有内容,就说明机器人进程还在。
如果长度为0,则机器人进程已经消失,重启就可以了。

  1. 好,我们可以利用 python的 os库完成此项操作:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
check_weixin.py
@author: 徒步学天下( [email protected])
用于监控 wx.py 进程是否存在,如果不存在,则重启 wx.py。
"""

import os
import smail
import time


process="/home/pi/wx.lock"
os.system("ps -ef|grep wx.py|grep -v grep >%s" % process)
if not(os.path.getsize(process)):
    os.system("nohup /home/pi/wx.py &")

总共8句,就可以完成了。

三、自动运行监控

问题来了:不过每次运行此程序才能检查,如何实现自动监控呢?

解决思路:这时候我们要用到linux的调度命令:

crontab -e
追加以下一行:

*/5 * * * * /home/pi/check_weixin.py

退出保存,之后系统会每5分钟运行一次检查程序,自动完成机器人系统的监控。

如何?应用Python实现进程监控还是很容易的吧。

四、迭代改进

问题又来了:机器人进程启动的时候要求登录,这个需要通过手机扫码解决。机器人使用的库,登录时有个设置,可以利用缓存自动登录。不过问题是,过一段时间之后,缓存会失效,这样,下次登录的时候,就连接不上微信了。这就是前一段时间机器人经常不好用的原因(自动登录不上)。

改进思路:机器人进程启动的时候,如果需要扫码登录,会在当前目录下生成一个wx.png二维码文件。扫码成功,或自动登录成功,则没有这个文件。
好了,我们对这个文件进行监控,发现需要扫描,就邮件通知我一下。

Python有邮件模块,可以收发邮件,我们继续做起来。

邮件解决

  1. 取得当前时间:
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
  1. 发送邮件,要就用smptlib和email模块。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
smail.py
@author: 徒步学天下( [email protected])
自动向指定邮箱发送邮件,标题为故障时间
"""

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import time

"""
发送邮件函数
已经指定发送邮箱和接收邮箱
标题为故障时间
"""
def callmail():
    msg = MIMEMultipart('related')
    msg['from'] = '[email protected]'
    msg['to'] = '[email protected]'
    msg['subject'] = 'Robot Dead**'+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
    content = "Your Robot Dead"
    txt=MIMEText(content)
    msg.attach(txt)

    smtp=smtplib
    smtp=smtplib.SMTP()
    smtp.connect('smtp.163.com','25')
    smtp.login('[email protected]','xxxxxxx')
    smtp.sendmail('[email protected]','[email protected]',msg.as_string())
    smtp.quit()

if __name__ == '__main__':
    callmail()

只要你有邮件账号,这里以[email protected]为例,邮件服务器支持smtp服务,这里是smtp.163.com。运行这个程序,就可以给你的邮箱发送一封邮件,标题就是故障时间(其实是发邮件时间,不过我们现在不管这个差别了,因为这只是个邮件提醒功能)
记得还得修改一下监控程序,检查是否有 wx.png 文件,如果有就调用发送报警邮件程序 smail.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
check_weixin.py
@author: 徒步学天下( [email protected])
用于监控 wx.py 进程是否存在,如果不存在,则重启 wx.py。
改进1:增加登录文件wx.png判断
"""

import os
import smail
import time


process="/home/pi/wx.lock"
os.system("ps -ef|grep wx.py|grep -v grep >%s" % process)
if not(os.path.getsize(process)):
    os.system("nohup /home/pi/wx.py &")

wxpng="/home/pi/wx.png"
if os.path.exists(wxpng):
    smail.callmail()

五、迭代改进2

问题又来了:有时候我在外面,一时半会儿无法把二维码传到本地来手机扫码,结果报警邮件5分钟一个,开会的功夫就二三十封邮件,很是烦人。
最好是告诉我一声之后就别再发这烦人的邮件了。

改进思路:判断一下wx.png文件的时间,与当前时间对比,超过6分钟了就别发邮件了(记得前面咱们是每5分钟检查一次进程吧)。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
check_weixin.py
@author: 徒步学天下( [email protected])
用于监控 wx.py 进程是否存在,如果不存在,则重启 wx.py。
改进1:增加登录文件wx.png判断
改进2:增加文件时间判断
"""

import os
import smail
import time


process="/home/pi/wx.lock"
os.system("ps -ef|grep wx.py|grep -v grep >%s" % process)
if not(os.path.getsize(process)):
   os.system("nohup /home/pi/wx.py &")

wxpng="/home/pi/wx.png"
if os.path.exists(wxpng):
   mtime = os.path.getmtime(wxpng)
   # 对六分钟(360秒)以内的错误报警
   if time.time()-mtime<360:
       smail.callmail()

这下清静了。

六、迭代改进3

问题又来了:为啥还是手动去取二维码文件呢,直接通过邮件发过来,不就可以直接扫吗?

改进思路:改进发邮件程序,直接用附件把二维码发过来。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
smail.py
@author: 徒步学天下( [email protected])
自动向指定邮箱发送邮件,标题为故障时间
改进3:附件为二维码文件wx.png
"""

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import time

"""
发送邮件函数
已经指定发送邮箱和接收邮箱
标题为故障时间
附件为二维码文件
"""
def callmail():
    msg=MIMEMultipart('related')
    msg['from']='[email protected]'
    msg['to']='[email protected]'
    msg['subject']='Robot Dead**'+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
    att = MIMEText(open('./wx.png','rb').read(), 'base64', 'utf-8')
    att['Content-Type']='application/octet-stream'
    att['Content-Disposition'] = 'attachment; filename="wx.png"'
    msg.attach(att)

    smtp=smtplib
    smtp=smtplib.SMTP()
    smtp.connect('smtp.163.com','25')
    smtp.login('[email protected]','xxxxxxx')
    smtp.sendmail('[email protected]','[email protected]',msg.as_string())
    smtp.quit()

if __name__ == '__main__':
    callmail()

也就是喝一顿咖啡的时间,我们就从无到有完成了一个简单的进程自动监控程序,还包括自动启动进程和聪明的邮件报警功能,是不是很有成就感呢。

人生苦短,我用Python。让我们自己动手创造美好生活吧。

徒步学天下( [email protected])
2017年6月25日于中国林都

你可能感兴趣的:(从零开始应用Python开发进程监控程序)