LoginSignup
0
0

More than 3 years have passed since last update.

Sinatraを使ってHeroku drainログをTDへ送るAppを作った時にハマった記録

Posted at

はじめに

Heroku drainからhttp経由でログを取得し、TDへ送るアプリをsinatraで作っていた時ハマった時のことを記録として残す。
Heroku drainからログをpostで受け取る形式のアプリを作った。(Sinatraは初めて)

最初はクラシック形式で作成。

app_main.rb
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する。

モジュールに書き直し

後々のメンテナンス性や拡張性、可読性を考えモジュール化させる。

app_main2.rb
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されてしまう状況に陥った。

app_main2.rb
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は一回呼び出せばそれで良い代物であって、
何度も呼び出される様な場所に記述をしてはいけない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0