一个监控脚本带来的Python实践和学习

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 工作中经常要和服务器、数据库这些打交道,有些小功能例如:服务监控、数据监控等用java往往无处下手,即使能做也要花费很长的时间,身边好几个同事都会Python,面对这些需求他们往往优先选择Python来实现,又快又省事。

工作中经常要和服务器、数据库这些打交道,有些小功能例如:服务监控、数据监控等用java往往无处下手,即使能做也要花费很长的时间,身边好几个同事都会Python,面对这些需求他们往往优先选择Python来实现,又快又省事。所以我也计划着自学一下Python,寻思着买一本入门的书来参考,在豆瓣上挑来挑去最后挑了《Head first Python》这本。买来后断断续续看了好几章了,对Python也有了一些基本的了解,不过一直没真正上手。

废话太多,直接步入正题,昨天领导让我写个脚本来实时监控某个服务的日志,监控日志中报出的用户购买超时的现象,如果某个node累计超时次数达到10次则通过邮件和短信告警。

 

需求就是上面说的这样,虽然Python用的还不熟练,不过当下也没其它好的方式来实现,没办法,赶鸭子上架,现学现用,如果碰到不会的就借助于万能的互联网吧

 

一、Python调用shell

首先考虑实现的方式,由于领导要求实时监控,所以当前想到的方式就是使用linux shell的tail命令扫描服务日志,然后再使用关键字来grep,根据grep出来的日志内容进行分析。这时候碰到了第一个问题,如何在Python中执行linux shell命令呢?

 

没办法,上网求助,网上有人推荐使用os.system,不过大部分都推荐使用subprocess模块来实现,通过官方文档说明,我决定使用subprocess

官方给出的文档里有这么一段话:

写道
The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several other, older modules and functions, such as:
os.system
os.spawn*
os.popen*
popen2.*
commands.*

翻译过来的意思大致就是:subprocess模块允许你新建子进程,可以连接到进程的输入、输出、异常通道,并且可以获取到子进程的返回值,这个模块是Python用来替代一些其它过时的模块和功能的。

所以说,官方推荐使用subprocess来实现类似的功能。

 

要使用subprocess,首先必须import该模块

Python代码   收藏代码
  1. import subprocess  

要调用shell命令,subprocess有很多方式,比如call、Popen等,这里我们使用Popen

首先看一个最简单的实例:

Python代码   收藏代码
  1. subprocess.Popen('ls -l',stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)  

上面的代码构建了一个Popen对象,Popen的构造函数格式如下:

Python代码   收藏代码
  1. subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)  

参数args可以是字符串或者序列类型(如:list,元组),用于指定进程的可执行文件及其参数。如果是序列类型,第一个元素通常是可执行文件的路径。

参数stdin, stdout, stderr分别表示程序的标准输入、输出、错误句柄。他们可以是PIPE,文件描述符或文件对象,也可以设置为None,表示从父进程继承。

如果参数shell设为true,程序将通过shell来执行。

关于其它具体的参数的说明,参见官方文档:http://docs.python.org/2/library/subprocess.html#popen-constructor

不想看英文的可以看网上的另一篇博客:http://blog.csdn.net/wuwangyingzhong/article/details/6002055

 

我的代码逻辑如下:

Python代码   收藏代码
  1. #日志文件目录和名称  
  2. filename = '/home/project/logs/xxx.log'  
  3. #要执行的shell命令  
  4. command='tail -f '+filename+'|grep "timeout"'  
  5. popen=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)  
  6. while True:  
  7.     #获取当前grep出来的日志文本行  
  8.     line=popen.stdout.readline().strip()  
  9.     #对日志文本进行分析(这里省略)  

 

二、Python发送http请求

上面已经提到,告警的方式为邮件和短信,我们的短信推送接口是一个http接口,所以如果需要短信告警,则需要通过python来请求该http接口。python中一共有urllib、urllib2、httplib、httplib2支持发送http请求,由于服务器上没有安装python的httplib和httplib2模块,所以只能使用urllib,urllib2

使用GET请求来请求短信推送接口,可以把参数写在url中,如果使用POST方式来请求接口,则数据必须放在data或者body中,不能放在url中,放在url中将被忽略。

附上一个通过urllib,urllib2发送GET请求的示例:

Python代码   收藏代码
  1. import urllib,urllib2  
  2.   
  3.   
  4. def main():  
  5.     url="http://www.baidu.com/s?wd=douban"  
  6.     req = urllib2.Request(url)  
  7.     print req  
  8.   
  9.     res_data = urllib2.urlopen(req)  
  10.     res = res_data.read()  
  11.     print res  
  12.   
  13. if __name__ == '__main__':  
  14.     main()  

关于python对http请求的操作,可以参见博客:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201231085444250/

 

三、脚本进程和子进程的退出

发现了2个问题:

问题1:在上面的代码中,python调用的shell tail命令作用是实时监控当前的日志,而服务是24小时不间断的,该python脚本也一直同步执行,所以只能使用nohup方式后台启动。每次要关闭该脚本,手动通过进程pid来kill。带来了一个新的问题,每次kill掉python主进程时,主进程执行时启动的Popen子进程未关闭,由于调试时曾经连续启动->kill->启动->kill多次,导致系统中出现了一大堆tail日志的进程,这是我原来没有预料到的。

问题2:我们的日志是生成的dailyRolling日志,文件名称为:xxx_dailyRolling.log,每天的0点会自动重命名为xxx_dailyRolling.logyyyyMMdd,yyyyMMdd代表前一天的日期,例如xxx_dailyRolling.log20131023,如果tail -f xxx_dailyRolling.log命令一直执行,到0点时会中断,所以我还需要在每天0点前停止当前的python脚本,然后在第二天0点后定时启动此python脚本

 

综上,2个问题一起解决,在0点前停止python脚本前先kill掉Popen子进程,然后再停止就OK了。

我的思路时每天设置一个固定的时间点,例如就定为每天的23:30:00(因为我们的服务在凌晨时基本上没人使用,监控的目的主要是为了监控白天高峰期时的服务情况,所以23:30到0点这段时间即使没监控也不影响),然后在Popen子进程执行时判断当前时刻是否到了23:30:00,如果已经到了,则终止子进程。通过实践证明,如果Popen子进程终止了,如果python主进程里没有挂起的其余子进程在执行,则主进程也会终止。

 

Popen可以通过terminate()或者kill()函数来终止当前的子进程。在执行了terminate()后,如果不想立即终止,可以通过wait()或poll()函数来等待子进程执行结束,关于各函数的使用,具体参考官方文档。

各函数说明如下:

写道
Popen.poll()
Check if child process has terminated. Set and return returncode attribute.

Popen.wait()
Wait for child process to terminate. Set and return returncode attribute.

Popen.terminate()
Stop the child. On Posix OSs the method sends SIGTERM to the child. On Windows the Win32 API function TerminateProcess() is called to stop the child.

Popen.kill()
Kills the child. On Posix OSs the function sends SIGKILL to the child. On Windows kill() is an alias for terminate().

附上一个示例:

Python代码   收藏代码
  1. #程序执行终止时间为当前时刻延迟15秒  
  2. stoptime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()+15))  
  3.   
  4. def main():  
  5.     popen=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)  
  6.     pid=popen.pid  
  7.     print('Popen.pid:'+str(pid))  
  8.     while True:  
  9.         line=popen.stdout.readline().strip()  
  10.         print(line)  
  11.         #当前时间  
  12.         thistime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))  
  13.         if thistime>=stoptime:  
  14.             #终止子进程  
  15.             popen.terminate()  
  16.             #等待子进程终止后跳出while循环  
  17.             if subprocess.Popen.poll(popen) is not None:  
  18.                 break  
  19.             else:  
  20.                 print('waiting for subprocess.Popen terminate()')  
  21.     print('DONE')  
  22.   
  23. if __name__ == '__main__':  
  24.     main()  

 

四、Python2.x和3.x版本的区别(部分)

Python在2.x和3.x之间有一些特性区别比较大,由于我本地是安装的最新的3.2.2版本,而服务器上还是2.6.x,所以在编写调试时遇到了一些,也拿出来说说说:

区别1.print函数

在python 2.x版本中,同时支持print(xxx)和print xxx,示例:

Python代码   收藏代码
  1. >>> name='chenzhou'  
  2. >>> print name  
  3. chenzhou  
  4. >>> print(name)          
  5. chenzhou  
  6. >>>   

在python 3.x版本中,只支持print(xxx)的方式,示例:

Python代码   收藏代码
  1. >>> name='chenzhou'  
  2. >>> print(name)  
  3. chenzhou  
  4. >>> print name  
  5. SyntaxError: invalid syntax  
  6. >>>   

区别2.判断字典中的key是否存在

在python 2.x中,可以使用has_key(key)函数,也可以判断 key in xxxMap.keys(),示例:

Python代码   收藏代码
  1. >>> users={'name':'chenzhou','age':'24','address':'Beijing'}  
  2. >>> print users.has_key('name')  
  3. True  
  4. >>> print 'name' in users.keys()  
  5. True  
  6. >>> print users.has_key('score')  
  7. False  
  8. >>> print 'score' not in users.keys()  
  9. True  
  10. >>>   

在python 3.x中,只支持key in xxxMap.keys() 示例:

Python代码   收藏代码
  1. >>> users={'name':'chenzhou','age':'24','address':'Beijing'}  
  2. >>> print('name' in users.keys())  
  3. True  
  4. >>> print('score' in users.keys())  
  5. False  
  6. >>> print(users.has_key('name'))  
  7. Traceback (most recent call last):  
  8.   File "<pyshell#20>", line 1in <module>  
  9.     print(users.has_key('name'))  
  10. AttributeError: 'dict' object has no attribute 'has_key'  
  11. >>>   

 

五、Python UnicodeDecodeError

脚本写完后在linux下执行时报错:

Shell代码   收藏代码
  1. UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 0: ordinal not in range(128)  

网友给出的原因是windows系统下编辑的文件在linux下编码转换出现的问题,具体解决方法如下:

Python代码   收藏代码
  1. #引入sys模块  
  2. import sys  
  3. #加入下面两行代码  
  4. reload(sys)  
  5. sys.setdefaultencoding('utf-8')  

其它:

在grep关键字时用到了正则表达式,推荐一篇关于Python正则表达式的好博

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
1天前
|
Python
python pandas学习(一)
该代码段展示了四个主要操作:1) 删除指定列名,如商品id;2) 使用正则表达式模糊匹配并删除列,例如匹配订单商品名称1的列;3) 将毫秒级时间戳转换为带有时区调整的日期时间格式,并增加8小时以适应本地时区;4) 将列表转换为DataFrame后保存为Excel文件,文件路径和名称根据变量拼接而成。
12 3
|
25天前
|
安全 Linux 网络安全
利用Python脚本自动备份网络设备配置
通过本文的介绍,我们了解了如何利用Python脚本自动备份网络设备配置。该脚本使用 `paramiko`库通过SSH连接到设备,获取并保存配置文件。通过定时任务调度,可以实现定期自动备份,确保网络设备配置的安全和可用。希望这些内容能够帮助你在实际工作中实现网络设备的自动化备份。
51 14
|
27天前
|
监控 算法 安全
深度洞察内网监控电脑:基于Python的流量分析算法
在当今数字化环境中,内网监控电脑作为“守城卫士”,通过流量分析算法确保内网安全、稳定运行。基于Python的流量分析算法,利用`scapy`等工具捕获和解析数据包,提取关键信息,区分正常与异常流量。结合机器学习和可视化技术,进一步提升内网监控的精准性和效率,助力企业防范潜在威胁,保障业务顺畅。本文深入探讨了Python在内网监控中的应用,展示了其实战代码及未来发展方向。
|
1月前
|
存储 人工智能 运维
【01】做一个精美的打飞机小游戏,浅尝阿里云通义灵码python小游戏开发AI编程-之飞机大战小游戏上手实践-优雅草央千澈-用ai开发小游戏尝试-分享源代码和游戏包
【01】做一个精美的打飞机小游戏,浅尝阿里云通义灵码python小游戏开发AI编程-之飞机大战小游戏上手实践-优雅草央千澈-用ai开发小游戏尝试-分享源代码和游戏包
199 48
【01】做一个精美的打飞机小游戏,浅尝阿里云通义灵码python小游戏开发AI编程-之飞机大战小游戏上手实践-优雅草央千澈-用ai开发小游戏尝试-分享源代码和游戏包
|
1月前
|
数据可视化 数据挖掘 大数据
1.1 学习Python操作Excel的必要性
学习Python操作Excel在当今数据驱动的商业环境中至关重要。Python能处理大规模数据集,突破Excel行数限制;提供丰富的库实现复杂数据分析和自动化任务,显著提高效率。掌握这项技能不仅能提升个人能力,还能为企业带来价值,减少人为错误,提高决策效率。推荐从基础语法、Excel操作库开始学习,逐步进阶到数据可视化和自动化报表系统。通过实际项目巩固知识,关注新技术,为职业发展奠定坚实基础。
|
2月前
|
Python
自动化微信朋友圈:Python脚本实现自动发布动态
本文介绍如何使用Python脚本自动化发布微信朋友圈动态,节省手动输入的时间。主要依赖`pyautogui`、`time`、`pyperclip`等库,通过模拟鼠标和键盘操作实现自动发布。代码涵盖打开微信、定位朋友圈、准备输入框、模拟打字等功能。虽然该方法能提高效率,但需注意可能违反微信使用条款,存在风险。定期更新脚本以适应微信界面变化也很重要。
212 61
|
2月前
|
Python
Python学习的自我理解和想法(10)
这是我在千锋教育B站课程学习Python的第10天笔记,主要学习了函数的相关知识。内容包括函数的定义、组成、命名、参数分类(必须参数、关键字参数、默认参数、不定长参数)及调用注意事项。由于开学时间有限,记录较为简略,望谅解。通过学习,我理解了函数可以封装常用功能,简化代码并便于维护。若有不当之处,欢迎指正。
|
2月前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
70 20
|
2月前
|
数据挖掘 vr&ar C++
让UE自动运行Python脚本:实现与实例解析
本文介绍如何配置Unreal Engine(UE)以自动运行Python脚本,提高开发效率。通过安装Python、配置UE环境及使用第三方插件,实现Python与UE的集成。结合蓝图和C++示例,展示自动化任务处理、关卡生成及数据分析等应用场景。
178 5
|
2月前
|
Python 容器
Python学习的自我理解和想法(9)
这是我在B站跟随千锋教育学习Python的第9天,主要学习了赋值、浅拷贝和深拷贝的概念及其底层逻辑。由于开学时间紧张,内容较为简略,但希望能帮助理解这些重要概念。赋值是创建引用,浅拷贝创建新容器但元素仍引用原对象,深拷贝则创建完全独立的新对象。希望对大家有所帮助,欢迎讨论。

热门文章

最新文章

推荐镜像

更多