2013年5月29日水曜日

tail -f をブラウザで表示

tail -f /var/log/httpd/access_log 
tail -f /var/log/httpd/error_log

まーよく使いますね。

ディレクターとかお客さん(プログラムわかりませんの人)とかでもデバッグ中にログ流しながらできたら、デバッグしてますっぽい雰囲気出て楽しいんじゃないかと思ったけど、
sshつないでもらうの怖いしなー。
っていうことでブラウザにログを流してみましょう。

実際やるときはパーミッションとか認証とかちゃんとがんばってください。

デモ

デモ

ユーザ:guest
パス:naisyo

socketIO

使うのはちょっと前に流行ったnodeのモジュール socketIO。
websocketを使いやすくしてくれてるようです。

インストール

nvm, node-dev, socketIO, forever のインストール

git clone https://github.com/creationix/nvm.git ~/.nvm
source ~/.nvm/nvm.sh
nvm install v0.10.8
npm install socket.io -g
npm install node-dev -g
npm install forever -g

下記サイトがわかりやすいのでどうぞ↓

サーバサイド

server.js

// dump
// http://creator.cotapon.org/articles/node-js/node_js-object-consoledump
function dump(v){
    return console.log(util.inspect(v));
}

// ログ確認クラス
var fs = require("fs");
var WatchLog = function(){
 this._initialize.apply(this, arguments);
};
WatchLog.prototype._initialize = function(config){
 var logList = [];
 var files = config['files'];
 var onChangeLog = config['onChangeLog'];
 for(var i=0,max=files.length;i<max;i++){
  var file = files[i];
  if(!fs.existsSync(file)){
   console.log("no file :" + file);
   continue;
  }
  var logIns = new WatchLog.Log(file, onChangeLog);
  logList.push(logIns);
 }

 this._logList = logList;
};
WatchLog.Log = function(){
 this._initialize.apply(this,arguments);
};
WatchLog.Log.prototype._initialize = function(filename, callback){
 this._filename = filename;
 this._callback = callback;
 var self = this;
 fs.watch(filename, {}, function(event, filename){
  self._onChange();
 });
};
WatchLog.Log.prototype._onChange = function(){
 this._callback(this);
};
WatchLog.Log.prototype.getFilename = function(){
 return this._filename;
};

// socketIo
var io = require('socket.io').listen(8080, {'log level': 2});
var sockets = io.sockets;
sockets.on('connection', function (socket) {
    console.log("connection id:" + socket.id);
});

// ログ監視 Go!
var exec = require('child_process').exec;
var watchLog = new WatchLog({
 files:[
  "/var/log/httpd/access_log"
  , "/var/log/httpd/error_log"
  , "/var/log/mysqld.log"
  , "/var/www/rails/rssapp/log/development.log"
  , "/home/webapp/socketiotest/node_log"
  , "/home/webapp/socketiotest/node_error_log"
  ]
 , onChangeLog:function(logIns /* WatchLog.Log */){
  var filename = logIns.getFilename();
  exec('tail -1 '+ filename, function(err, stdout, stderr){
   if(err) throw err;
   var data = {
    result:stdout
    , filename:filename
   };
   io.sockets.emit('onChange', data);
  });
 }
});

つなぎっぱなしイベントドリブンっていう感じが新鮮ですね。

exec('tail -1 '+ filename, function(err, stdout, stderr){
)};

このへん
プロセス立ち上げるんだけど、コールバックを指定できる。
フロントも待たせない。
いいなー。

デーモンで起動

startnodedeamon.sh

readonly NODE_SERVER_DIR="/home/webapp/socketiotest"
source ~/.nvm/nvm.sh
nvm use v0.10.8
forever start ${NODE_SERVER_DIR}/server.js >${NODE_SERVER_DIR}/node_log  2>> ${NODE_SERVER_DIR}/node_error_log

フロント

フロントはhtml,js で

index.html

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="UTF-8">
    <title>socketSample</title>
    <link rel="stylesheet" href="index.css" />
  </head>
  <body>  
    <div id="wrap">
      <div class="logarea" id="httpdaccess">
        <h2>var/log/httpd/access_log</h2>
        <pre></pre>
      </div>
      <div class="logarea" id="httpderror">
        <h2>var/log/httpd/error_log</h2>
        <pre></pre>
      </div>
      <div class="logarea" id="railsdevelop">
        <h2>/var/www/rails/rssapp/log/development.log</h2>
        <pre></pre>
      </div>
      <div class="logarea" id="mysqlerror">
        <h2>var/log/mysqld.log</h2>
        <pre></pre>
      </div>
      <div class="logarea" id="node">
        <h2>/home/webapp/socketiotest/node_log</h2>
        <pre></pre>
      </div>
      <div class="logarea" id="nodeerror">
        <h2>/home/webapp/socketiotest/node_error_log</h2>
        <pre></pre>
      </div>
    </div>
    <script src="http://colors.jp.net:8080/socket.io/socket.io.js"></script>
    <script src="index.js"></script>
  </body>
</html>

index.js

var socket = io.connect('http://colors.jp.net:8080');

var domIdMap = {
 '/var/log/httpd/access_log': 'httpdaccess'
 , '/var/log/httpd/error_log': 'httpderror'
 , '/var/log/mysqld.log': 'mysqlerror'
 , '/var/www/rails/rssapp/log/development.log': 'railsdevelop'
 , '/home/webapp/socketiotest/node_log': 'node'
 , '/home/webapp/socketiotest/node_error_log': 'nodeerror'
};

socket.on("onChange", function(data){
 var filename = data.filename;
 var result = data.result;

 var domId = domIdMap[filename];
 var dom = document.querySelector("#" + domId + " pre");
 var parent = dom.parentNode;
 dom.innerHTML += result;
 parent.scrollTop = parent.scrollHeight;
});

こんだけです、socketIOべんりー

0 件のコメント:

コメントを投稿