Python运维三十六式:用Python写一个简单的监控系统


市面上有很多开源的监控系统:Cacti、nagios、zabbix。感觉都不符合我的需求,为什么不自己做一个呢

用Python两个小时徒手撸了一个简易的监控系统,给大家分享一下,希望能对大家有所启发

首先数据库建表

建立一个数据库“falcon”,建表语句如下:

 1 CREATE TABLE `stat` (
 2   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 3   `host` varchar(256) DEFAULT NULL,
 4   `mem_free` int(11) DEFAULT NULL,
 5   `mem_usage` int(11) DEFAULT NULL,
 6   `mem_total` int(11) DEFAULT NULL,
 7   `load_avg` varchar(128) DEFAULT NULL,
 8   `time` bigint(11) DEFAULT NULL,
 9   PRIMARY KEY (`id`),
10   KEY `host` (`host`(255))
11 ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

首先我们设计一个web服务,实现如下功能:

  1. 完成监控页面展示
  2. 接受POST提交上来的数据
  3. 提供json数据GET接口

目录结构如下:

web
├── flask_web.py
└── templates
    └── mon.html

flask_web.py

 1 import MySQLdb as mysql
 2 import json
 3 from flask import Flask, request, render_template
 4 app = Flask(__name__)
 5 db = mysql.connect(user="reboot", passwd="reboot123", \
 6         db="falcon", charset="utf8")
 7 db.autocommit(True)
 8 c = db.cursor()
 9 
10 @app.route("/", methods=["GET", "POST"])
11 def hello():
12     sql = ""
13     if request.method == "POST":
14         data = request.json
15         try:
16             sql = "INSERT INTO `stat` (`host`,`mem_free`,`mem_usage`,`mem_total`,`load_avg`,`time`) VALUES('%s', '%d', '%d', '%d', '%s', '%d')" % (data['Host'], data['MemFree'], data['MemUsage'], data['MemTotal'], data['LoadAvg'], int(data['Time']))
17             ret = c.execute(sql)
18         except mysql.IntegrityError:
19             pass
20         return "OK"
21     else:
22         return render_template("mon.html")
23 
24 @app.route("/data", methods=["GET"])
25 def getdata():
26     c.execute("SELECT `time`,`mem_usage` FROM `stat`")
27     ones = [[i[0]*1000, i[1]] for i in c.fetchall()]
28     return "%s(%s);" % (request.args.get('callback'), json.dumps(ones))
29     
30 
31 if __name__ == "__main__":
32     app.run(host="0.0.0.0", port=8888, debug=True)

这个template页面是我抄的highstock的示例,mon.html

简单起见我们只展示mem_usage信息到页面上

 1 <title>51reboot.com</title>
 2 <!DOCTYPE HTML>
 3 <html>
 4     <head>
 5         <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 6         <title>Highstock Example</title>
 7 
 8         <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
 9         <style type="text/css">
10 ${demo.css}
11         </style>
12         <script type="text/javascript">
13 $(function () {
14     $.getJSON('/data?callback=?', function (data) {
15 
16         // Create the chart
17         $('#container').highcharts('StockChart', {
18 
19             rangeSelector: {
20                 inputEnabled: $('#container').width() > 480,
21                 selected: 1
22             },
23 
24             title: {
25                 text: '51Reboot.com'
26             },
27 
28             series: [{
29                 name: '51Reboot.com',
30                 data: data,
31                 type: 'spline',
32                 tooltip: {
33                     valueDecimals: 2
34                 }
35             }]
36         });
37     });
38 });
39         </script>
40     </head>
41     <body>
42 <script src="http://cdnjs.cloudflare.com/ajax/libs/highstock/2.0.4/highstock.js"></script>
43 <script src="http://code.highcharts.com/modules/exporting.js"></script>
44 
45 
46 <div id="container" style="height: 400px"></div>
47     </body>
48 </html>

web展示页面完成了,运行起来:

python flask_web.py 监听在8888端口上

我们需要做一个agent来采集数据,并上传数据库

moniItems.py

 1 #!/usr/bin/env python
 2 import inspect
 3 import time
 4 import urllib, urllib2
 5 import json
 6 import socket
 7 
 8 class mon:
 9     def __init__(self):
10         self.data = {}
11 
12     def getTime(self):
13         return str(int(time.time()) + 8 * 3600)
14 
15     def getHost(self):
16         return socket.gethostname()
17 
18     def getLoadAvg(self):
19         with open('/proc/loadavg') as load_open:
20             a = load_open.read().split()[:3]
21             return ','.join(a)
22     
23     def getMemTotal(self):
24         with open('/proc/meminfo') as mem_open:
25             a = int(mem_open.readline().split()[1])
26             return a / 1024
27     
28     def getMemUsage(self, noBufferCache=True):
29         if noBufferCache:
30             with open('/proc/meminfo') as mem_open:
31                 T = int(mem_open.readline().split()[1])
32                 F = int(mem_open.readline().split()[1])
33                 B = int(mem_open.readline().split()[1])
34                 C = int(mem_open.readline().split()[1])
35                 return (T-F-B-C)/1024
36         else:
37             with open('/proc/meminfo') as mem_open:
38                 a = int(mem_open.readline().split()[1]) - int(mem_open.readline().split()[1])
39                 return a / 1024
40     
41     def getMemFree(self, noBufferCache=True):
42         if noBufferCache:
43             with open('/proc/meminfo') as mem_open:
44                 T = int(mem_open.readline().split()[1])
45                 F = int(mem_open.readline().split()[1])
46                 B = int(mem_open.readline().split()[1])
47                 C = int(mem_open.readline().split()[1])
48                 return (F+B+C)/1024
49         else:
50             with open('/proc/meminfo') as mem_open:
51                 mem_open.readline()
52                 a = int(mem_open.readline().split()[1])
53                 return a / 1024
54     
55     def runAllGet(self):
56         #自动获取mon类里的所有getXXX方法,用XXX作为key,getXXX()的返回值作为value,构造字典
57         for fun in inspect.getmembers(self, predicate=inspect.ismethod):
58             if fun[0][:3] == 'get':
59                 self.data[fun[0][3:]] = fun[1]()
60         return self.data
61 
62 if __name__ == "__main__":
63     while True:
64         m = mon()
65         data = m.runAllGet()
66         print data
67         req = urllib2.Request("http://51reboot.com:8888", json.dumps(data), {'Content-Type': 'application/json'})
68         f = urllib2.urlopen(req)
69         response = f.read()
70         print response
71         f.close()
72         time.sleep(60)

nohup python moniItems.py >/dev/null 2>&1 & 运行起来

访问 http://51reboot.com:8888 就可以看到我们的监控数据了:效果图如下

欢迎加入运维开发技术分享QQ群:365534424;数百位业内高手和同行在等你交流

长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn