Python寫(xiě)的一個(gè)簡(jiǎn)單監(jiān)控系統(tǒng)
市面上有很多開(kāi)源的監(jiān)控系統(tǒng):Cacti、nagios、zabbix。感覺(jué)都不符合我的需求,為什么不自己做一個(gè)呢
用Python兩個(gè)小時(shí)徒手?jǐn)]了一個(gè)簡(jiǎn)易的監(jiān)控系統(tǒng),給大家分享一下,希望能對(duì)大家有所啟發(fā)
首先數(shù)據(jù)庫(kù)建表
建立一個(gè)數(shù)據(jù)庫(kù)“falcon”,建表語(yǔ)句如下:
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;
首先我們?cè)O(shè)計(jì)一個(gè)web服務(wù),實(shí)現(xiàn)如下功能:
1.完成監(jiān)控頁(yè)面展示
2.接受POST提交上來(lái)的數(shù)據(jù)
3.提供json數(shù)據(jù)GET接口
目錄結(jié)構(gòu)如下:
web
├── flask_web.py
└── templates
└── mon.html
[/code]
flask_web.py
[code]
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)
這個(gè)template頁(yè)面是我抄的highstock的示例,mon.html
簡(jiǎn)單起見(jiàn)我們只展示mem_usage信息到頁(yè)面上
<title>jb51.net</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: 'jb51.net'
},
series: [{
name: 'jb51.net',
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展示頁(yè)面完成了,運(yùn)行起來(lái):
Python flask_web.py 監(jiān)聽(tīng)在8888端口上
我們需要做一個(gè)agent來(lái)采集數(shù)據(jù),并上傳數(shù)據(jù)庫(kù)
moniItems.py
#!/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):
#自動(dòng)獲取mon類里的所有g(shù)etXXX方法,用XXX作為key,getXXX()的返回值作為value,構(gòu)造字典
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://jb51.net: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 & 運(yùn)行起來(lái)
訪問(wèn) http://jb51.net:8888 就可以看到我們的監(jiān)控?cái)?shù)據(jù)了:效果圖如下

相關(guān)文章
給Python中的MySQLdb模塊添加超時(shí)功能的教程
這篇文章主要介紹了給Python中的MySQLdb模塊添加超時(shí)功能的教程,timeout功能在服務(wù)器的運(yùn)維當(dāng)中非常有用,需要的朋友可以參考下2015-05-05
一文教你使用Python實(shí)現(xiàn)本地分頁(yè)
這篇文章主要為大家詳細(xì)介紹了Python如何實(shí)現(xiàn)本地分頁(yè)的算法,主要針對(duì)二級(jí)數(shù)據(jù)結(jié)構(gòu),文中的示例代碼簡(jiǎn)潔易懂,有需要的小伙伴可以了解下2025-02-02
python安裝mysql的依賴包mysql-python操作
這篇文章主要介紹了python安裝mysql的依賴包mysql-python操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-01-01
Python中time庫(kù)的使用(日期時(shí)間)
time庫(kù)是python中處理時(shí)間的標(biāo)準(zhǔn)庫(kù),這篇文章主要介紹了Python中time庫(kù)的使用(日期時(shí)間),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-02-02
Python數(shù)據(jù)可視化制作全球地震散點(diǎn)圖
這篇文章主要介紹了Python數(shù)據(jù)可視化制作全球地震散點(diǎn)圖,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-08-08
微信小程序前端如何調(diào)用python后端的模型詳解
近期需要開(kāi)發(fā)一個(gè)打分的微信小程序,涉及到與后臺(tái)服務(wù)器的數(shù)據(jù)交互,這篇文章主要給大家介紹了關(guān)于微信小程序前端如何調(diào)用python后端模型的相關(guān)資料,需要的朋友可以參考下2022-04-04

