小さいrailsサービスあるある

railsで何かサービスを作ったとする。ExceptionNotificationも入れた。NewRelicで5分毎に死活監視もしてる。なのに「落ちてるみたいです」とTwitterで言われる。

nginx + unicornの組み合わせでアクセスが増えた時、大抵真っ先に起こるのがunicornのtime out。

2013/02/08 18:36:10 [error] 20932#0: *3506622 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 〜ってやつ。

重いDBのクエリとかでアクセスをさばくスピードより接続数が増えてきて起こる。railsアプリまで処理が行かないのでExceptionは起こらない。NewRelicで監視してるURL以外で起きたり時々起きたりしてるからこちらが気付かない。

Nginxのエラーログを監視する

要はNginxのエラーログも監視しないといけない。syslog(rsyslog)でもplainなfileを監視したりalertメール飛ばしたり、複数台のログを1台に集約したりプラグインでできるけど、不必要なエラーログをフィルタリングしたりの設定が少し面倒くさい。

nagios or ganglia or monit入れる?この程度のサービスでfluentd使うのも大袈裟だしなあ。

logentriesを使う

logentriesLogglyとか沢山あるログ収集系のWebサービスです。多分これ系のどのサービス使っても同じ事できますが、LogglyだとAlertingは別サービスになってたりしてメンドイ。logentriesはWeb UIはイマイチですが設定は簡単だしalertメール飛ばすだけなら十分便利です。

logをlogentriesに送る方法は色々ありますが、専用agentを入れるのが一番簡単です。



$ su -
# echo 'deb http://rep.logentries.com/ squeeze main' >/etc/apt/sources.list.d/logentries.list
# gpg --keyserver pgp.mit.edu --recv-keys C43C79AD && gpg -a --export C43C79AD | apt-key add -
# apt-get update
# apt-get install python-setproctitle logentries
# le register
# apt-get install logentries-daemon

NginxのErrorログを監視。

# le follow /var/log/nginx/error.log --name Nginx-Error

しばらくするとこんな感じでログが集まってくる。

nginxのerror logは普通に404とかのエラーもあるので全部をalertメールしてたらウザいのでパターンにタグをつけます。

そしてそのタグに対してAlerts設定でメールを飛ばせばOK。「1時間に10回以上起きたら」とか「1時間に1回しか送りません」とかもWebから設定できるので簡単。

これで

「お客さんのエラー体験 = 俺らにAlertメール」

の図式に(常識的なメール数の中で)なるのでみんなで頑張ってエラー減らしまっしょい!という雰囲気になって良いです。

git commit時にlog入りの写真を取ってくれる。

$ gem install lolcommits
$ cd /path-to/project-repos
$ lolcommits --enable

mroth/lolcommits · GitHub

post-commitにコマンドが入るだけなのでシンプル。

% cat .git/hooks/post-commit 
#!/bin/sh
lolcommits --capture

commitするたびに~/.lolcommits/project-nameディレクトリに写真が保存されていきます。Macのカメラが一瞬光るぐらいで作業の邪魔にはなりません。

2週間ぐらい経ってから思い出してディレクトリを見てみたら面白かったです。大体はしかめっ面で画面を睨みつけてる写真になるんですが、変なのをピックアップしてみた。

横に何があったんだろう?

binding_of_caller入れたな〜。クラッシュしまくって直ぐ取っちゃいましたが・・・。lolcommitsで撮ってることは直ぐ忘れてしまいます。

完全に一致

チンカス氏

どうなってるんだよ、怖い話かよ!

iOSアプリ、Androidアプリのダウンロード数などの情報を集約してくれてメール通知などもしてくれるDISTIMOがAPIを提供してたのでmixpanelの時と同じようにTeam Dashboardに出してみました。

アプリ版ももっと頑張ろうというモチベーションが湧いて来ました。

Team DashboardはHTTP Proxyという機能があって、ブラウザ上からJSONのデータを引っ張ってきてパスを指定すればそれだけでウィジェットに表示できるので、合計数は怖話本体にJSON APIを作り、PVのGoogle Analyticsと収益のnendはそれぞれ引っ張ってきて(nendはmechanizeでスクレイプ)、heroku上のsinatraで自作のJSONを返しています。

グラフだけはganglia互換みたいなDatapointsを自分で用意する必要があります。でもdemoコードがついてるので実装はパクれば簡単。レンジ指定などは端折ってとりあえずMixpanelから日別の怖い話投稿数・サインアップ数・シェア数を取ってきて出すようにしてみました。

# app/models/sources/datapoints/mixpanel.rb:
module Sources
  module Datapoints
    class Mixpanel < Sources::Datapoints::Base
      def get(targets, from, to, options = {})
        client = ::Mixpanel::Client.new(
          api_key: 'xxxxxxxxxxxxxxxxxxxxxxx',
          api_secret: 'xxxxxxxxxxxxxxxxxxxxxxxx'
        )

        data = client.request('events', {
          event:     '["Share","Signed up","Posted story"]',
          type:      'general',
          unit:      'day',    
          interval:   30,      
        })

        results = []           
        targets.each do |target|        
          datapoints = []
          data["data"]["series"].each do |date|
            datapoints << [data["data"]["values"][target][date], Time.parse(date).to_i]
          end
          results << {'target' => target, 'datapoints' => datapoints}
        end                    

        results                
      end                      

      def available_targets(options = {}) 
        ["Share", "Posted story", "Signed up"]
      end

      def supports_target_browsing?
        true
      end
    end
  end
end

怖話 - Team Dashboard


SNSログイン(Twitterでログインとか)をリリースしてから明らかにサインアップ数が増えてることが分かって嬉しい。

あとはWebとiPhone版とAndroid版の比率とか出したいので円グラフを出したいところです。

昨日Team Dashboardを設定して今日見てみたら…

もう、オマエら勝手に弄るなよなぁw

そもそもイントラ向けっぽいのでデータ変更系メソッドだけにBASIC認証かけときました。

# app/controllers/api/base_controller.rb: 
module Api
  class BaseController < ApplicationController
    http_basic_authenticate_with name: 'admin', password: 'foo', only: [:create, :update, :destroy]
    # some codes
  end
end

これでよし。

追記:


Created with Gifboom

弊社オフィスのダッシュボードは現Engine Yard@yandoさんから貰ったEeePCで動かしています。@yandoさんとても助かっています。ありがとうございます。みんなEngine Yard使おう!(東京リージョンもあるよ!)

オフィスでGoogle AnalyticsとかMixpanelとかlogentriesとかディスプレイに表示させてたんですが、適当じゃなくてそろそろちゃんとした指標(ユーザー増加率とか)を出して共有したいなと思いました。自分で作るのは面倒なので探していたらTeam Dashboardがrails + backborne.jsで出来てて手頃そう。(qnypさんのブログで知りました)

$ git clone git://github.com/fdietz/team_dashboard.git
$ bundle
$ cp config/database.example.yml config/database.yml
$ rake db:create && rake db:migrate
$ rake populate
$ rails s

デフォルトはmysqlなのでherokuで動かしたい場合はpostgresql-adapterを追加。

# Gemfile:
group :production do
  gem "activerecord-postgresql-adapter"
end

怖話では毎月PV・収益の報告をしてますが、これでリアルタイムで見れるようになりました。

怖話 - Team Dashboard

ajaxで投稿してその結果を調べるみたいなテストでテストが通ったり通らなかったりする。投稿が反映される前に見に行くことがあるから。

feature "Posting a comment", js: true do
  scenario "as signed user" do
    comment_id = Comment.last.id + 1
    within("#new_comment") do
      fill_in 'comment[body]', with: 'コメントのテスト'
    end
    click_button '規約に同意してコメントする'
    sleep 1 # PLZ WAIT!! FIXME!!
    find("#comment_#{comment_id}").should have_content('コメントのテスト')
  end
end

CapybaraのREADMEにも書いてあるけどデフォルトは2秒待つようだけど5に変えたら行けた。(sleep 1は取りましたw)

# spec/spec_helper.rb:
RSpec.configure do |config| 
  Capybara.default_wait_time = 5
end

Facebook OAuthとかで証明書ちゃんと設定しないとSSLのエラーが出る。

SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (OpenSSL::SSL::SSLError)

certifiedがgemの中に証明書持ってるので使うと楽。

$ gem install certified

stevegraham/certified · GitHub

ceder stackバージョン。

ほぼ下記のまんまです。

Creating Static Sites in Ruby with Rack | Heroku Dev Center

$ mkdir -p public/{images,js,css}
$ touch site/{config.ru,public/index.html}
# Gemfile:
source :rubygems
gem 'rack'
# config.ru:
use Rack::Static,
  urls: ['/images', '/js', '/css'],
  root: 'public'

run lambda { |env|
  [
    200,
    {
      'Content-Type'  => 'text/html',
      'Cache-Control' => 'public, max-age=86400'
    },
    File.open('public/index.html', File::RDONLY)
  ]
}

komagata.orgはまんまコレなのでソースへのリンクも置いておきます。heroku便利ですね。

komagata/komagata-org · GitHub

debian(wheezy)でお手軽なiptablesのフロントエンドはないかなと、Debian WikiのFirewallのページを探していたらufw(Uncomplecated Firewal)が便利そうだったので使ってみました。(これ絶対元々はUbuntu Firewallとかそういう名前だっただろう。汚い、流石Ubuntu汚い)

ufw気に入った

$ sudo apt-get install ufw

ufwは単なるiptablesのフロントエンドでufw show rawでiptablesの生ruleも表示できるそうです。良さそうな予感。

$ sudo ufw default deny
$ sudo ufw allow 10022
$ sudo ufw allow 80/tcp
$ sudo ufw enable

あら簡単。(sshは10022ポートに変更してるので)

何回来たらrejectとか細かい設定もできるみたいですが、インフラ弱者の俺にはこれでも十分過ぎる程です。