328 lines
No EOL
17 KiB
HTML
328 lines
No EOL
17 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="tool" content="leanote-desktop-app">
|
||
<title>用Python写一个简单的监控系统 - 51reboot</title>
|
||
<style>
|
||
|
||
*{font-family:"lucida grande","lucida sans unicode",lucida,helvetica,"Hiragino Sans GB","Microsoft YaHei","WenQuanYi Micro Hei",sans-serif;}
|
||
|
||
body {
|
||
margin: 0;
|
||
}
|
||
|
||
/*公用文字样式*/
|
||
h1{font-size:30px}h2{font-size:24px}h3{font-size:18px}h4{font-size:14px}
|
||
.note-container{
|
||
width:850px;
|
||
margin:auto;
|
||
padding: 10px 20px;
|
||
box-shadow: 1px 1px 10px #eee;
|
||
}
|
||
#title {
|
||
margin: 0;
|
||
}
|
||
table {
|
||
margin-bottom: 16px;
|
||
border-collapse: collapse;
|
||
}
|
||
table th, table td {
|
||
padding: 6px 13px;
|
||
border: 1px solid #ddd;
|
||
}
|
||
table th {
|
||
font-weight: bold;
|
||
}
|
||
|
||
table tr {
|
||
background-color: none;
|
||
border-top: 1px solid #ccc;
|
||
}
|
||
table tr:nth-child(2n) {
|
||
background-color: rgb(247, 247, 249);
|
||
}
|
||
.mce-item-table, .mce-item-table td, .mce-item-table th, .mce-item-table caption {
|
||
border: 1px solid #ddd;
|
||
border-collapse: collapse;
|
||
padding: 6px 13px;
|
||
}
|
||
blockquote {
|
||
border-left-width:10px;
|
||
background-color:rgba(128,128,128,0.05);
|
||
border-top-right-radius:5px;
|
||
border-bottom-right-radius:5px;
|
||
padding:15px 20px;
|
||
border-left:5px solid rgba(128,128,128,0.075);
|
||
}
|
||
blockquote p {
|
||
margin-bottom:1.1em;
|
||
font-size:1em;
|
||
line-height:1.45
|
||
}
|
||
blockquote ul:last-child,blockquote ol:last-child {
|
||
margin-bottom:0
|
||
}
|
||
pre {
|
||
padding: 18px;
|
||
background-color: #f7f7f9;
|
||
border: 1px solid #e1e1e8;
|
||
border-radius: 3px;
|
||
display: block;
|
||
}
|
||
code {
|
||
padding: 2px 4px;
|
||
font-size: 90%;
|
||
color: #c7254e;
|
||
white-space: nowrap;
|
||
background-color: #f9f2f4;
|
||
border-radius: 4px;
|
||
}
|
||
.footnote {
|
||
vertical-align: top;
|
||
position: relative;
|
||
top: -0.5em;
|
||
font-size: .8em;
|
||
}
|
||
|
||
hr {
|
||
margin:2em 0
|
||
}
|
||
img {
|
||
max-width:100%
|
||
}
|
||
pre {
|
||
word-break:break-word
|
||
}
|
||
p,pre,pre.prettyprint,blockquote {
|
||
margin:0 0 1.1em
|
||
}
|
||
hr {
|
||
margin:2em 0
|
||
}
|
||
img {
|
||
max-width:100%
|
||
}
|
||
.sequence-diagram,.flow-chart {
|
||
text-align:center;
|
||
margin-bottom:1.1em
|
||
}
|
||
.sequence-diagram text,.flow-chart text {
|
||
font-size:15px !important;
|
||
font-family:"Source Sans Pro",sans-serif !important
|
||
}
|
||
.sequence-diagram [fill="#ffffff"],.flow-chart [fill="#ffffff"] {
|
||
fill:#f6f6f6
|
||
}
|
||
.sequence-diagram [stroke="#000000"],.flow-chart [stroke="#000000"] {
|
||
stroke:#3f3f3f
|
||
}
|
||
.sequence-diagram text[stroke="#000000"],.flow-chart text[stroke="#000000"] {
|
||
stroke:none
|
||
}
|
||
.sequence-diagram [fill="#000"],.flow-chart [fill="#000"],.sequence-diagram [fill="#000000"],.flow-chart [fill="#000000"],.sequence-diagram [fill="black"],.flow-chart [fill="black"] {
|
||
fill:#3f3f3f
|
||
}
|
||
ul,ol {
|
||
margin-bottom:1.1em
|
||
}
|
||
ul ul,ol ul,ul ol,ol ol {
|
||
margin-bottom:1.1em
|
||
}
|
||
kbd {
|
||
padding:.1em .6em;
|
||
border:1px solid rgba(63,63,63,0.25);
|
||
-webkit-box-shadow:0 1px 0 rgba(63,63,63,0.25);
|
||
box-shadow:0 1px 0 rgba(63,63,63,0.25);
|
||
font-size:.7em;
|
||
font-family:sans-serif;
|
||
background-color:#fff;
|
||
color:#333;
|
||
border-radius:3px;
|
||
display:inline-block;
|
||
margin:0 .1em;
|
||
white-space:nowrap
|
||
}
|
||
.toc ul {
|
||
list-style-type:none;
|
||
margin-bottom:15px
|
||
}
|
||
</style>
|
||
<!-- 该css供自定义样式 -->
|
||
<link href="../leanote-html.css" rel="stylesheet">
|
||
</head>
|
||
|
||
<body>
|
||
|
||
<div class="note-container">
|
||
<h1 class="title" id="leanote-title">用Python写一个简单的监控系统 - 51reboot</h1>
|
||
<div class="content-html" id="leanote-content"><p>市面上有很多开源的监控系统:Cacti、nagios、zabbix。感觉都不符合我的需求,为什么不自己做一个呢</p><p>用Python两个小时徒手撸了一个简易的监控系统,给大家分享一下,希望能对大家有所启发</p><p>首先数据库建表</p><p>建立一个数据库“falcon”,建表语句如下:</p><pre id="leanote_ace_1479693920366_0" class="brush:python ace-tomorrow" data-mce-style="line-height: 1.5; font-size: 14px; height: 231px;">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;</pre><p>首先我们设计一个web服务,实现如下功能:</p><ol><li>完成监控页面展示</li><li>接受POST提交上来的数据</li><li>提供json数据GET接口</li></ol><p>目录结构如下:</p><pre id="leanote_ace_1479795467113_0" class="ace-tomorrow">web
|
||
├── flask_web.py
|
||
└── templates
|
||
└── mon.html</pre><p>flask_web.py</p><pre id="leanote_ace_1479693978975_0" class="brush:python ace-tomorrow" data-mce-style="line-height: 1.5; font-size: 14px; height: 693px;">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)</pre><p>这个template页面是我抄的highstock的示例,mon.html</p><p>简单起见我们只展示mem_usage信息到页面上</p><pre id="leanote_ace_1479695091757_0" class="ace-tomorrow brush:html">
|
||
<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></pre><p>python flask_web.py 监听在8888端口上</p><p>我们需要做一个agent来采集数据,并上传数据库</p><p>moniItems.py</p><pre id="leanote_ace_1479694477128_0" class="brush:python ace-tomorrow">#!/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)</pre><p>nohup python moniItems.py >/dev/null 2>&1 & 运行起来</p><p><img id="__LEANOTE_D_IMG_1479695175380" src="http://192.168.56.4:9000/api/file/getImage?fileId=5833f84623eeeb0f8f0000c4" alt="chart" data-mce-src="http://192.168.56.4:9000/api/file/getImage?fileId=5833f84623eeeb0f8f0000c4"><img src="http://192.168.56.4:9000/api/file/getImage?fileId=5833f84623eeeb0f8f0000c5" alt="" data-mce-src="http://192.168.56.4:9000/api/file/getImage?fileId=5833f84623eeeb0f8f0000c5"></p></div>
|
||
</div>
|
||
|
||
<!-- 该js供其它处理 -->
|
||
<script src="../leanote-html.js"></script>
|
||
</body>
|
||
</html> |