GrowthForecastのデータをHRForecastにインポートする

## はじめに
じょう「KPI測定しよう！」
おいら「いいですね！GrowthForecast入れました！」
じょう「打ち合わせで使うからExcelでデイリーの増減データちょうだい！」
おいら「りょ、りょうかいです！（rrdfetchをコマンドラインで叩いてデータをCSVに整形）」
じょう「デイリーの増減をグラフで見れてなおかつCSVでデータをダウンロード出来るページ無いの？」
おいら「りょ・・・ちょ、ちょっと待ってください！」

## やったこと
上記の依頼を受けた際まず始めに、GrowthForecastで使われているRRDtoolの良さ気なフロントエンドを探しましたが、要件に見合うものが見つかりませんでした。（あったら知りたいです・・・出来るだけオレオレツールは作りたくないのです・・・）
RRDtoolには対応していないもののHRForecastが要件を満たしそうでした。そこでGrowthForecastのデータをHRForecastにインポートするスクリプトを書きました。それが以下になります。

## やりかた
### GrowthForecastのxportを拡張する
GrowthForecastにはxportというデータをjsonでエクスポート出来る機能が付いています。これを拡張しstepとcf (統合関数) (これらの単語について詳しく知りたい方は[RRDtoolのドキュメント](http://agj.at/~fors/sysworks/data/rrdtool/rrdgraph.txt)参照) を指定できるようにします。
Diff: [xportにてstepとcf (統合巻数) を指定できるように修正](https://github.com/anoworl/GrowthForecast/commit/b414e22678bacc5abfaeb84c92ce28514427a7d6)→2013/12/08:  [本家にmergeされました！](https://github.com/kazeburo/GrowthForecast/pull/44)

### 移行スクリプトを動作させる
以下の移行スクリプトをHR_URL (HRForecastのURL) とGF_URL (GrowthFOrecastのURL) 、またAUTH (双方にかかっているBasic認証のユーザ名とパスワード)を埋めて実行すれば、GrowthForecastのデータがデイリーに変換されHRForecastにそのままのURL構造でインポートされます。またそれだけではなく"-substract"という接尾語が付いた前日との増減を記録したグラフも作成されます。
ONLY_YESTERDATをtrueにすると昨日のデータだけをインポートするので速くなります。一番最初にfalseのまま全データを移行した後は、その後trueにして一日おきにCronで回せば最新のデータに追従出来ます。

```rb
# -*- encoding: utf-8 -*-
require 'open-uri'
require 'pp'
require 'multi_json'
require 'oj'
require 'net/http'
require 'uri'
require 'active_support'
require 'active_support/all'

ONLY_YESTERDAT = false

HR_URL = 'http://hr_url'
GF_URL = 'http://gf_url'
AUTH = ['hogehoge', 'hagehage']

Time.zone = 'UTC'
ENV['TZ'] = 'UTC'

def gf_read(path)
  json = open(GF_URL + path, http_basic_authentication: AUTH).read
  MultiJson.load(json)
end

def hr_post(path, data={})
  url = URI(HR_URL)
  http = Net::HTTP.new(url.host, url.port)
  request = Net::HTTP::Post.new(url.path + path)
  request.basic_auth(*AUTH)
  request.set_form_data(data)
  response = http.request(request)
end

graphs = gf_read('/json/list/graph')
graphs.each do |graph|
  graph_path = [graph['service_name'], graph['section_name'], graph['graph_name']].join('/')

  graph_json = gf_read("/json/graph/#{graph_path}")
  created_at = Time.parse(graph_json['created_at'])

  from = created_at.tomorrow.beginning_of_day
  to = Time.now.utc.yesterday.beginning_of_day
  from = to.yesterday.beginning_of_day if ONLY_YESTERDAT
  options = {
    t: 'c',
    to: to.to_date.to_s(:db),
    from: from.to_date.to_s(:db),
    step: 86400,
    cf: 'MAX'
  }
  xport = gf_read("/xport/#{graph_path}?#{URI.encode_www_form(options)}")
  start_xport = Time.at(xport['start_timestamp']).to_date
  end_xport = Time.at(xport['end_timestamp']).to_date
  
  dailies = (start_xport..end_xport).zip(xport['rows'].flatten)

  dailies.each do |date, num|
    options = { number: num.to_i , datetime: date.to_s(:db) }
    hr_post("/api/#{graph_path}", options)
  end

  dailies.each_with_index do |value, i|
    date, num = *value
    next if i < 1
    options = { number: num.to_i - dailies[i-1][1].to_i, datetime: date.to_s(:db) }
    hr_post("/api/#{graph_path}-subtract", options)
  end
end
```

## おわりに
こんな家内制手工業みたいなことやりたくないです！！！なんか全てが統合されたよさげな環境ほしいです・・・。KibanaとかSplunkを触ってみようと思っているのですが、何かよさげなソリューションあったら教えて下さい・・・。