構成はこのようになっていました。
+----------------------------+ +------------------------+ | web server (10.0.0.8) | | mongo server(10.0.0.16)| |----------------------------| |------------------------| | fluentd | | | | | | | | +---------+ +--------+ | | +----------+ | | | input | | output | | | | fluent | | | |---------|+--> |--------| +--------->|----------| | | | tail | | mongo | | | | test | | | +---------+ +--------+ | | +----------+ | +----------------------------+ +------------------------+
今回はnode.jsを使用して、mongoDBに保存されたログをブラウザでリアルタイムにtailしてみます。
構成は以下のとおりです。
+----------------------------+ +-------------------------+ | web server (10.0.0.8) | | mongo server(10.0.0.16) | |----------------------------| |-------------------------| | fluentd | | mongod | | | | | | +---------+ +--------+ | | +----------+ | | | input | | output | | | | fluent | | | |---------|+--> |--------|+---------->|----------| | | | tail | | mongo | | | | logs | | | +---------+ +--------+ | | +-----+----+ | +----------------------------+ +------------|------------+ | +--------------+ | +-------------------------+ | | node server(10.0.0.100) | | |-------------------------| | | node.js | | | | | | +-----------+ | +------->| mongoose | | | |-----------| | | | socket.io +----------> Brower | +-----------+ | +-------------------------+
今回、web serverとmongo serverは、ほとんど前回の設定のままですが、
新規nodeサーバーでmongodbにアクセスするmongooseはデフォルトで複数系の名前のコレクションにアクセスするようになっています。
そこで、webサーバーのtd-agentのmongo outputプラグインの書き出し先をlogsという名前に変更しておきます。
また、リアルタイムに表示させたいのでflush_intervalを0sに設定しておきます。
<source> type tail format apache path /var/log/httpd/access_log tag apache.access </source> <match apache.access="apache.access"> type mongo flush_interval 0s database fluent collection logs host 10.0.0.16 user memorycraft password ******* </match>
それでは、nodeサーバーを設定します。
新規にEC2インスタンスをたちあげてnodeとhttpdをインストールします。
# yum install httpd -y # /etc/init.d/httpd start # yum install -y wget # cd /usr/local/src/ # wget http://nodejs.org/dist/v0.8.14/node-v0.8.14.tar.gz # tar xzvf node-v0.8.14.tar.gz # cd node-v0.8.14 # ./configure # make # make install
次にnpmをインストールしてからsocket.io, log, forever, mongooseをnpmインストールします。
# curl https://npmjs.org/install.sh | sh # npm install -g socket.io # npm install -g forever
nodeを動かすためのユーザーを作成します
# useradd appadmin # passwd appadmin # chmod 755 /home/appadmin # su - appadmin
ノードモジュールへのパスを通すために環境変数を設定します。
$ vi ~/.bash_profile $ source ~/.bash_profile --- export NODE_PATH=/usr/local/lib/node_modules --- $ source ~/.bash_profile
ここで、nodeサーバーとHTML用のコンテンツ置き場を用意します。
ディレクトリ構成は以下のとおりです。
cd ~/nodetest tree . |-- node | |-- logs | | `-- app.log | `-- server.js (nodeサーバー) `-- public |-- assets | |-- css | |-- img | `-- js | `-- client.js (nodeクライアント) `-- index.html (tail用の画面)
また、publicをhttpdのDocumentRootにするため、以下のように設定します。
$ su - # cd /var/www # mv html html.org # ln -s /home/appadmin/nodetest/public html # vi /etc/httpd/conf/httpd/conf --- ~略~ <directory html="html" var="var" www="www"> Options FollowSymLinks AllowOverride All ~略~ --- </directory> # /etc/init.d/httpd restart
そして、httpdとnodeに接続させるため、SecurityGroupを以下のように設定します。
次にサーバーとコンテンツを実装してみます。 それぞれの内容は以下の通りです。
node/server.js
//3001番でlistenします var server = require('http').createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/html'}); res.end('server connected'); }); server.listen(3001); //logsコレクションのスキーマ定義をしておきます。 var mongoose = require('mongoose'); var Schema = mongoose.Schema; var AccessSchema = new Schema({ host: String, user: String, method: String, path: String, code: Number, size: Number, referer: String, agent: String, time : Date }); mongoose.model('log', AccessSchema); //fluentデータベースに接続します。 mongoose.connect('mongodb://10.0.0.16/fluent'); var Access = mongoose.model('log'); //socket.ioを起動します。 var io = require('socket.io').listen(server); io.sockets.on('connection', function (socket) { /** * クライアント接続時に、初期データとして、 * 保存されているlogsコレクションをすべてemitします。 */ Access.find({}).sort({time:1}).exec(function(e, docs){ if(e){ } else{ socket.emit('init', docs); } }); }); /** * 1.5秒おきに最終取得ログの日時以降のログを取得して * 全員にブロードキャストし、最終日時を保存します。 */ var last = new Date(); setInterval(function(){ Access.find({}).where('time').gt(last).sort({time:1}).exec(function(e, docs){ if(e){ } else{ for(var i=0; i<docs.length; i++){ if(last < docs[i].time){ last = docs[i].time; } } io.sockets.emit('log', docs); } }); }, 1500);
public/assets/js/client.js
$(function(){ //接続します var socket = io.connect('http://' + location.hostname + ':3001/'); socket.on('connect', function() { /** * 接続成功時に初期データを時系列降順で表示させます */ socket.on('init', function(data){ $("#log").empty(); for(var i=0; i<data.length; i++){ row = data[i]; $("#log").prepend(row.host+" "+row.time+" "+row.path+"<br/>"); } }); /** * 随時送られてくるデータは一番上に表示させます */ socket.on('log', function(data){ for(var i=0; i<data.length; i++){ row = data[i]; $("#log").prepend(row.host+" "+row.time+" "+row.path+"<br/>"); } }); }); });
public/index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript"> $(function(){ function load(){ $.getScript("assets/js/client.js"); } $.getScript("http://" + location.hostname + ":3001/socket.io/socket.io.js", function(){ load(); }); }); </script> <body> <div id="content"> <h1>ログ</h1> <div id="log" width="500px" height="100%"> </div> </div> </body> </html>
早速動かしてみます。
$ cd ~/nodetest/node $ forever start server.js
これでnodeサーバーが起動しました
それでは、ブラウザを見てみます。
初期ログが表示されています。うまく動いているようです。
そこで、fluentdのtail対象サーバーであるwebサーバーへアクセスをしてみます。
わかりやすくするために、何度かリロードしておきます。
そして、さきほどのnodeサーバーの画面をみると、、、
おお!ログが追加で現れました!
これであるサーバーのログデータを別のサーバーでリアルタイムに表示させることができました。
以上です。