CouchDB と HTML5 でMRTG的なことをしてみるテスト。
ML115をリフレッシュして、完全にCouchDBサーバーにした。いつもLinux入れるときには適当なパフォーマンスモニタツールをいれて、いろいろ集めてほくそ笑んでいるのだが、グラフは canvas で書けるし、データベースは CouchDB で簡単に入るんだから、別に自分でやればいいんじゃね?と、車輪の再発明を試してみました。
これを出すまでにかかった時間は... 15分ぐらい。
とりあえず /proc/ をJSONにする。
最初 awk にしようかと思ったが、JSONに出す、となるとsyntax error が心配だったので、Python。Perl は苦手なので。20行ぐらい。ただJSONにするだけなので、どうでもいいスクリプトです。
#!/usr/bin/env python import json import re from datetime import datetime FILE = "/proc/meminfo" REGEX = re.compile(r"([^:]+):\s+(\d+)\s+(\w+)") if __name__ == "__main__": doc = { "type" : "/proc/meminfo", "result" : {}, "created_at" : datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S +0000"), "updated_at" : datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S +0000") } with open(FILE) as f: for line in f.readlines(): m = REGEX.match(line) if m: name = m.group(1) value = m.group(2) unit = m.group(3) doc["result"][name] = { "value" : int(value), "unit" : unit } print json.dumps(doc)
yssk22@relax:~/stats/formatter$ ./meminfo.py {"created_at": "2010/03/06 14:06:50 +0000", "type": "/proc/meminfo", "result": {"WritebackTmp": {"unit": "kB", "value": 0}, "SwapTotal": {"unit": "kB", "value": 3229024}, "Active(anon)": {"unit": "kB", "value": 58108}, "SwapFree": {"unit": "kB", "value": 3229024}, "MemFree": {"unit": "kB", "value": 2372956}, "Committed_AS": {"unit": "kB", "value": 170288}, "SUnreclaim": {"unit": "kB", "value": 11536}, "NFS_Unstable": {"unit": "kB", "value": 0}, "VmallocChunk": {"unit": "kB", "value": 34359449991}, "Writeback": {"unit": "kB", "value": 0}, "Inactive(file)": {"unit": "kB", "value": 5257096}, "MemTotal": {"unit": "kB", "value": 8195800}, "VmallocUsed": {"unit": "kB", "value": 287820}, "AnonPages": {"unit": "kB", "value": 66092}, "Active": {"unit": "kB", "value": 277352}, "Inactive(anon)": {"unit": "kB", "value": 8416}, "CommitLimit": {"unit": "kB", "value": 7326924}, "Hugepagesize": {"unit": "kB", "value": 2048}, "Cached": {"unit": "kB", "value": 5330420}, "SwapCached": {"unit": "kB", "value": 0}, "VmallocTotal": {"unit": "kB", "value": 34359738367}, "Dirty": {"unit": "kB", "value": 12}, "Mapped": {"unit": "kB", "value": 12472}, "Unevictable": {"unit": "kB", "value": 0}, "SReclaimable": {"unit": "kB", "value": 102340}, "Mlocked": {"unit": "kB", "value": 0}, "DirectMap2M": {"unit": "kB", "value": 8378368}, "Bounce": {"unit": "kB", "value": 0}, "Inactive": {"unit": "kB", "value": 5265512}, "PageTables": {"unit": "kB", "value": 3396}, "DirectMap4k": {"unit": "kB", "value": 10176}, "Slab": {"unit": "kB", "value": 113876}, "Buffers": {"unit": "kB", "value": 146352}, "Active(file)": {"unit": "kB", "value": 219244}}, "updated_at": "2010/03/06 14:06:50 +0000"}
cron で起動
- d @- とすると標準入力から読めるんですね。
*/1 * * * * /usr/bin/python $HOME/stats/formatter/meminfo.py | /usr/bin/curl -X POST -d @- http://${COUCH_USER}:${COUCH_PASS}@localhost:5984/stats */1 * * * * /usr/bin/python $HOME/stats/formatter/stat.py | /usr/bin/curl -X POST -d @- http://${COUCH_USER}:${COUCH_PASS}@localhost:5984/stats
mapreduce でグラフ用のデータにする
function(doc){ if(doc.type == "/proc/meminfo"){ var stat = doc.result; var time = new Date(doc.created_at); for(var key in stat){ var val = stat[key].value; if( val != undefined ){ emit([key, time.getFullYear(), time.getMonth() + 1, time.getDate(), time.getHours(), time.getMinutes() ], val); } } } }
created_at を配列にしているのは、範囲指定を年/月/日/時/分でグループ化できるようにするためです。あとで平均とかのreduce計算を入れてみようと思っているので。
HTML5 canvas の力を借りて list 機能でグラフにする。
jQuery のグラフライブラリでもいいのですが、せっかくなのでHTML5のcanvas試してみよう、と思って、http://www.html5.jp/library/graph_line.html を拝借しました。
適当に作ったのでいい加減ですが、mapの結果からグラフ用のclient side JavaScriptを生成するためのserver side JavaScriptをlistに書いておきます。
send(render(templates.site.html.header, bindings)); var row; var vals = null; var key = null; send('<script type="text/javascript">'); send("var items = [];\n"); while(row = getRow()){ if( row.key[0] != key ){ if( key != null ){ send("]);\n"); } vals = []; key = row.key[0]; send("items.push([" + toJSON(key)); } send("," + toJSON(row.value)); } if( key != null ){ send("]);\n"); } send('</script>'); send(render(templates.history.html.main, bindings)); send(render(templates.site.html.footer, bindings)); return ""; });
テンプレートはこんな感じです。
<div><canvas width="800" height="400" id="sample"></canvas></div> <script type="text/javascript"> $(function(){ var lg = new html5jp.graph.line("sample"); lg.draw(items); }); </script>
結論
- MRTG っぽいことが一瞬でできた。何この快適さ。cron が動いていればOKだし、HTTPなのでリモートサーバーも簡単じゃん。
- stat と meminfo もそうだけど、view で「自分で集計できる」というのは、この手のツールとしては便利じゃん?
- _changes(ドキュメントの変更通知) と _filter(通知を特定条件に絞り込む) 使えば、閾値監視も簡単にできそう。
- 何より、グラフに出すまでがすごくrelax。
- Query Parameter で簡単に?*1任意の期間で絞り込める。
- レプリケーション使えば、ノードグループ毎に集計したりとかも簡単だよね。
- Couch Designer があればグラフ処理もGUIで設定できそう。。
なんかいろいろ可能性ありそうです。
などはもちろんありますけど。まぁお試しってことで。