#はじめに
Heroku drainからhttp経由でログを取得し、TDへ送るアプリをsinatraで作っていた時ハマった時のことを記録として残す。
Heroku drainからログをpostで受け取る形式のアプリを作った。(Sinatraは初めて)
#最初はクラシック形式で作成。
require 'sinatra'
require 'sinatra/reloader' if development?
require 'td'
require 'date'
TreasureData::Logger.open('DB名',
:apikey=>ENV['TD_API_KEY'],
:auto_create_table=>true)
post '/' do
・・・ requestの内容をパースする処理 ・・・
TD.event.post('テーブル名',{送るデータ})
end
ここで一つ注意点。
・TreasureData::Logger.openはpostのなかに記述してはいけない
理由は簡単。 postされるたびTreasureData::Logger.openが実行されるため
最終的にはThread errorでログが受け取れない状態に陥る。
この記述にすると大体5分間隔でbufferに蓄積したデータをTDへpostする。
#モジュールに書き直し
後々のメンテナンス性や拡張性、可読性を考えモジュール化させる。
require 'sinatra/base'
require 'sinatra/reloader'
require 'td'
require 'date'
require 'ltsv'
require "concurrent/map"
require './object_ext' #.present?が使いたかったために拡張
class MyApp < Sinatra::Base
configure :development do
register Sinatra::Reloader
end
before do
#TD初期設定
TreasureData::Logger.open('DB名',
:apikey=>ENV['TD_API_KEY'],
:auto_create_table=>true)
class Lib
include ObjectExtension
def log_parser(log)
・・・ 受け取ったログをパースしてhashで返す ・・・
end
end
paser = Lib.new
end
post '/' do
・・・ logを受け取りlog_parser(log)でパースする ・・・
TD.event.post('テーブル名',{送るデータ})
end
end
・ここでのミス
beforeを使ったこと
実際のところ前処理をする必要は今回のアプリには無かったが、
beforeで事前に色々と設定や処理などをするものと勘違いしていたためまたもやThread errorの連発。
何が起きていたかと言うと、herokuからドレインされたログを受ける度にbeforeが呼ばれTreasureData::Logger.openを
呼び出すと処理を行っていた。そのため、今度はbufferに溜まるのを待たずに即TDにpostする現象に見舞われblockされてしまう状況に陥った。
require 'sinatra/base'
require 'sinatra/reloader'
require 'td'
require 'date'
require 'ltsv'
require "concurrent/map"
require './object_ext' #.present?が使いたかったために拡張
class MyApp < Sinatra::Base
configure :development do
register Sinatra::Reloader
end
#TD初期設定
TreasureData::Logger.open('DB名',
:apikey=>ENV['TD_API_KEY'],
:auto_create_table=>true)
class Lib
include ObjectExtension
def log_parser(log)
・・・ 受け取ったログをパースしてhashで返す ・・・
end
end
paser = Lib.new
post '/' do
・・・ logを受け取りlog_parser(log)でパースする ・・・
TD.event.post('テーブル名',{送るデータ})
end
end
MyApp.run!
結果から言うとbeforeは要らなかった。
これで、約5分間隔でTDへpostする様に安定した。
#結論
TreasureData::Logger.openは一回呼び出せばそれで良い代物であって、
何度も呼び出される様な場所に記述をしてはいけない。