IDCF テックブログ

IDCF テックブログ

クラウド・データセンターを提供するIDCフロンティアの公式テックブログ

YBIのクエリ結果をSlackへ通知する

※2016年10月1日より、サービス名称が「Yahoo!ビッグデータインサイト」から「トレジャーデータサービス by IDCF」に変更となっております。

ビッグデータ・ソリューションアーキテクトの高階(takashina)です。

みなさんの社内や組織内のコミュニケーションには、どんなツールを使ってますか? 電話、メール、ケータイメッセージはもちろんのこと、LINE、FacebookのMessenger、Skype、Facetime、Slack、chatwork、HipChatなどといった様々なジャンルのツールを使っているかと思います。プッシュ通知されるツールだと、タイムラインを追っていくだけで必要な情報や通知内容が読めるので、手間が少なくて便利ですよね。

ログのバッチ処理をしている場合、自動的にその集計結果を送ってきてもらえたら、それも手間が少なくて便利そう。 そこで今日は、Yahoo!ビッグデータインサイト(以下「YBI」)で実行したクエリの結果をSlackへ通知する手順についてご紹介します。
f:id:maktakas:20160530124256p:plain

前提条件

ここから先、次の前提で綴っていきます。

  • CentOSサーバーの基本的な操作ができる
  • 外部のBotから投稿してもOKなSlackのアカウントを持っている
  • YBIのアカウントを持ち、YBIの基本機能を理解している

用意するモノ

手順

1. IDCFクラウドで仮想サーバー作成、ネットワークの設定

まずはIDCFクラウドでSlackへの投稿を操作するサーバーを作ります。 他のサーバーを使う方は、適宜同様の設定をしてください。

IDCFクラウドで仮想サーバーを作成する手順についてはIDCFクラウド ヘルプサイトをご覧ください。 なお、今回はおすすめTemplateのCentOS 7.1 64-bitで作成しました。
ネットワークの設定は下記のように行います。 SSH(22/TCP)とSinatra(4567/TCP)でアクセス可能としてください。
※Sinatraが何者か、は後述します。

まずIPアドレスの取得
f:id:maktakas:20160523204354p:plain

ファイアウォールの設定
f:id:maktakas:20160523204433p:plain

ポートフォワードの設定
f:id:maktakas:20160523204503p:plain

2. Slackでの準備

続いてSlack側で準備をしていきます。通知を送りたいSlackのteamにアクセスしておきましょう。

外部のツール等からSlackへ投稿できる機能としてIncoming Webhooksがあります。今回はこの機能を使ってYBIからSlackへのクエリ結果通知を実現していきます。
なお、既にIncoming Webhooksの設定がされているSlackのChannelであれば、ここの手順は不要です。

2-1. Slack設定ページ

歯車マークのChannel Settingsから「Add an app or integration」を選択します。
f:id:maktakas:20160520143305p:plain

すると、Slackの細かな設定ができるページへ飛びます。 ここの検索窓で「incoming webhooks」を入力すると候補に「Incoming Webhooks」が現れるのでクリックします。

2-2. Incoming Webhooks設定ページ

f:id:maktakas:20160520143621p:plain

team名の右側にある「configure」、「Add Configuration」とクリックします。
f:id:maktakas:20160520144728p:plain f:id:maktakas:20160520144733p:plain

Post to Channelで、Incoming Webhooksで投稿する先のchannelを選択して、 「Add Incoming WebHookss integration」ボタンをクリックします。
f:id:maktakas:20160520145011p:plain

2-3. 投稿用URLの発行

https://hooks.slack.comで始まるWebhook URLが発行されます。 外部ツールからこのURLにデータを投げるとSlackのChannel投稿されるわけです。
f:id:maktakas:20160520145956p:plain

このページでは、Webhookを使った投稿者名、アイコン等を変更することができますが、とりあえず今はそのまま次に進みます。 「Save Settings」をクリックして、Slack側での準備は完了です。

※注意!
このWebhook URLは関係者以外に知られないようにしてください。バレてしまうと誰でもChannelへ投稿できるようになってしまいます!

2-4. Webhook URLのテスト

Webhook URLを使った投稿ができるかどうか、CentOSサーバーにログインして、試してみましょう。

$ curl -X POST --data-urlencode 'payload={"text": "Test Message"}' https://hooks.slack.com/services/xxxxxxxxx/xxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx

うまく行けば、SlackのChannelにこんな投稿がされているはずです。
f:id:maktakas:20160523155616p:plain

3. td2slackの準備

続いて、CentOSサーバーにてtd2slackをインストールします。 YBIはTreasure Dataのサービスをベースにしています。YBIからSlackへ通知する仕組みについては、Treasure Dataのクエリ結果をSlackに流せる「td2slack」があるので、これを使います。

td2slackは、RubyによるWebアプリケーションを簡単に実現するためのソフトウェアであるSinatraで作られています。 今回ご紹介しているtd2slackは、YBIから送られてきたHTTP PUTをSinatraでフッキングしてSlackへ送る、という動きをしています。
Sinatraについて詳しく知りたい方はこちらをどうぞ

3-1. yumインストール

td2slackをインストールするのにbundlerを使っていきます。
その前に、インストールに使うruby-devel、gcc、rubygem-bundlerをyumでインストールします。RubyGemsもアップデートしておきましょう。

$ sudo yum install ruby-devel gcc rubygem-bundler
(中略)
New leaves:
  gcc.x86_64
  ruby-devel.x86_64
  rubygem-bundler.noarch

$ sudo gem update --system
Updating rubygems-update
Fetching: rubygems-update-2.6.4.gem (100%)
Successfully installed rubygems-update-2.6.4
Installing RubyGems 2.6.4
RubyGems 2.6.4 installed
(中略)
RubyGems system software updated

3-2. git clone

適当なディレクトリ配下にgit cloneします。

$ git clone https://github.com/treasure-data/td2slack.git
Cloning into 'td2slack'...
remote: Counting objects: 49, done.
remote: Total 49 (delta 0), reused 0 (delta 0), pack-reused 49
Unpacking objects: 100% (49/49), done.

3-3. 環境変数設定

下記の環境変数を設定します。

$ export SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxxxxxxxx/xxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx
$ export RACK_ENV=production
  • Sinatraアプリケーション(app.rb)からSLACKへ投稿する際に、SLACK_WEBHOOK_URLの環境変数で指定したURLへ送っています。
  • RACK_ENVは、Sinatraアプリケーションを外部のサーバーから利用できるようにするために設定しています。

3-4. td2slackインストール

td2slackで使われるjsonのgemがGemfileに含まれていなかったため、追記したうえでbundlerでインストールします。

$ cd td2slack
$ vi Gemfile
source 'https://rubygems.org'
gem 'sinatra'
gem 'slack-notifier'
gem 'json'     (← 一行追加)

$ bundle install --path vendor/bundle
Fetching gem metadata from https://rubygems.org/.............
Resolving dependencies...
Installing json 1.8.3
Installing rack 1.6.0
Installing rack-protection 1.5.3
Installing tilt 2.0.1
Installing sinatra 1.4.6
Installing slack-notifier 1.1.0
Using bundler 1.7.8
Your bundle is complete!
It was installed into ./vendor/bundle

これで実行環境が整いました。

4. 実行テスト

とりあえず実行してみましょう。

$ bundle exec ruby app.rb
[2016-05-23 20:21:05] INFO  WEBrick 1.3.1
[2016-05-23 20:21:05] INFO  ruby 2.0.0 (2014-11-13) [x86_64-linux]
== Sinatra (v1.4.7) has taken the stage on 4567 for production with backup from WEBrick
[2016-05-23 20:21:05] INFO  WEBrick::HTTPServer#start: pid=11116 port=4567

この状態でYBIのWeb UIからクエリを実行してみます。 適当なDatabaseを選んで、テスト用に「SELECT ‘aaa’ AS foo」などという単純なクエリを書きます。 このクエリの結果は「foo」カラムに「aaa」という文字列が1行だけ現れます。
f:id:maktakas:20160523211531p:plain

これをResult Exportの機能で「HTTP PUT」へエクスポートします。記入個所はHost、Port、Pathの3箇所です。
f:id:maktakas:20160523211541p:plain

ここまで設定したら、Web UI右上にある「Run」!

すると..Slackにこんな投稿がされるはずです。
f:id:maktakas:20160523212329p:plain

CentOSサーバーにはこんなログが出てます。

WARN: tilt autoloading 'tilt/erb' in a non thread-safe way; explicit require 'tilt/erb' suggested.
xxx.xxx.xx.xx - - [23/May/2016:20:23:54 +0900] "PUT /example HTTP/1.1" 200 - 0.4638
xxx-xxx-xx-xx.jp-east.compute.idcfcloud.com - - [23/May/2016:20:23:54 JST] "PUT /example HTTP/1.1" 200 164
- -> /example
[2016-05-23 20:23:54] ERROR Errno::ECONNRESET: Connection reset by peer
        /usr/share/ruby/webrick/httpserver.rb:80:in `eof?'
        /usr/share/ruby/webrick/httpserver.rb:80:in `run'
        /usr/share/ruby/webrick/server.rb:295:in `block in start_thread'

確認できたらSinatraは止めておきましょう。Ctrl-Cです。

5. td2slackをデーモンで動かす

Sinatraアプリであるtd2slackは、rackupコマンドでデーモン起動可能です。下記では4567/TCPポートで起動しています。netstatで起動状況を確認してみましょう。

$ bundle exec rackup -D config.ru -p 4567

$ netstat -tnap
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:4567            0.0.0.0:*               LISTEN      18591/ruby      

止める時はkillしてください。

$ kill -9 ${pid}

6. 出力結果のフォーマット作成

Result Exportを設定する際に、 Path: /example と設定しました。 これは、CentOSサーバーのtd2slack/viewsディレクトリ配下にあるerbファイルに沿って出力されています。 example.erbファイルを見てみると..

$ more views/example.erb
This is <%=@td['foo'][0]%>

クエリの結果は「foo」カラムに「aaa」という文字列が1行だけ現れるもので、Slackへの投稿された内容は以下の通りでした。
f:id:maktakas:20160523212329p:plain

<%=@td['foo'][0]%>の部分にクエリ結果の「aaa」が代入されていたのですね。 このようにviewsディレクトリ配下のerbファイルを設定すると、いろいろと出力結果をカスタマイズできます。

ところで、YBIにはsample_datasetsというデータベース内に、過去のNasdaq株価データが入ったテーブルがサンプルデータとして格納されています。このデータセットに対して、次のようなクエリを実行して、結果をSlackへ流してみましょう。Sinatraアプリを起動しておくのをお忘れなく。

$ bundle exec rackup -D config.ru -p 4567

設定ファイル:トップ5をフォーマットして表示しています。

$ vi views/rate_of_increase.erb
Nasdaq株価上昇率トップ5
日付 | 銘柄 | 上昇率
<% 5.times do |i| %>
  <%= i + 1 %>位 <%= @td['date'][i] %> | <%= @td['symbol'][i] %> | <%= @td['rate_of_increase'][i] %>
<% end %>

クエリ:日毎・銘柄毎の株価上昇率を計算して、上昇率トップ5を取得しています。

SELECT TD_TIME_FORMAT(time, 'yyyy-MM-dd') AS date, symbol, (close - open) / open AS rate_of_increase
FROM nasdaq
WHERE TD_TIME_RANGE(time, '2012-01-01', '2013-01-01')
  AND (close - open) > 0
  AND open > 0
ORDER BY rate_of_increase DESC
LIMIT 5

Result Exportの設定は次のようにします。

Export to: HTTP PUT
Host: td2slackが動くホスト名かIPアドレス
Port: 4567
Username: 空白
Passowrd: 空白
Path: /rate_of_increase

クエリをRunしてみましょう。Slackへ出力される結果は次のようになるはずです。
f:id:maktakas:20160524212506p:plain

今回の環境

$ cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
$ /usr/bin/ruby -v
ruby 2.0.0p598 (2014-11-13) [x86_64-linux]
$ /usr/bin/gem -v
2.6.4
$ /usr/bin/bundler -v
Bundler version 1.7.8

おわりに

いかがでしたか。
クエリ結果を定期的にSlackへ出力してもらえると、監視アラートの代わりに使うこともできますね。

それでは、ごきげんよう!

Copyright © IDC Frontier Inc.