Dashingを使って指標を表示させるダッシュボードを作る

業務で見ているパラメータ(KPI的なもの)をダッシュボード的な体で表示させたいなと思ってあれこれ調べると
DashingというGemを見つけてこれを使うとパラメータを常時表示させるものをかなりカジュアルに
作れたのでご紹介。

デモはここで確認できます。Herokuの上で動いてますね。

DashingShopifyが作っていてShopify自体もオフィスでこれを利用して
パラメータをTV等に表示させているとのこと。

インストール

$ gem install dashing

dashing コマンドを使える様にします。

ひな形を作成

作成するダッシュボードのひな形を作成します。

$ dashing new test
create  test
create  test/.gitignore
create  test/Gemfile
create  test/README.md
(snip)
create  test/widgets/text/text.coffee
create  test/widgets/text/text.html
create  test/widgets/text/text.scss

といった具合で指定した名前でディレクリが掘られてそれ以下に必要なファイルが設置されます。

とりあえず起動してみる

作成したディレクトリに移動してまずはbundle installします。

$ cd test
$ bundle install --path vendor/bundles
(snip)

次にダッシュボードを起動します。*1

$ bundle exec dashing start
Thin web server (v1.6.3 codename Protein Powder)
Maximum connections set to 1024
Listening on 0.0.0.0:3030, CTRL+C to stop

で、http://localhost:3030/ でダッシュボードを確認することができます。

停止は $ bundle exec dashing stop で停止できます。

また、上記で起動するとログを標準出力に出す形で起動するので、

$ bundle exec dashing start -d

とすることで、デーモン化することができます。

ダッシュボードを新規に作成する

全く新しくダッシュボードを作るときには dashboard ディレクトリ以下に任意のerbテンプレートを設置することで
新規に作成することができます。

例えば dashboard/test.erb に以下のテンプレートを書いてみます。

<% content_for :title do %>test<% end %>
<div class="gridster">
<ul>
<li data-row="1" data-col="1" data-sizex="2" data-sizey="1">
<div data-id="welcome" data-view="Text" data-title="Text widget" data-text="Dashingテスト" data-moreinfo="テストだよー"></div>
</li>
<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
<div data-id="test-data" data-view="Number" data-title="売上" data-moreinfo="テストです" data-prefix="¥"></div>
</li>
<center><div style="font-size: 12px">Try this: curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "text": "Hey, Look what I can do!" }' \http://<%=request.host%>:<%=request.port%>/widgets/welcome</div></center>
</div>

これを置いてアクセスをすると以下の様なダッシュボードが http://localhost:3030/test で表示できる様になります。

ここで、実際にダッシュボードへ数字を入れるには、

  • jobs ディレクトリ以下に数値をダッシュボードに送信するRubyスクリプトを置く
  • ダッシュボードに設けられるAPIにPOSTリクエストを送る

の2つの方法があるのですが、後者であれば既存のサービスで動いているスクリプト等とも相性が良いのでそちらを試してみることにします。

先のerbテンプレートのサンプルで「売上」というウイジットを表示させるために

<div data-id="test-data" data-view="Number" data-title="売上" data-moreinfo="テストです" data-prefix="¥"></div>

というタグを書いていて、

  • data-view
    • widgets ディレクトリ以下にあるウイジット実装が対応
    • ウイジットとはサンプルにあった数字を表示させたりグラフを表示させたりするものが相当
  • data-id
    • ウイジットをAPIやjobs以下に置かれるスクリプトで更新する際に一意性を識別するためのID

となっています。なので、今回のNumberというウイジットであれば以下の様なcurlコマンドを叩くと該当の
ウイジットの数値を更新することができます。

$ curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "current":100}' http://localhost:3030/widgets/test-data

上のcurlコマンドを叩くと

更新されます。

今回は Number というウイジットに対して更新をかけるため、current というパラメータをcurlコマンドでPOSTしましたが、このパラメータはウイジットによって異なります。

で、その辺りを簡単に知るには直接 widgets ディレクトリ以下にある各ウイジット毎のCoffee scriptを読むと把握できます。*2


といった具合で、Dashingを利用すると、簡単にダッシュボードパネルを作成することができるのでお勧めです。

こういった形で数値をリアルタイムで確認できる様になると、プロジェクトに関わる全員が現状を把握しやすいのと数字が動いているのをみることで「動いている実感」が沸くのでオススメです。

*1:ちなみにアプリケーションサーバとしてはThinが利用されていいます。

*2:現状、ドキュメントにまとめられていないので恐らくそれしか知るすべがなさそう。シンプルなのですぐ読み取れますが。

iCalendarフォーマットの予定をNode.jsでparseする

icalというnpmパッケージがあるので、これを利用すると素朴にiCal形式のデータを読み取ってオブジェクトとして扱うことができます。

var parser = require('ical');
var url = "http://〜/plan.ics";
parser.fromURL(url, {}, function(err, data) {
for(var plan in data) {
console.log(data[plan]);
}
});

とやると、以下の様な形で予定をparseすることができます。

{ type: 'VEVENT',
params: [],
start: { Mon, 13 Oct 2014 08:30:00 GMT tz: undefined },
dtstamp: '20141013T083000Z',
created: '20141013T083000Z',
'last-modified': '20141013T083000Z',
end: { Mon, 13 Oct 2014 09:00:00 GMT tz: undefined },
summary: '◯☓ミーティング',
organizer: 'hideack',
uid: '*****@****',
description: '定例です',
location: '',
sequence: '1',
status: 'CONFIRMED',
transparency: 'OPAQUE' }

便利そう。素朴にできるシリーズでした。

winstonを使ってみる(node.jsでログを取る)

node.jsでログを取るときにwinstonを使ってみたのでそのメモ。

まずはnpmコマンドでインストール。

$ npm install winston --save

で、詳しくはGithub上のREADMEを参照するとかなり詳しくかかれているので、それを参照しながら実際にログを取ってみます。

やりたいこととしては、

  • ファイルと標準出力にログを出したい
  • ファイルに記録する際はJSONではなくタイムスタンプとログレベルとメッセージが並ぶ様にしたい
  • 標準出力に表示する際は色を付け、タイムスタンプも表示し、全てのログを記録したい
  • 標準出力に出すか否かは任意にしたい

という設定を仮定してみます。以下の様な形。

var winston = require('winston');
var getLoggerSettings = function(consoleLog) {
var settings = {
transports: [
new winston.transports.File({ filename: "winston.log", json: false})
],
exceptionHandlers: [
new winston.transports.File({ filename: "winston.log", json: false})
]
};
if (consoleLog) {
settings.transports.push(new winston.transports.Console({colorize: true, timestamp: true, level: 'silly'}));
settings.exceptionHandlers.push(new winston.transports.Console({colorize: true, timestamp: true, level: 'silly'}));
}
return settings;
};
var logger = new (winston.Logger)(getLoggerSettings(true));
logger.silly('silly');
logger.debug('debug');
logger.verbose('verbose');
logger.info('info');
logger.warn('warn');
logger.error('error');

こうすることによって、ターミナル上には、

といった形でログが表示されます。また、ログファイル上にも、

2014-10-12T07:19:37.276Z - info: info
2014-10-12T07:19:37.276Z - warn: warn
2014-10-12T07:19:37.276Z - error: error

な形で記録されます。ファイル側にinfo以上のログしか記録されていないのは、new winston.transports.File({ filename: "winston.log", json: false}) としていてログレベルを明記していないので、標準のinfo以上のログが記録されています。

ここでは、標準出力とファイルログだけを対象にしましたが、winston-riakや、winston-mongodbという実装もあるので、ログをデータベースに記録することも容易そう*1

node.jsであれこれ書いてログを取りたいときはしばらく使ってみよう。

*1:見た感じですが...

node.jsで素朴にMySQLへ接続する

素朴 = ORMなどを利用せずに素朴なクエリを1行程度発行したい場合にどうしたんだっけ。と少し調べたのでメモエントリ。

npmのmysqlを利用する。

$ npm install mysql --save

あとは、接続→クエリ発行→切断の順で書いていく。

var db = require('mysql');
var settings = {
"host": "localhost",
"database": "sample_database",
"user": "sample_user",
"password": "sample_password"
};
var connection = db.createConnection(settings);
connection.query("select count(*) from users;", function(err, result) {
if (err) {
// 接続失敗
return;
}
console.log(result);  // [ { 'count(*)': 8 } ]
connection.end(function() {
// 接続終了
});
});

結果はJSONで得られる。素朴だ。

植田正治のつくりかた

少し前に買って一度全部眺めていたのだけど、改めて昨日から開きは閉じを繰り返してずっと眺めてる。

「三つ子の魂」といい「雀百まで」という。
いったんはまりこんだら、抜けることは容易ではないらしく、
今もって五十年前と同じような写真を撮っていることを、口にするのも恥ずかしい。
方向はともかく、写真に対する精神的燃焼度だけは、昔とちっとも変わっていないのだ、
といって自らを納得させるより仕方がない。
だって今は、今でも熱心なアマチュアだから。

gulpを利用してmochaで書かれたテストを実行する

定例の2周り遅れエントリ。Castoや、STORYBOARDSではtask runnerにGruntを利用していたのですが、glupも触ってみようということで使ってみました。

最近はnode.jsでちょっとしたツールを書いていたりすることが多く、そのテストにmochaを使って書いていたりするので試しにその実行のタスクをglupで書いてみることにしました。

まずは、glupのインストール。globalで入れてコマンドラインから叩ける様にします。

$ npm install -g gulp
$ gulp -v
[19:28:32] CLI version 3.8.8
[19:28:32] Local version undefined

実際にgulpを使いたいプロジェクトに入って、プロジェクト直下にもインストールします。

$ cd project
$ npm install gulp --save-dev
$ gulp -v
[19:30:00] CLI version 3.8.8
[19:30:00] Local version 3.8.8

更にmochaのテストをgulpで実行させるために、gulp-mocha等々入れます。

$ npm install gulp-mocha --save-dev
$ npm install gulp-util --save-dev

これで準備ができたので、プロジェクト直下に gulpfile.js を作成します。今回は、

  • mochaのテストを実行するタスク
  • libディレクトリまたはtestディレクトリ以下を監視して、ファイルに変更があればそのmochaのテストを実行するタスクを呼び出すというタスク

の2つを書いてみます。ほぼサンプルそのままですが...。

var gulp = require('gulp');
var mocha = require('gulp-mocha');
var gutil = require('gulp-util');
gulp.task('mocha', function() {
return gulp.src(['test/*.js'], { read: false })
.pipe(mocha({ reporter: 'list'}))
.on('error', gutil.log);
});
gulp.task('watch-mocha', function() {
gulp.watch(['lib/**', 'test/**'], ['mocha']);
});

こうすることで、mochawatch-mocha というタスクが作成されました。まずシンプルにテストを実行するには、プロジェクトルートで

$ gulp mocha
[19:35:25] Using gulpfile ~/project/gulpfile.js
[19:35:25] Starting 'mocha'...
․ test A : 16ms
(snip)
5 passing (29ms)
[19:35:25] Finished 'mocha' after 397 ms

とgulpを利用してmochaのテストを実行できます。もうひとつ作成している watch-mocha というタスクを実行すると

[19:37:58] Using gulpfile ~/project/gulpfile.js
[19:37:58] Starting 'watch-mocha'...
[19:37:58] Finished 'watch-mocha' after 9.99 ms

と表示され待機状態になるので、gulpfile.js 上で指定したlib及びtestディレクトリ以下のファイルを編集して保存すると自動的に変更が検出されたタイミングでmochaのテストが実行されます。

[19:37:58] Using gulpfile ~/project/gulpfile.js
[19:37:58] Starting 'watch-mocha'...
[19:37:58] Finished 'watch-mocha' after 9.99 ms
[19:39:32] Starting 'mocha'...
․ test A : 16ms
(snip)

もっとも、この程度のタスクの大きさだとあんまりメリット感じられないのですが、gulpfile.js

gulp.src(['test/*.js'], { read: false }).pipe(mocha({ reporter: 'list'})).on('error', gutil.log);

のくだりの手続き的に書いていくやり方はわかりやすい気もしたり。もう少しあれこれ触っていこうかと思います。