Python语言已经成为现在最受欢迎的程序设计语言之一。由于其简洁性、易读性以及可扩展性,Python 语言在系统运维工作中得到了广泛的应用。这里结合一个小程序,介绍一下在日常工作中是如何应用Python快速解决进程监控问题。
一、问题源起
前几天学习编写了一个微信机器人,但发现一个问题,是经常会死掉。该系统运行在一台树莓派上,本来应该是一个后台运行的进程,不过时常会出现进程自动退出的情况。
因为是使用现成的模块库,退出原因一时很难找到,好在只要重启就可以了。那我们就开发一个小的监控程序临时解决这个问题,以后再仔细研究机器人代码吧。
说明一下:树莓派的系统是基于Ubuntu,因此,本文也适用于其他Linux系统。
二、解决思路
- 编写一个进程监控程序,监控这个机器人进程是否存在。
- 进程不存在的话,就自动重启机器人进程。
- 在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,则机器人进程已经消失,重启就可以了。
- 好,我们可以利用 python的 os库完成此项操作:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
check_weixin.py
@author: 徒步学天下( hhxx2014@qq.com)
用于监控 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有邮件模块,可以收发邮件,我们继续做起来。
邮件解决:
- 取得当前时间:
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
- 发送邮件,要就用smptlib和email模块。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
smail.py
@author: 徒步学天下( hhxx2014@qq.com)
自动向指定邮箱发送邮件,标题为故障时间
"""
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import time
"""
发送邮件函数
已经指定发送邮箱和接收邮箱
标题为故障时间
"""
def callmail():
msg = MIMEMultipart('related')
msg['from'] = '110@163.com'
msg['to'] = '110@163.com'
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('110@163.com','xxxxxxx')
smtp.sendmail('110@163.com','110@163.com',msg.as_string())
smtp.quit()
if __name__ == '__main__':
callmail()
只要你有邮件账号,这里以110@163.com为例,邮件服务器支持smtp服务,这里是smtp.163.com。运行这个程序,就可以给你的邮箱发送一封邮件,标题就是故障时间(其实是发邮件时间,不过我们现在不管这个差别了,因为这只是个邮件提醒功能)
记得还得修改一下监控程序,检查是否有 wx.png 文件,如果有就调用发送报警邮件程序 smail.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
check_weixin.py
@author: 徒步学天下( hhxx2014@qq.com)
用于监控 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: 徒步学天下( hhxx2014@qq.com)
用于监控 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: 徒步学天下( hhxx2014@qq.com)
自动向指定邮箱发送邮件,标题为故障时间
改进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']='110@163.com'
msg['to']='110@163.com'
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('110@163.com','xxxxxxx')
smtp.sendmail('110@163.com','110@163.com',msg.as_string())
smtp.quit()
if __name__ == '__main__':
callmail()
也就是喝一顿咖啡的时间,我们就从无到有完成了一个简单的进程自动监控程序,还包括自动启动进程和聪明的邮件报警功能,是不是很有成就感呢。
人生苦短,我用Python。让我们自己动手创造美好生活吧。
徒步学天下( hhxx2014@qq.com)
2017年6月25日于中国林都