はじめに
じょう「KPI測定しよう!」
おいら「いいですね!GrowthForecast入れました!」
じょう「打ち合わせで使うからExcelでデイリーの増減データちょうだい!」
おいら「りょ、りょうかいです!(rrdfetchをコマンドラインで叩いてデータをCSVに整形)」
じょう「デイリーの増減をグラフで見れてなおかつCSVでデータをダウンロード出来るページ無いの?」
おいら「りょ・・・ちょ、ちょっと待ってください!」
やったこと
上記の依頼を受けた際まず始めに、GrowthForecastで使われているRRDtoolの良さ気なフロントエンドを探しましたが、要件に見合うものが見つかりませんでした。(あったら知りたいです・・・出来るだけオレオレツールは作りたくないのです・・・)
RRDtoolには対応していないもののHRForecastが要件を満たしそうでした。そこでGrowthForecastのデータをHRForecastにインポートするスクリプトを書きました。それが以下になります。
やりかた
GrowthForecastのxportを拡張する
GrowthForecastにはxportというデータをjsonでエクスポート出来る機能が付いています。これを拡張しstepとcf (統合関数) (これらの単語について詳しく知りたい方はRRDtoolのドキュメント参照) を指定できるようにします。
Diff: xportにてstepとcf (統合巻数) を指定できるように修正→2013/12/08: 本家にmergeされました!
移行スクリプトを動作させる
以下の移行スクリプトをHR_URL (HRForecastのURL) とGF_URL (GrowthFOrecastのURL) 、またAUTH (双方にかかっているBasic認証のユーザ名とパスワード)を埋めて実行すれば、GrowthForecastのデータがデイリーに変換されHRForecastにそのままのURL構造でインポートされます。またそれだけではなく"-substract"という接尾語が付いた前日との増減を記録したグラフも作成されます。
ONLY_YESTERDATをtrueにすると昨日のデータだけをインポートするので速くなります。一番最初にfalseのまま全データを移行した後は、その後trueにして一日おきにCronで回せば最新のデータに追従出来ます。
# -*- 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を触ってみようと思っているのですが、何かよさげなソリューションあったら教えて下さい・・・。