Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8832

log.ioでログをブラウザでリアルタイムモニタリングする

$
0
0

「log.io」を使ってログを集約し、ブラウザからリアルタイムにモニタリングしてみます。

log.io
 http://logio.org/

log.ioは、TCPでログを受信するとともに、ブラウザからログを参照することができます。
Webサーバの機能が付いているので楽ちんなのと、WebSocketを使っているので、リアルタイムにログが出力されてきます。
それから、TCPでログを受信するので、AndroidやArduinoやNode.jsなど、様々なプラットフォームからのログを集約することができそうです。

log.ioのセットアップ

npmでモジュール化されています。

npm install -g log.io
mkdir ~/.log.io
vi ~/.log.io/server.json
log.io-server

server.jsonはこんな感じです。

json;server.json
{"messageServer":{"port":6689,"host":"【起動させるマシンのIPアドレス】"},"httpServer":{"port":6688,"host":"【起動させるマシンのIPアドレス】"},"debug":false,"basicAuth":{"realm":"【適当な名前】","users":{"【ログインユーザ名】":"【ログインパスワード】"}}}

【起動させるマシンのIPアドレス】には、log.ioを起動させたマシンのホスト名またはIPアドレスを指定します。
上記の場合、ポート6688にWebサーバが立ち上がり、ポート6689にログ受信を待ち受けます。

http:// 【起動させるマシンのIPアドレス】:6688

を開いてみます。ログインパスワードを聞かれますので、server.jsonで指定した【ログインユーザ名】、【ログインパスワード】を入力すればログインできて以下のような画面が表示されます。

image.png

ログの送信

それではログを送信しています。
送信は、TCPで以下のようなフォーマットの文字列を送ります。

 +msg|streamName1|sourceName1|this is log message\0

streamName1やsourceName1で区別されるログを表示したり非表示にしたりできます。

TCPで送信すればよいだけなので、様々なプラットフォームから送信することができます。
今回は以下で送信してみます。

・Android
・Arduino
・Node.js
・Javascript(ブラウザ)

出力後はこんな感じ。

image.png

Android

クラスファイル化してみました。

LogIo.java
packagecom.example.logiotest;importandroid.content.Context;importandroid.util.Log;importjava.io.OutputStream;importjava.net.Socket;importno.nordicsemi.android.log.LogSession;importno.nordicsemi.android.log.Logger;importno.nordicsemi.android.log.LogContract.Log.Level;publicclassLogIo{publicStringtag="logio";publicStringdefault_stream_name=null;publicStringdefault_source_name=null;publicStringhost=null;publicintport;Socketsocket=null;OutputStreamouts=null;enumConnectState{Disconnected,Connecting,Connected};ConnectStateisconnected=ConnectState.Disconnected;LogSessionlogSession=null;publicLogIo(Stringhost,intport){this.default_stream_name="stream";this.default_source_name="source";this.host=host;this.port=port;}publicLogIo(Contextcontext,Stringkey,Stringname){logSession=Logger.newSession(context,key,name);}publicvoidlog(Stringmessage){log3(default_stream_name,default_source_name,message);}publicvoidlog2(Stringsource,Stringmessage){log3(default_stream_name,source,message);}synchronizedpublicvoidlog3(Stringstream,Stringsource,Stringmessage){if(host!=null){Log.d(tag,"["+stream+"] ["+source+"] - "+message);finalStringpacket="+msg|"+stream+"|"+source+"|"+message+"\0";newThread(newRunnable(){@Overridepublicvoidrun(){try{byte[]buffer=packet.getBytes("UTF-8");if(isconnected==ConnectState.Connected){outs.write(buffer);outs.flush();}elseif(isconnected==ConnectState.Disconnected){isconnected=ConnectState.Connecting;socket=newSocket(host,port);outs=socket.getOutputStream();isconnected=ConnectState.Connected;outs.write(buffer);outs.flush();}}catch(Exceptionex){try{if(outs!=null){outs.close();outs=null;}socket.close();socket=null;}catch(Exceptionex2){}isconnected=ConnectState.Disconnected;}}}).start();}if(logSession!=null){Stringpacket=message;if(source!=null)packet="["+source+"] "+packet;if(stream!=null)packet="["+stream+"] "+packet;Log.d(tag,packet);Logger.log(logSession,Level.INFO,packet);}}}

※LoggerSessionなるものが混在してわかりにくいですが、nRF Loggerというもので、後述します。ということで、盲目的に、appのbuild.gradleのdependenciesに以下を追記しておきます。
 implementation 'no.nordicsemi.android:log:2.3.0'

あとは、以下のように呼び出せばよいです。

LogIologio=newLogIo(“【起動させるマシンのIPアドレス】”,6689);logio.log("こんばんは1");logio.log2("fromAndroid","こんばんは2");

【起動させるマシンのIPアドレス】のところに、log.ioを立ち上げたマシンのホスト名またはIPアドレスを指定します。

それと、ネットワークを使うので、AndroidManifest.xmlに以下を追記します。
 <uses-permission android:name="android.permission.INTERNET" />

Arduino

Arduinoもログ送信可能です。

#include <WiFiClient.h>
WiFiClientlogio_client;Stringlogio_host;intlogio_port=6689;Stringdefault_stream_name="stream";Stringdefault_source_name="source";voidlogio_setup(Stringhost,intport){logio_host=host;logio_port=port;}voidlogio_log(Stringmessage){logio_log3(default_stream_name,default_source_name,message);}voidlogio_log2(Stringsource,Stringmessage){logio_log3(default_stream_name,source,message);}voidlogio_log3(Stringstream,Stringsource,Stringmessage){Serial.println("["+stream+"] ["+source+"] - "+message);if(!logio_client.connected()){if(!logio_client.connect(logio_host.c_str(),logio_port)){Serial.println("connection failed");return;}}if(logio_client.connected()){Stringpacket="+msg|"+stream+"|"+source+"|"+message;logio_client.write(packet.c_str(),strlen(packet.c_str())+1);logio_client.flush();}}

あとは、setup()でWiFiをAPに接続したのち、以下を呼び出し、

 logio_setup("【起動させるマシンのIPアドレス】", 6689);

loop()などの適当なところで以下を呼び出します。

logio_log("Test Message");logio_log2("fromArduino”, "TestMessage");

Node.js

モジュール化しました。

logio.js
'use strict';constnet=require('net');varConnectState={disconnected:0,connecting:1,connected:2};classLogIo{constructor(host,port){this.host=host;this.port=port;this.default_stream_name='stream';this.default_source_name='source';this.isconnected=ConnectState.disconnected;this.client=newnet.Socket();this.client.on('close',()=>{this.isconnected=ConnectState.disconnected;console.log('[LogIo] disconnected');});}log(message){this.log3(this.default_stream_name,this.default_source_name,message);}log2(source_name,message){this.log3(this.default_stream_name,source_name,message);}log3(stream_name,source_name,message){console.log(`[${stream_name}] [${source_name}] - ${message}`);varpacket=`+msg|${stream_name}|${source_name}|${message}\0`;if(this.isconnected==ConnectState.connected){this.client.write(packet);}elseif(this.isconnected==ConnectState.disconnected){try{this.isconnected=ConnectState.connecting;this.client.connect(this.port,this.host,()=>{this.isconnected=ConnectState.connected;this.client.write(packet);console.log('[LogIo] connected to '+this.host+':'+this.port);});}catch(error){console.error(error);}}else{console.log('[LogIo] connecting');}}}module.exports=LogIo;

あとは、呼び出し側で以下を呼び出せばよいです。

varlogio=newLogIo('【起動させるマシンのIPアドレス】',6689)logio.log('test message');logio.log2('fromNodejs','test message');

javascript

Javascriptには残念ながらTCP通信する機能がないため、TCP通信するNode.jsサーバを立ち上げて、そこからlog.ioサーバに転送してもらいましょう。

サーバ側の実装です。

index.js
'use strict';constHELPER_BASE=process.env.HELPER_BASE||'../../helpers/';constResponse=require(HELPER_BASE+'response');constLOGIO_HOST=process.env.LOGIO_HOST||'【起動させるマシンのIPアドレス】';constLOGIO_PORT=process.env.LOGIO_PORT||6689;varLogIo=require('./logio');varlogio=newLogIo(LOGIO_HOST,LOGIO_PORT)exports.handler=async(event,context,callback)=>{if(event.path=='/logio-post'){varbody=JSON.parse(event.body);if(body.stream&&body.source)logio.log3(body.stream,body.source,body.message);elseif(!body.stream&&body.source)logio.log2(body.source,body.message);elseif(!body.stream&&!body.source)logio.log(body.message);elsethrow"invalid param";returnnewResponse({"status":"OK"});}}

Node.jsのところで作成したlogio.jsを流用しています。
エンドポイント「/logio-post」に、JSONでPOSTすれば、log.ioサーバに転送します。

POSTするJSONのフォーマットは以下の感じです。

{
  "stream": "【任意のStream名】", // オプション
  "source": "【任意のSource名】", // オプション
  "message": "【任意のメッセージ】", // 必須
}

あとは、ブラウザのJavascriptで以下のように呼び出せばよいです。

start.js
varurl="http:// 【起動させるマシンのIPアドレス】:6689/logio-post";varparam={source:"fromHttp",message:"こんにちは"};do_post(url,param);functiondo_post(url,body){constheaders=newHeaders({"Content-Type":"application/json; charset=utf-8"});returnfetch(newURL(url).toString(),{method:'POST',body:JSON.stringify(body),headers:headers}).then((response)=>{if(!response.ok)throw'status is not 200';returnresponse.json();});}

log.ioもうちょっと

触ってみて気づいたけど、

・StreamやSourceを作らないと初回のメッセージが表示されないのが面倒だなあ。。。
・日付を自動的に入れてくれるとありがたいのに。。。
・ブラウザだけで、StreamやSourceが削除できないなあ。。。

(おまけ) Androidでローカルログ保存

Androidでは、log.ioで集約する方法のほかに、Android内にインストールした別のアプリに集約し、そのアプリからモニタリングする方法もあります。
その便利なアプリが「nRF Logger」です。

Google Play:nRF Logger
 https://play.google.com/store/apps/details?id=no.nordicsemi.android.log&hl=ja

もともと、BLEを使ったアプリのLoggerとして作られたようです。
とりあえず、このアプリをAndroidにインストールしておきます。

ログを送信する側のために、ライブラリを用意してくれています。

NordicSemiconductor/nRF-Logger-API
 https://github.com/NordicSemiconductor/nRF-Logger-API

ソースはすでに、LogIo.javaの中に実装しています。
appのbuild.gradleのdependenciesに
implementation 'no.nordicsemi.android:log:2.3.0'
の追加もお忘れずに。

で、使うときには以下の感じです。

LogIologio=newLogIo(this,"testKey","testName");logio.log("こんばんは1");

(ちなみに、ログレベルはINFO固定にしてます)

こんな感じで、nRF Loggerアプリからログをモニタリングできます。

image.png

以上


Viewing all articles
Browse latest Browse all 8832

Trending Articles