Nov 14, 2005

Ajaxで簡単リソースモニター

クラスタなどのリソースモニターをAjaxを使って実現すると、Ganglia Monitoring Systemみたいな味気なさ(最近はチェックしていないのでカッコヨクなっていたらスマソ)が解決したり、Centralized Serverで行う実質的なレンダリング(一般的にはHTML生成)のオーバーヘッドが抑制できたりするのではないかとふと思いついてしまいました。まあJava Appletを使えば済むと言えばまったくその通りなのですけれど。

ともかくやってみました。nantoさんのブラウザ上でお絵かき: Days on the Moonを利用します。描画ルーチンの利用方法に関してはこちらを参考にさせていただいています。

まず、簡単なAjax Client Libraryを用意します。AjaxClient.jsという名前にしておきます。いろいろブラウザごとの非互換性があるので、注意深くググればもっとよくできたライブラリが見つかるでしょう。

2005-12-13修正: Ajax Client Libraryをざっくり修正。ときどきいじっているので下から最新版をゲットしてください。

AjaxClient.js

// Ajax Client Library

AjaxClient = function() {}

AjaxClient.initClient = function() {
  if (window.XMLHttpRequest)
    return new XMLHttpRequest();
  var types = [
         "Microsoft.XMLHTTP",
         "MSXML2.XMLHTTP.5.0",
         "MSXML2.XMLHTTP.4.0",
         "MSXML2.XMLHTTP.3.0",
         "MSXML2.XMLHTTP"
  ];
  for (var i in types) {
    try {
      return new ActiveXObject(types[i]);
    } catch(e) {}
  }
  return null;
}

AjaxClient.call = function(param) {
  var uri = param['uri'];
  if (!uri) return;
  var c = AjaxClient.initClient();
  if (!c) return;
  var method = param['method'].toUpperCase() || 'GET';
  // add random bits to avoid caching in some UA
  uri += (uri.match(/\?/) ? '&' : '?') + '.r=' + Math.random(1);
  var content = null;
  if (param['args']) {
    var args = new Array();
    for (var a in param['args'])
      args.push(a + '=' + encodeURIComponent(param['args'][a]));
    content = args.join('&');
  }
  if (content && method == 'GET') {
    uri += '&' + content;
    content = null;
  }
  c.open(method, uri, true);
  c.onreadystatechange = function() {
    switch (c.readyState) {
    case 1:
      if (param['loading']) param['loading'](c);
      break;
    case 2:
      if (param['loaded']) param['loaded'](c);
      break;
    case 3:
      if (param['interactive']) param['interactive'](c);
      break;
    case 4:
      if (c.status && (c.status != 200)) {
        if (param['error'])
          param['error'](c, c.responseText);
        else
          alert('Error: [' + c.status + '] ' + c.responseText);
      } else if (param['load'])
        param['load'](c, c.responseText);
      break;
    }
  };
  if (content)
    c.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  c.send(content);
}

次にモニタリング用のインタフェースを用意します。ここでは簡単のためにマシンのuptimeを監視するものとし、例えば以下のような内容のCGIを用意します(uptime.cgi)。

#!/bin/sh
echo Content-type: text/plain
echo
uptime

最後にモニターをレンダリングするHTMLです。サーバーのuptime.cgiを5秒おきにポーリングしてload averageをプロットしてくれます。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Uptime monitor</title>
<script type="text/javascript" src="AjaxClient.js"></script>
<script type="text/javascript" src="DrawingCanvas.js"></script>
</head>
<body>
<div id="canvas" style="position:absolute;top:10px;left:10px"></div>
<script type="text/javascript">
var canvas = new DrawingCanvas(document.getElementById('canvas'), 600, 200);
canvas.parent.setAttribute('style', 'position:absolute;top:10px;left:10px');
canvas.setBgColor("#eee");
canvas.setLineColor("#800");
canvas.setLineWidth(1);
for (var y = 0; y <= 200; y += 50) {
  canvas.startLine(0, y);
  canvas.lineTo(620, y);
  canvas.endLine();
}
canvas.setLineColor("#888");
for (var x = 0; x <= 640; x += 20) {
  canvas.startLine(x, 0);
  canvas.lineTo(x, 200);
  canvas.endLine();
}

var loadList = new Array();

function drawCanvas(c, result) {
  if (!result) return;
  if (loadList.length) canvas.undo();
  if (loadList.length > 60) loadList.shift();
  result.match(/load average: ([\d.]+),/);
  loadList[loadList.length] = RegExp.$1;

  canvas.setLineColor("#f00");
  canvas.setLineWidth(2);
  var x = 0;
  canvas.startLine(x, 200 - loadList[0] * 100);
  for (var i = 1; i < loadList.length; i++) {
    x += 10;
    canvas.lineTo(x, 200 - loadList[i] * 100);
  }
  canvas.endLine();
}

function doClientCall() {
  AjaxClient.call({
    'load': drawCanvas,
    'uri': 'uptime.cgi'
  });
}

var timer;
function toggleTimer(o) {
  if (o.value == 'Start') {
    o.value = 'Stop';
    // set Interval Time by msec
    timer = setInterval('doClientCall()', 5000);
  } else {
    o.value = 'Start';
    if (timer) clearInterval(timer);
  }
}
</script>
<div style="position:absolute;top:220px;left:10px"><input type="button" value="Start" onclick="toggleTimer(this)" /></div>
</body>
</html>

プロットする値の系列が複数になってもdrawCanvasをちょっと変更するだけで済みますね。

それにしてもDrawingCanvas様様です。Firefox 1.0xではdivエレメントを山ほど生成してプロットされるので非常に遅いのですが、1.5RC2を使うと早速導入されたSVGエンジンで、Internet ExplorerではVMLでそれぞれレンダリングしてくれます。

というわけで(何が?)、SC|05でSeattleに来ています。OOPSLA 2002のときと同じWashington State Convention Center。誰か蟹のうまい中華レストランを教えてください。

About Me

My Photo

つくばで働く研究者

Total Pageviews

Amazon

Copyright 2012 Ogawa::Buzz | Powered by Blogger
Design by Web2feel | Blogger Template by NewBloggerThemes.com