CouchDB と HTML5 でMRTG的なことをしてみるテスト。

ML115をリフレッシュして、完全にCouchDBサーバーにした。いつもLinux入れるときには適当なパフォーマンスモニタツールをいれて、いろいろ集めてほくそ笑んでいるのだが、グラフは canvas で書けるし、データベースは CouchDB で簡単に入るんだから、別に自分でやればいいんじゃね?と、車輪の再発明を試してみました。

これを出すまでにかかった時間は... 15分ぐらい。

とりあえず /proc/ をJSONにする。

最初 awk にしようかと思ったが、JSONに出す、となるとsyntax error が心配だったので、PythonPerl は苦手なので。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 のグラフライブラリでもいいのですが、せっかくなのでHTML5canvas試してみよう、と思って、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で設定できそう。。

なんかいろいろ可能性ありそうです。

などはもちろんありますけど。まぁお試しってことで。

*1:CouchDBのspecしらないと大変か