发表于 2014年9月21日root

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

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

首先数据库建表

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

MySQL

CREATE TABLE `stat` (  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,  `host` varchar(256) DEFAULT NULL,  `mem_free` int(11) DEFAULT NULL,  `mem_usage` int(11) DEFAULT NULL,  `mem_total` int(11) DEFAULT NULL,  `load_avg` varchar(128) DEFAULT NULL,  `time` bigint(11) DEFAULT NULL,  PRIMARY KEY (`id`),  KEY `host` (`host`(255)) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

1

2

3

4

5

6

7

8

9

10

11

CREATE TABLE `stat` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`host` varchar(256) DEFAULT NULL,

`mem_free` int(11) DEFAULT NULL,

`mem_usage` int(11) DEFAULT NULL,

`mem_total` int(11) DEFAULT NULL,

`load_avg` varchar(128) DEFAULT NULL,

`time` bigint(11) DEFAULT NULL,

PRIMARY KEY (`id`),

KEY `host` (`host`(255))

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

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

  1. 完成监控页面展示

  2. 接受POST提交上来的数据

  3. 提供json数据GET接口

目录结构如下:

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

1

2

3

4

web

├── flask_web.py

└── templates

└── mon.html

flask_web.py

flask_web.py

Python

import MySQLdb as mysql import json from flask import Flask, request, render_template app = Flask(__name__) db = mysql.connect(user="reboot", passwd="reboot123", \        db="falcon", charset="utf8") db.autocommit(True) c = db.cursor() @app.route("/", methods=["GET", "POST"]) def hello():    sql = ""    if request.method == "POST":        data = request.json        try:            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']))            ret = c.execute(sql)        except mysql.IntegrityError:            pass        return "OK"    else:        return render_template("mon.html") @app.route("/data", methods=["GET"]) def getdata():    c.execute("SELECT `time`,`mem_usage` FROM `stat`")    ones = [[i[0]*1000, i[1]] for i in c.fetchall()]    return "%s(%s);" % (request.args.get('callback'), json.dumps(ones))     if __name__ == "__main__":    app.run(host="0.0.0.0", port=8888, debug=True)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

import MySQLdb as mysql

import json

from flask import Flask, request, render_template

app = Flask(__name__)

db = mysql.connect(user="reboot", passwd="reboot123", \

db="falcon", charset="utf8")

db.autocommit(True)

c = db.cursor()

@app.route("/", methods=["GET", "POST"])

def hello():

sql = ""

if request.method == "POST":

data = request.json

try:

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']))

ret = c.execute(sql)

except mysql.IntegrityError:

pass

return "OK"

else:

return render_template("mon.html")

@app.route("/data", methods=["GET"])

def getdata():

c.execute("SELECT `time`,`mem_usage` FROM `stat`")

ones = [[i[0]*1000, i[1]] for i in c.fetchall()]

return "%s(%s);" % (request.args.get('callback'), json.dumps(ones))

if __name__ == "__main__":

app.run(host="0.0.0.0", port=8888, debug=True)

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

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

mon.html

XHTML

<title>51reboot.com</title> <!DOCTYPE HTML> <html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">        <title>Highstock Example</title>        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>        <style type="text/css"> ${demo.css}        </style>        <script type="text/javascript"> $(function () {    $.getJSON('/data?callback=?', function (data) {        // Create the chart        $('#container').highcharts('StockChart', {            rangeSelector: {                inputEnabled: $('#container').width() > 480,                selected: 1            },            title: {                text: '51Reboot.com'            },            series: [{                name: '51Reboot.com',                data: data,                type: 'spline',                tooltip: {                    valueDecimals: 2                }            }]        });    }); });        </script>    </head>    <body> <script src="http://cdnjs.cloudflare.com/ajax/libs/highstock/2.0.4/highstock.js"></script> <script src="http://code.highcharts.com/modules/exporting.js"></script> <div id="container" style="height: 400px"></div>    </body> </html>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

<title>51reboot.com</title>

<!DOCTYPE HTML>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<title>Highstock Example</title>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>

<style type="text/css">

${demo.css}

</style>

<script type="text/javascript">

$(function () {

$.getJSON('/data?callback=?', function (data) {

// Create the chart

$('#container').highcharts('StockChart', {

rangeSelector: {

inputEnabled: $('#container').width() > 480,

selected: 1

},

title: {

text: '51Reboot.com'

},

series: [{

name: '51Reboot.com',

data: data,

type: 'spline',

tooltip: {

valueDecimals: 2

}

}]

});

});

});

</script>

</head>

<body>

<script src="http://cdnjs.cloudflare.com/ajax/libs/highstock/2.0.4/highstock.js"></script>

<script src="http://code.highcharts.com/modules/exporting.js"></script>

<div id="container" style="height: 400px"></div>

</body>

</html>

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

python flask_web.py 监听在8888端口上

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

moniItems.py

moniItems.py

Python

#!/usr/bin/env python import inspect import time import urllib, urllib2 import json import socket class mon:    def __init__(self):        self.data = {}    def getTime(self):        return str(int(time.time()) + 8 * 3600)    def getHost(self):        return socket.gethostname()    def getLoadAvg(self):        with open('/proc/loadavg') as load_open:            a = load_open.read().split()[:3]            return ','.join(a)        def getMemTotal(self):        with open('/proc/meminfo') as mem_open:            a = int(mem_open.readline().split()[1])            return a / 1024        def getMemUsage(self, noBufferCache=True):        if noBufferCache:            with open('/proc/meminfo') as mem_open:                T = int(mem_open.readline().split()[1])                F = int(mem_open.readline().split()[1])                B = int(mem_open.readline().split()[1])                C = int(mem_open.readline().split()[1])                return (T-F-B-C)/1024        else:            with open('/proc/meminfo') as mem_open:                a = int(mem_open.readline().split()[1]) - int(mem_open.readline().split()[1])                return a / 1024        def getMemFree(self, noBufferCache=True):        if noBufferCache:            with open('/proc/meminfo') as mem_open:                T = int(mem_open.readline().split()[1])                F = int(mem_open.readline().split()[1])                B = int(mem_open.readline().split()[1])                C = int(mem_open.readline().split()[1])                return (F+B+C)/1024        else:            with open('/proc/meminfo') as mem_open:                mem_open.readline()                a = int(mem_open.readline().split()[1])                return a / 1024        def runAllGet(self):        #自动获取mon类里的所有getXXX方法,用XXX作为key,getXXX()的返回值作为value,构造字典        for fun in inspect.getmembers(self, predicate=inspect.ismethod):            if fun[0][:3] == 'get':                self.data[fun[0][3:]] = fun[1]()        return self.data if __name__ == "__main__":    while True:        m = mon()        data = m.runAllGet()        print data        req = urllib2.Request("http://51reboot.com:8888", json.dumps(data), {'Content-Type': 'application/json'})        f = urllib2.urlopen(req)        response = f.read()        print response        f.close()        time.sleep(60)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

#!/usr/bin/env python

import inspect

import time

import urllib, urllib2

import json

import socket

class mon:

def __init__(self):

self.data = {}

def getTime(self):

return str(int(time.time()) + 8 * 3600)

def getHost(self):

return socket.gethostname()

def getLoadAvg(self):

with open('/proc/loadavg') as load_open:

a = load_open.read().split()[:3]

return ','.join(a)

def getMemTotal(self):

with open('/proc/meminfo') as mem_open:

a = int(mem_open.readline().split()[1])

return a / 1024

def getMemUsage(self, noBufferCache=True):

if noBufferCache:

with open('/proc/meminfo') as mem_open:

T = int(mem_open.readline().split()[1])

F = int(mem_open.readline().split()[1])

B = int(mem_open.readline().split()[1])

C = int(mem_open.readline().split()[1])

return (T-F-B-C)/1024

else:

with open('/proc/meminfo') as mem_open:

a = int(mem_open.readline().split()[1]) - int(mem_open.readline().split()[1])

return a / 1024

def getMemFree(self, noBufferCache=True):

if noBufferCache:

with open('/proc/meminfo') as mem_open:

T = int(mem_open.readline().split()[1])

F = int(mem_open.readline().split()[1])

B = int(mem_open.readline().split()[1])

C = int(mem_open.readline().split()[1])

return (F+B+C)/1024

else:

with open('/proc/meminfo') as mem_open:

mem_open.readline()

a = int(mem_open.readline().split()[1])

return a / 1024

def runAllGet(self):

#自动获取mon类里的所有getXXX方法,用XXX作为key,getXXX()的返回值作为value,构造字典

for fun in inspect.getmembers(self, predicate=inspect.ismethod):

if fun[0][:3] == 'get':

self.data[fun[0][3:]] = fun[1]()

return self.data

if __name__ == "__main__":

while True:

m = mon()

data = m.runAllGet()

print data

req = urllib2.Request("http://51reboot.com:8888", json.dumps(data), {'Content-Type': 'application/json'})

f = urllib2.urlopen(req)

response = f.read()

print response

f.close()

time.sleep(60)

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

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

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