2016/12/09

Managed Database API としての Insights

これは、NewRelic Advent Calendar 2016 の9日目の記事となります。他の日もよろしくお願いします。

NewRelic Insights の二つの顔

NewRelic Insights には二つの側面があります。

一つは、APMなど他のサービスと同じく、完結したWebサービスの顔です。APMやInfrastructureなどのサービスを使用していると、そこで収集したデータをブラウザからの簡単な操作で監視用のダッシュボードを作ることができます。

もう一つは、APIから利用するNOSQLタイプのDatabaseサービスとしての顔です。

データ収集用のAPIとして、カスタムイベントAPI があり、ほぼ任意のJSON形式のデータを入力することができます。

検索用のAPIでは、NRQLというSQLに似た検索用の言語を使って問い合わせることができます。

これを Ruby などで作成したスクリプトからアクセスすることで、データベースサーバとして使うことができます。この場合は、単体でそのまま使うのではなく、スクリプトを書いて他のサービスと組み合わせることで、多様な用途に使用できます。

ここでは、NRQLの検索を下記のサービスと組み合わせて使用した一つの事例を紹介したいと思います。

完成形

このスクリプトは、Insights から収集したデータを円グラフを添付して、下記のようにSlackにPostします。

Insights with Charturl

内容は部門別の売上データですが、元データは海外との取引を含むため、現地通貨になっています。これを最新のレートで円建てに変換した上で集計しています。

これを実現するまでに、次のような課題を解決しました。

  • 各通貨の最新レートをAPIで入手
  • JOINができないInsightsで外部データを含めて集計を行う
  • データからチャートのイメージファイルを作成する
  • SlackにイメージファイルをPostする

これを順番に説明していきたいと思います。

各通貨の最新レートをAPIで入手

これは、Google の通貨コンバータを使いました。HTMLベースのサービスなので、簡単なスクレイピングを行っています。

def get_rate(currency)
 doc = Nokogiri::HTML(open("https://www.google.com/finance/converter?a=1&from=#{currency}&to=JPY"))
 doc.css('.bld').first.text.split.first.to_f
end

def get_rate_table
 ret = { 'JPY' => 1.0 }
 %w{KRW USD TWD}.each do |c|
   ret[c] = get_rate(c)
 end
 ret
end

rates = get_rate_table # {"JPY"=>1.0, "KRW"=>0.098, "USD"=>114.416, "TWD"=>3.5936}

Insightsで通貨変換しながら集計する

NRQLは基本的な構文はSQLに似ていて、使い始めるのは容易ですが、複数テーブルのjoinができないという制約があります。

「現地通貨建ての金額を円建てに統一して集計する」という処理は、普通のRDBなら、通貨レートの変換テーブルを用意して、それをjoinして、次のようなSQLになると思います。

select section, sum(sales.amount * rates.rate) from sales, rates where sales.currency = rates.currency group by section;

InsightsのようなNOSQLでは、このような場合は、非正規化して、salesテーブルに通貨レートを含めるのが一般的な解決だと思います。しかし、円建てへの変換をsalesデータの発生時のレートで行うなら、それも可能ですが、今回は、検索時の最新レートを使いたいという要求なので、この方法は使えません。

このような場合、少し泥臭い方法ですが、filterという機能を使うことで似たような集計を行うことができます。

SELECT filter(sum(total*1.0), where currency = 'JPY')
       + filter(sum(total*0.098), where currency = 'KRW')
       + filter(sum(total*114.416), where currency = 'USD')
       + filter(sum(total*3.5936), where currency = 'TWD') 
  FROM Sales 
  WHERE status = 'completed' 
  FACET section 
  SINCE 1 day ago

これだと、各通貨ごとのレートをNRQL内のリテラルとして含める必要があります。この部分は、先ほど入手したデータから文字列として生成するようにします。

def generate_filter_expression(c, r)
 "filter(sum(total*#{r}), where currency = '#{c}')"
end

filter_expressions = rates.map do |c, r|
 generate_filter_expression(c, r)
end.join('+')

これを使って集計用のNRQLを作成し、Insightsに問い合わせします。

def insights_query(nrql)
 nrql_encoded = nrql.gsub(' ') { '%20' }
   .gsub('(') { '%28' }
   .gsub(')') { '%29' }
   .gsub('+') { '%2B' }
 result = `curl -s -H "Accept: application/json" -H "X-Query-Key: #{NEWRELIC_QUERY_KEY}" "https://insights-api.newrelic.com/v1/accounts/#{NEWRELIC_ACCOUNT_ID}/query?nrql=#{nrql_encoded}"`
 JSON.parse(result)
end
ret = insights_query("SELECT #{filter_expressions} FROM Sales FACET payment_method SINCE 1 day ago")

チャートを生成する

これで、チャート作成用のデータはできましたが、Slackにポストするためには、チャートを画像ファイルとして作成する必要があります。

ChartURLはこれを実行してくれるサービスです。基本は有償のサービスですが、月200件の変換まではフリーアカウントで行うことができます。

使い方としては、サインアップしたら、自分のアカウント内にプロジェクトを作り、そのプロジェクトの中に「テンプレート」というものを作成します。「テンプレート」にはグラフの種類や描画方法をJSON形式で設定します。設定画面内にサンプルデータを登録して、プレビューすることもできます。

これができれば、テンプレートのIDとデータだけをAPIに投げることで、グラフが生成され、shorturl形式が戻ってきます。ほぼサンプルコードのままですが、これを行うところは下記のようになります。

def generate_chart(columns)
 url = "https://charturl.com/short-urls.json?api_key=#{CHARTURL_API_KEY}"
 data = {
   template: "donut-chart1",
   options: {
     data: {
       columns: columns,
       type: "donut"
     },
   }
  }

 options = {
   headers: {'Content-Type' => 'application/json'},
   body: data.to_json
 }

 resp = Typhoeus::Request.post(url, options)
 JSON.parse(resp.response_body)['short_url']
end

# Insights の形式から ChartUrl の形式に変換
columns = ret['facets'].map do |r|
 name = r['name']
 value = r['results'].first['result']
 [name, value]
end

image_url = generate_chart(columns)

SlackにイメージファイルをPostする

最後に、このチャートのURLを attachment として、 SlackにPost します。

def post_to_slack(msg, image_url)
 if SLACK_URL
   json = {
     channel: "#newrelic",
     username: "payments",
     text: msg.join("\n"),
     attachments: [
       { "image_url": image_url}
     ]
   }.to_json

   cmd = "curl -s -S -X POST --data-urlencode 'payload=#{json}' #{SLACK_URL}"
   system cmd
 else
   puts msg,image_url
 end
end

post_to_slack(msg, image_url)


以上の処理を全部つなげて、定数の設定を冒頭に追加すれば、動作するスクリプトになります。


NEWRELIC_QUERY_KEY=ENV['NEWRELIC_QUERY_KEY']
NEWRELIC_ACCOUNT_ID=ENV['NEWRELIC_ACCOUNT_ID']
CHARTURL_API_KEY=ENV['CHARTURL_API_KEY']
SLACK_URL = ENV['SLACK_URL']

終わりに

完結したサービスやアプリケーションをそのまま使うか、部品を集めて自分で組み合わせて使うか、という選択は、古くからある難問です。

最初からできているものを使えば、作業量は少なくてすみますが、一見良さそうに見えても、実際に具体的な用途で使おうとすると、思わぬ制約があって使えないことがわかるということも少なくありません。今回の例では、「最新の通貨レートで変換する」という要件がそれにあたります。サービスとしての Insightsでは要件を満たせませんでした。

今は、部品が単なるライブラリやコンポーネントでなく、Web上のサービスとして提供されていますので、部品の組み合わせが最適解になる範囲が増えていると思います。

そのような観点で Insights を見ると、「NRQLを投げるとJSONが返ってくる」というモデルはシンプルで応用範囲が広いと思います。APIだけだと、NRQLを組み立ててテストするところが大変ですが、ここはブラウザ上で試行錯誤できるし、結果の形式も同じ画面で確認できます。

NewRelicを使っている場合は、とりあえず、アプリケーションの重要なデータを Insightsの「カスタムイベント」として登録しておくと、このように色々なところで活用できると思います。

Qiita で New Relic Advent Calendar 2017 いろいろ書きました。特に、New Relic APM の入門的な連載を書きましたので、是非、ご覧ください。

New Relic 公式の日本 New Relic ユーザー会を立ち上げました。ワークショップの情報など日本のお客様向けに情報を発信していきますので、是非、参加ください。

過去記事

2018/09/13

翻訳: FutureStack18: New Relic 開発者向けプログラム-オープン化、シンプル化、活発化への道

今年も始まりました。New Relic の年次カンファレンス FutureStack 18。
この記事では、Elixir 用の New Relic APM エージェントの発表とデベロッパープログラムの発表がされています。

続きを読む

2018/08/27

翻訳: New Relic APM 新機能: 分散トレーシング

New Relic APM にDistributed Tracing (分散トレーシング)機能が追加されました。メニュー単位で機能が追加されたのはだいぶなかったのではないかと思います。マイクロサービスにおけるサービスをまたがったデータの流れを可視化できる機能のようです。是非、チェックしてみてください。

続きを読む

2018/05/18

SREcon18 と Rails デベロッパー向けアンケート結果の紹介

SRECon America カンファレンスにおけるアンケートの記事と Rails デベロッパーに対するアンケートの記事という2つの異なったレイヤーのアンケートに関する記事を見つけたので、ざっくり紹介します。違った視点での傾向が見れてなかなか面白いです。

続きを読む

2018/05/11

AWS Summit Tokyo を中心に直近の New Relic 関連イベントのご紹介

5/30 から始まる AWS summit Tokyo に参加するということで、海外から New Relic スタッフが来日し、イベント等を行います。是非、この機会に New Relic に興味のある人は参加してみてはいかがでしょうか。(基本、日本人スタッフいるので、日本語でも大丈夫なはず)

続きを読む

2018/03/17

翻訳: New Relic Browser JavaScript Error Analytics ベータ版 – エラーの早期発見、修正に役立つ

New Relic Browser の JS エラー機能が新しくなるようです (現在ベータ版)。APM で採用されているエラープロファイルが JS エラーにも対応したようです。これによって、エラーが起きている傾向が分析できるようになり、今後の JS のエラーが起きる前に対策が取りやすくなります。既存の PRO ユーザーはベータ版が使えるようなので、是非、使ってみてください。

続きを読む

 もっと見る