まっしろけっけ

めもてきなやーつ

Rubyはじめて1年間+αで読んだ書籍や参考にしたサイト等

よくあるタイトルの記事
Rubyを仕事で使いはじめてやっと1年たったのでまとめてみる
書こうと思って数ヶ月経ってしまったので現在は経験1年半くらい

Rubyをお仕事で使う以前のお話は下記参照

PHP書いてたけどRuby書くことになって1年間でやったことてきな - まっしろけっけ

参考にした書籍

最初に読んだ本

タイトル通りRubyは楽しかったです。

RailsによるアジャイルWebアプリケーション開発 第4版

RailsによるアジャイルWebアプリケーション開発 第4版

仕事で使うのがRails3.2だったのでRails3の本を探していて良さそうだったので
こちらを購入
Railsの基本的なことがわかった気がする

ちょっとRubyになれてきて読んだ本

Ruby書き始めて3ヶ月くらいの時に読んだのが下記の本

パーフェクトRuby (PERFECT SERIES 6)

パーフェクトRuby (PERFECT SERIES 6)

この本はRubyに慣れて来た自分にとっては復習的な意味やそんな書き方出来るのかRubyすげーってなってとても良かった。

入門Chef Solo - Infrastructure as Code

入門Chef Solo - Infrastructure as Code

この本はRubyというよりはRubyで書かれたchefというプロビジョニングツールの本
recipeをRubyで記述出来るのでchefは個人的に楽。
サクッと読めたし、この本の内容はとても役にたっている。

それなりに慣れてきて読んだ本

Ruby初めてもうすぐ10ヶ月くらいで読んだ本
ちょうどその時期に発売されたので即ポチった。

パーフェクトRuby on Rails

パーフェクトRuby on Rails

経験10ヶ月の自分としては復習になる内容と参考になる内容両方がありとても役にたった。
内容的には初心者にはちょっと辛いかもしれないが、ちょっと慣れてきた人であれば為になることが多いので読む価値はあると思う。
便利なgemをいくつも紹介してくれているので、それらを実際に導入してみた。

1年以降に読んだ本

1年以降に読んだのが下記

Ruby徹底攻略 (WEB+DB PRESS plus)

Ruby徹底攻略 (WEB+DB PRESS plus)

復習の様な気持ちで読んだ。

gemのfluentdを使いたかったのでこちらで勉強をして導入した。

直接的なRubyに関する本ではないがRubyを使ってちょっと深い層(プログラミング言語とか)の説明がされています。

Rubyのしくみ -Ruby Under a Microscope-

Rubyのしくみ -Ruby Under a Microscope-

Ruby自体がどのように作られているかを解説してくれている一冊。
C言語が解らなくてもいいが解るととても面白いと思います。
個人的にはGC周りの話はとても面白かった。

Effective Ruby

Effective Ruby

中途半端に読んで止まっているが最初からだいぶ面白い

参考にしたサイト

とりあえず日本語のサイトをあげてみる

Ruby

Rubyコーディング規約

Rubyに慣れるまではだいぶお世話になった。

Rubyist Magazine - るびま

Rubyに関しての色々な情報がしれる。
過去のRubyKaigiのレポートもまとまってたりする。(RubyKaigi2014は今のところない)

Ruby Reference Manual
Rubyリファレンス

Rubyのリファレンス系は特にこの2つ

Rails

Railsドキュメント

Railsのドキュメント

Ruby on Rails Guides

最近翻訳のペースが上がっているので今からRails始めるなら日本語版でも不自由無いかも

その他

RubyRailsに限らずに参考にしているサイト

はてなブックマーク

みんな大好きはてブ
とりあえずテクノロジーカテゴリーは常にチェック

shiro16 (@shiro166) | Twitter

みんな知ってるtwitter
とりあえずRubyRailsのコアコミッターの方々やクッ社の方々をfollowして
その人達がシェアする内容をチェックしたり、
RTした人を更にfollowしていけばいいんじゃないかな。kamipoさんとか

Qiita - プログラマの技術情報共有サービス

アカウントは作ってないけど参考になる記事は多いので
見る専門ですが良く利用している。

まとめ

とりあえず思い出しつつ、今手元にある本と参考にしているサイトを記述してみた。
(貸し出してるものもあるので他にも読んだ本はあるかもしれない)
書いてて困ったらググれば情報なんていっぱい出てくるので
そんなに困ること無い気がする。

最近はこんなこと出来ないのかなー?と思ってちょっとググって出てこなかったら
そのgemのソースコード読んだり、Railsソースコード読んだりすることが多い。
Railsのソースとか読んでるとそこから学べることがかなり多い。

fluent-plugin-record-reformerを使ってhostnameを追加してみた

以前下記の記事でFluentd + Elasticsearch + kibanaを導入して
リアルタイムログ解析を行う方法をメモったその後。

実際に導入してみるとhostnameが無いと結局調査を行うには
どのhostに入って詳細な調査をすれば良いか分からないから片っ端から入ってみるみたいな感じになっちゃっていたので
hostnameも追加したいなとずっと思っていてしてなかった。。。


fluentd + elasticsearch + kibanaを導入したので手順をメモ - まっしろけっけ

つい先日hostname追加を行ったのでその内容をメモ
※今回の方法以外にも実は簡単に出来る方法があるかもしれない。

fluent-plugin-record-reformerをinstall

構成は上記の過去記事を参照してください。
今回はfluent-plugin-record-reformerというpluginを使います。
Forwarderにて下記を実行

$ gem install fluent-plugin-record-reformer

fluent.confを編集

# Nginx access logの設定
<source>
  type tail # 
  path /var/log/nginx/access.log # nginxのaccess logのpath
  format nginx # fileのフォーマット
  tag nginx.access.addHostname # tag名
  pos_file /var/log/fluent/nginx.access.pos # position fileを保存しておくpath
</source>

# Rails errorの設定
<source>
  type tail
  path RAILS_ROOT/log/rails.log # Railsのlogのpath指定
  format multiline # 複数行のログを送りたいときに指定
  format_firstline /.*[eE]rror.*/ # Errorもしくはerrorを含む行からformatNの条件を満たすログまでを送信する
  format1 /(?<error>.*[eE]rror.*)\n\n/ # 改行が連続している部分まで送信する
  tag rails.error.addHostname # tag名
  pos_file /var/log/fluent/rails.error.pos # position fileを保存しておくpath
</source>

<match **.addHostname>
  type record_reformer
  renew_record false
  enable_ruby true
  output_tag ${(tag_parts - ["addHostname"]).join(".")}

  <record>
    hostname ${hostname}
  </record>
</match>

<match *.**> # この条件にmatchするtagを下記の条件でごにょごにょする
  type forward
  buffer_type memory # Fluentdの内部バッファリングにmemoryを使用
  buffer_chunk_limit 256m # チャンクのサイズ
  buffer_queue_limit 128 # チャンクキューの長さ
  flush_interval 5s # データフラッシュの間隔
  <server>
    host aggregator_host # aggregatorのIP
    port aggregator_port # aggregatorのfluentの使用portを指定
  </server>
</match>
  • 各tag名に.addHostnameを追加
  • addHostnameが付いているtag用のmatchを追加
  • addHostnameのmatchでhostnameを追加

あとはForwarderのfluentdを再起動させるとhostnameが追加されます

感想

簡単にhostnameの追加が出来ました。
そしてhostnameあるとやはり便利!

gemのwheneverを導入してみた

wheneverとは?

javan/whenever · GitHub
簡単に説明するとRubyのコードでcrontabの管理が出来るライブラリです。

導入以前

whenever導入前はbatchを実行するserverに入って「crontab -e」とかで編集する
crontabメンテナンスおじさんが存在していた。

問題点

  • 設定がcrontabメンテナンスおじさんに依存してしまう
  • crontabメンテナンスおじさんとcrontabを設定しているserverがお亡くなりになった場合、再設定出来ない

解決方法

  1. chefで管理する
  2. ansibleで管理する
  3. どこかにまとめておく
  4. whenever導入

等々があった訳ですが
1,2はほぼ同じでプロビジョニングツールで管理するやり方です。

  • crontab変更する為だけにプロビジョニングツールを走らせるのめんどくさい
  • recipeやplaybook変更したけど、すぐには反映したくないけどcrontabだけ変更したいってなったら面倒

3に関して結局メンテナンスおじさんが発生してしまうのを回避出来ない・・・
wheneverではdeploy時にcrontabを更新することが可能なので問題点を解決出来るはず!ということで導入を決定。
経験上crontabを変更するのはdeployのタイミングがほとんどで緊急で編集したいということもほとんどない

gem install

環境は下記

導入自体は結構簡単

Gemfileに下記を追記でbundle install

+ gem 'whenever', require: false

もしくはgem install

$ gem install whenever

設定をcrontabの更新

$ cd rails_root
$ wheneverize . # もしくはbundle exec wheneverize .

これでconfig/schedule.rbというファイルが作成されます。
コメントアウトにてExampleが書いてあります。

schedule.rbを編集
※サンプルなので仮のrake taskを指定しています

# 出力先logの指定
set :output, 'log/crontab.log'
# 実行環境の指定
set :environment, :production

# 1時間毎に実行
every :hour do
  rake 'rake:task1'
end

# 1時間毎に実行
every 1.hour do
  rake 'rake:task2'
end

# 3分毎に実行(crontabと記述方法を合わせる)
every '*/3 * * * *' do
  rake 'rake:task3'
end

crontabを更新してみる

$ bundle exec whenever --update-crontab
# ここでinvalid byte sequence in US-ASCII (ArgumentError)が出たら
$ export LC_ALL=en_US.UTF-8
$ export LANG=en_US.UTF-8
$ bundle exec whenever --update-crontab
$ crontab -l
# Begin Whenever generated tasks for: rails_root/config/schedule.rb
0 * * * * /bin/bash -l -c 'cd rails_root && RAILS_ENV=production bundle exec rake rake:task1 --silent >> log/crontab.log 2>&1'

0 0,2,4,6,8,10,12,14,16,18,20,22 * * * /bin/bash -l -c 'cd rails_root && RAILS_ENV=production bundle exec rake rake:task2 --silent >> log/crontab.log 2>&1'

*/3 * * * * /bin/bash -l -c 'cd rails_root && RAILS_ENV=production bundle exec rake rake:task3 --silent >> log/crontab.log 2>&1'

# End Whenever generated tasks for: rails_root/config/schedule.rb

以上で簡単な設定と使い方はおしまい。
今回はrake taskを指定していますが、runner,commandといったものの指定も可能です。

deploy時に更新する

次にdeploy時にcrontabを更新したいので
whenever/capistranoの設定を行います。

Capfile,deploy.rb等に下記を追記

+ require 'whenever/capistrano'

その他のオプションを設定
追記場所は各自のcapistranoの設定に合わせて行ってください。

+ set :whenever_roles, :batch # 対象のロールを指定
+ set :whenever_environment, :production # 対象の環境を指定

これで対象のロールをdeployすればcrontabが更新されるはずです。
whenever/capistranoの詳細な設定周りは下記を参照してください。
whenever/lib/whenever/capistrano at master · javan/whenever · GitHub

環境毎にcrontabの設定を変更したり

実際に導入するにあたり環境毎に一部のrake taskを実行したくない環境とかもあったので
下記のようにしています。

schedule.rb

# 事故防止の為RAILS_ENVの指定が無い場合にはdevelopmentを使用する
rails_env = ENV['RAILS_ENV'] || :development

set :environment, rails_env

set :output, 'log/crontab.log'

# 全環境での設定


if rails_env.to_sym == :production
  # production環境のみで設定
end

capistranoの設定

+ set :whenever_roles, :batch
+ set :whenever_environment, :production
+ set :whenever_command, "RAILS_ENV=#{whenever_environment} bundle exec whenever  --update-crontab"
# もしくは
+ set :whenever_command, "RAILS_ENV=#{fetch(:whenever_environment)} bundle exec whenever --update-crontab"

こんな感じに設定しておけば環境毎にcrontabの内容を変更することも可能です。
※サンプルのcapistranoに関しては--dry-runオプションで確認しただけになります

まとめ

wheneverの導入によりcrontabメンテナンスおじさん(基本的に自分)の排除に成功しました。
wheneverでの時間指定の記述方法はいくつかありますが、
自分はcrontabと比較した時に分かりやすいのと○時間毎とか設定した場合に冗長になるのが嫌だったので
crontabと同じ記述方法を採用しています。
その他の細かい設定はwheneverのREADMEに載っていますのでご確認ください。

今回のサンプルは下記で公開してます。
shiro16/blog-samples · GitHub

Ruby2.2.0のインストールがlibffi.a: could not read symbols: Bad valueで失敗した件

Ruby 2.2.0 Released

素晴らしいクリスマスプレゼント!!
twitter見ている感じだと開発者の皆さんは大変だったようでお疲れ様でした+ありがとうございます。
Let's Install

install

Rubyのversion管理はrbenv使ってます。


rbenvでrubyのversion管理をするよ - まっしろけっけ

rubyのversion upをした時の作業内容メモ - まっしろけっけ


詳細は上記の記事を参照してください。
環境はvm上にCnetOS入れてます。

$ rbenv install 2.2.0
Downloading ruby-2.2.0.tar.gz...
-> http://dqw8nmjcqpjn7.cloudfront.net/7671e394abfb5d262fbcd3b27a71bf78737c7e9347fa21c39e58b0bb9c4840fc
Installing ruby-2.2.0...

BUILD FAILED (CentOS release 6.5 (Final) using ruby-build 20141222-4-ge455975)

Inspect or clean up the working tree at /tmp/ruby-build.20141225151244.8260
Results logged to /tmp/ruby-build.20141225151244.8260.log

Last 10 log lines:
make[3]: Leaving directory `/tmp/ruby-build.20141225151244.8260/ruby-2.2.0/ext/fiddle/libffi-3.2.1'
linking shared-object fiddle.so
/usr/bin/ld: ./libffi-3.2.1/.libs/libffi.a(raw_api.o): relocation R_X86_64_32 against `.text' can not be used when making a shared object; recompile with -fPIC
./libffi-3.2.1/.libs/libffi.a: could not read symbols: Bad value
collect2: ld returned 1 exit status
make[2]: *** [../../.ext/x86_64-linux/fiddle.so] Error 1
make[2]: Leaving directory `/tmp/ruby-build.20141225151244.8260/ruby-2.2.0/ext/fiddle'
make[1]: *** [ext/fiddle/all] Error 2
make[1]: Leaving directory `/tmp/ruby-build.20141225151244.8260/ruby-2.2.0'
make: *** [build-ext] Error 2

エラー出た・・・

libffi-develを入れる

libffi.a: could not read symbols: Bad valueとかエラー出て困った。
twitterを漁っていると・・・


柴田さんありがとうございますmm

ということでlibffi-develを入れてリトライ

$ sudo yum install libffi-devel
$ rbenv install 2.2.0
Downloading ruby-2.2.0.tar.gz...
-> http://dqw8nmjcqpjn7.cloudfront.net/7671e394abfb5d262fbcd3b27a71bf78737c7e9347fa21c39e58b0bb9c4840fc
Installing ruby-2.2.0...
Installed ruby-2.2.0 to /hoge/.rbenv/versions/2.2.0
$ rbenv global 2.2.0
$ ruby -v
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]

入ったー

$ gem install bundler # とりあえずbundlerいれるよね

明日は会社の環境でもinstallして動作確認とかしてみよう

初心者は役立つかもしれないRuby(Rails)のmethod名に「?」がつくmethodのまとめ

まとめようと思った経緯

題名の通りRuby(Rails)にはmethod名に「?」がつくmethodが多く存在します。
「空文字の場合はtrue/falseどっち返すんだっけ?」ってなってconsole等で確認することが良くあるので、
(自分が)よく使うものを一覧でまとめておいてみる

環境とか

今回の検証環境は下記
下記のversionにしたのは最新使ってみたかったという理由のみ!

$ ruby -v
ruby 2.2.0preview2
$ rails -v
Rails 4.2.0.rc3

各methodで調べるデータは下記

  • nil
  • true
  • false
  • 文字(空文字と空文字以外)
  • 数値(0と1)
  • 配列(空配列と空配列以外)
  • Hash(空Hashと空Hash以外)

実行するコードは下記

nil?の部分を各methodに変更していく

params = [nil, true, false, "", "hoge", 0, 1, [], [1], {}, {key: 1}]

params.each do |param|
  begin
    result = param.nil?
  rescue => e
    result = e.message
  ensure
    puts "#{param}.nil? => #{result}"
  end
end

Ruby

nil?

nilかどうかを調べるnil?
当たり前かもしれませんがnil以外はfalse

nil.nil?      => true
true.nil?     => false
false.nil?    => false
"".nil?       => false
"hoge".nil?   => false
0.nil?        => false
1.nil?        => false
[].nil?       => false
[1].nil?      => false
{}.nil?       => false
{key: 1}.nil? => false
empty?

空かどうか調べるempty?
空文字、空配列、空hashのみtrueでした。
いくつかのclassでは定義されていないのでundefined methodの例外が発生しました。

nil.empty?      => undefined method `empty?' for nil:NilClass
true.empty?     => undefined method `empty?' for true:TrueClass
false.empty?    => undefined method `empty?' for false:FalseClass
"".empty?       => true
"hoge".empty?   => false
0.empty?        => undefined method `empty?' for 0:Fixnum
1.empty?        => undefined method `empty?' for 1:Fixnum
[].empty?       => true
[1].empty?      => false
{}.empty?       => true
{key: 1}.empty? => false
zero?

zeroかどうかを調べるzero?
Numeric classを継承しているclassにのみ定義されているようです。
最近使っただけでよくはつかわない

nil.zero?      => undefined method `zero?' for nil:NilClass
true.zero?     => undefined method `zero?' for true:TrueClass
false.zero?    => undefined method `zero?' for false:FalseClass
"".zero?       => undefined method `zero?' for "":String
"hoge".zero?   => undefined method `zero?' for "hoge":String
0.zero?        => true
1.zero?        => false
[].zero?       => undefined method `zero?' for []:Array
[1].zero?      => undefined method `zero?' for [1]:Array
{}.zero?       => undefined method `zero?' for {}:Hash
{key: 1}.zero? => undefined method `zero?' for {key: 1}:Hash
nonzero?

zeroじゃないかどうかを調べるnonzero?
zero? methodと同じでNumeric classを継承しているclassにのみ定義されているようです。

?付きmethodですが0の場合はnilを返し0じゃない場合はselfを返します。
最近使っただけでよくはつかわない

nil.nonzero?      => undefined method `nonzero?' for nil:NilClass
true.nonzero?     => undefined method `nonzero?' for true:TrueClass
false.nonzero?    => undefined method `nonzero?' for false:FalseClass
"".nonzero?       => undefined method `nonzero?' for "":String
"hoge".nonzero?   => undefined method `nonzero?' for "hoge":String
0.nonzero?        => nil
1.nonzero?        => 1
[].nonzero?       => undefined method `nonzero?' for []:Array
[1].nonzero?      => undefined method `nonzero?' for [1]:Array
{}.nonzero?       => undefined method `nonzero?' for {}:Hash
{key: 1}.nonzero? => undefined method `nonzero?' for {key: 1}:Hash

Rails

blank?

nil? + empty? のようなmethod
更にfalseでもtrueを返します

nil.blank?      => true
true.blank?     => false
false.blank?    => true
"".blank?       => true
"hoge".blank?   => false
0.blank?        => false
1.blank?        => false
[].blank?       => true
[1].blank?      => false
{}.blank?       => true
{key: 1}.blank? => false
present?

!blank?もしくはblank?.!のようなmethod
if 変数.present?とunless 変数.blank?は同じ意味になります。

nil.present?      => false
true.present?     => true
false.present?    => false
"".present?       => false
"hoge".present?   => true
0.present?        => true
1.present?        => true
[].present?       => false
[1].present?      => true
{}.present?       => false
{key: 1}.present? => true
blank?, present?のおまけ

空文字の際にtrueを返すblank?ですが下記の文字列でもtrueを返します

params = [" ", " ", "\t", "\n", "\r", "\r\n", "\f", "\s"]

" ".blank?    => true
" ".blank?   => true
"\t".blank?   => true
"\n".blank?   => true
"\r".blank?   => true
"\r\n".blank? => true
"\f".blank?   => true
"\s".blank?   => true

present?で同じ文字列を判定

" ".present?    => false
" ".present?   => false
"\t".present?   => false
"\n".present?   => false
"\r".present?   => false
"\r\n".present? => false
"\f".present?   => false
"\s".present?   => false

ちなみにempty?の全てfalseを返します

" ".empty?    => false
" ".empty?   => false
"\t".empty?   => false
"\n".empty?   => false
"\r".empty?   => false
"\r\n".empty? => false
"\f".empty?   => false
"\s".empty?   => false

blank?がこのような挙動になるのはこちらをご覧ください。

まとめ

下記のような結果になったよ。

nil? empty? zero? nonzero? blank? present?
nil true × × × true false
true false × × × false true
false false × × × true false
空文字 false true × × true false
文字列 false false × × false true
0 false × true nil false true
1 false × false self false true
空配列 false true × × true false
配列 false false × × false true
空Hash false true × × true false
Hash false false × × false true

×はundefined method
一部の出力は見やすいように加工してますよ

PHP書いてたけどRuby書くことになって1年間でやったことてきな

久しぶりに雑談っぽい記事
よくあるようなタイトルでブログを書いてみる(実は4ヶ月前から下書きとして放置温めていた訳では・・・)
Rubyをお仕事で使い始めて(ほぼ未経験の状態から)1年以上(1年4ヶ月くらい)たったので
Rubyを使い始めて1年でやったこととかまとめてみる

Rubyをお仕事で使う以前のお話

Rubyの直前だとPHP書いてました。
FrameworkはCodeIgniterで、他にPHPのFrameworkだとZend Frameworkはお仕事で使ったことあります。
他の言語だと、C/C++,Java(少々),JavaScript,etc...

Rubyを使うことになった経緯

PHPで書いていたシステムのリプレースで闇による策略(適当)により
最終的にRuby(Ruby on Rails)でやるよ!ってなったから
(PHPは数年書いてたので個人的に新しい言語出来るのは嬉しかった)
なので下記のような感じでお仕事の内容は進んでいくのです。

  1. リプレース
  2. リリース
  3. その後
1.リプレース

Rubyなにそれ?おいしいの?状態だったので技術書でRubyRailsの勉強をしつつ
ここら辺の善しとされる記述方をガン見したり社内の他のRailsプロジェクトのソースを見ること数日

とりあえず1機能作ってみることになり作成してpull requestを送る
チーム内に1名経験者がいたのでその人にレビューして貰い、修正して再度レビューをして貰い・・・
等々を繰り返してRubyになれて来たあたりでもう一冊下記の技術書を購入

パーフェクトRuby (PERFECT SERIES 6)

パーフェクトRuby (PERFECT SERIES 6)

この本はRubyに慣れて来た自分にとっては復習的な意味やそんな書き方出来るのかRubyすげーってなってとても良かった。

そんなこんなで何とかリプレース終わったんですが、
やはり経験者がレビューをしてくれるっていうのは
Ruby特有の記述方を理解する上でとてもありがたかった。

2.リリース

リリース1ヶ月前くらいに経験者の人がチームから抜け(一応サポートはしてくれるという形)、
運用したことない自分が色々やることになってしまった件。
そんなこんなでリリースした訳ですが、レスポンスがおっそ!ってなり
2週間くらいごにょごにょを行うことになり,
その2週間くらいユーザにちゃんとしたサービスを提供できていないことが申し訳なさすぎて本当に胃が痛い毎日を送ることになった。
(負荷テストをやるべきだったのですが色々な事情により・・・また何故か同じ構成なのに本番環境でのみしか起こらない現象でもあったため)

でもこの2週間くらいのごにょごにょで
だいぶRuby on Railsで構築されたサービスの運用で問題になってくる部分が理解でき
経験値はだいぶ積めた気がする。

3.その後

リリース後は機能追加とかしていく訳ですが、
機能追加という面では特に困ったことは無く(時々Rubyの罠にはまったりしましたが・・・)
機能追加の他にもレスポンスを早くする為に主にviewのレンダリングの高速化等を行いました。

  • Ruby関連の技術書をいくつか読む
  • はてぶとかでRuby関連の情報をチェック
  • twitterRubyの凄い人達をフォロー
  • chefのrecipe書く
  • capistrano deployタスク整理
  • fragment cache使用
  • いくつかのgemの作成
  • Redis-Sentinel導入
  • Rubyのversion up
  • RubyKaigi2014に参加

機能追加以外には上記の様なことをやりちょうど1年たったくらいでRailsのversionを3.2から4.1へupgradeしました。

まとめてきな

そんなこんなでRubyistになった訳です。
色々な理由からはじめたRubyですが、
書き始めた段階から経験者にレビューして貰える環境だったので
その点でかなりRubyらしい書き方を覚えることが出来て習得がスムーズにいった気がします。
Ruby(Rails)を使ってみて感じたことは以下のような点です。

1.コードを短く綺麗に書ける

綺麗なコードは芸術だと思っている自分としてはこれは凄く嬉しかった。
しかも可読性が高く直感的にわかりやすい。

2.ARがすごい

これはRubyでは無くRailsの話
ActiveRecordが凄く優秀でこれのおかげで更にコードを綺麗に書ける

3.命名は凄く大事

以前は略語とかを使ってmethod名等を短くしていたのですが、
method名は可読性が高く直感的にわかりやすいものを付ける癖がつきました。
Rubyだからという訳ではなく他の言語でも気をつければいいのですが・・・

4.Gemがいっぱい

Gemがいっぱいあって便利
使用するGemをGemfileに書いてbundle installすれば
簡単にGemを導入出来るのは素敵すぎる

5.testを書く文化てきなやつ

Ruby書いているならtestも一緒に書くの当たり前だよねてきな雰囲気がある気がするのですが、
testを書いていてよかったと思うことが多々あるのでtestを書く習慣が出来たのはよかった。
他の言語でもちゃんとtest書こうと思えた。
testがあるとリファクタとかRubyRails,その他のgemのversion upも楽だった

6.開発効率があがった気がする

開発の効率はあがった気がする。
PHP書いてた時はtest書かなかったけど、
testを書いている今と比べても今の方が開発のスピードは上がったしバグも少ない気がする。

7.コミュニティが凄い

日本人(Matz)が作成した言語だからなのかも知れませんが、
コミュニティの活発さが凄く目立っている感があっていいなという印象

8.多機能すぎてググるのつらめ

複雑なことも出来るので、こんな複雑なこと出来るのかな?
っていうときにどんなワードでググればいいかわからないというのが
初期のときに多かった気がします。

9.version upを追うの大変

他の言語に比べて新しいversionが公開されるスピードが早いのと、
それを追わなければならない感が強いと感じました。
追うのは大変ですが個人的にはそれが楽しかったりします。

10.書いていて楽しい

そのままなのですが書いてて楽しい
でもこれが一番大事ですよね

他にもいっぱい感じたことがあるのですが最後の「書いていて楽しい」というのが
一番大きいですね。
参考にした技術書やサイトも後ほどまとめようかと思います。

Fluentd + Elasticsearch +Kibanaを導入したので手順をメモ

導入経緯

「serverのログ見るときに複数のserverにsshで入って見るのとかつらめ」
という理由からリアルタイムで集められたら幸せになれるのではと考え、
fluentdを使ってみようとい結論に至った訳です。

なぜfluentdにしたのか

他にもflume(良く知らない)とかあるのになぜfluentdにしたかと言うと下記の理由から

  • Rubyで実装されているのでカスタマイズとかプラグイン作る場合も作りやすいかな
  • gemとして提供されているのでRubyプロジェクトでは導入しやすいかな
  • プラグインがいっぱいある
  • RubyKaigiでそのっつさんの下記のお話を聞いていたりで使ってみたかったとかそんな感じ

Fluentd Hacking Guide at RubyKaigi 2014

リアルタイムログ解析もしてみる

Fluentdを使うならElasticserchとKibanaも導入してリアルタイムログ解析も楽しそうなので導入を決定

Fluentdのセットアップ

今回はnginxのアクセスログRailsのアプリケーションログの中のエラーを抽出してAggregatorに集約したいと思います。
セットアップ前にちょっとfluentdについて説明
いくつかの種類のノードがあるので今回関係あるものを軽く説明

Forwarder

Aggregatorにイベントを送信するノード

Aggregator

各Forwarderから送られるイベントを集約する為のノード

セットアップ

今回はgemを使ってセットアップしますが他にもrpmパッケージからのインストール等複数の選択肢がありますので
下記を参考にしてください。
http://docs.fluentd.org/ja/categories/installation
Ruby等は既にinstallしている前提です。
Rubyのinstallは過去記事をご覧ください。

ForwarderとAggregatorで実行

$ gem install yajl-ruby --platform=ruby # gem install fluentdで正常にinstallできない場合があったので実行
$ gem install fluentd
$ fluentd --setup ~/fluent # ~/fluentdのディレクトリにfluentd用の設定ファイル等を作成する
$ fluentd -c ./fluent/fluent.conf -vv & # 設定ファイルを指定し起動
$ echo '{"json":"message"}' | fluent-cat debug.test # 動作テスト
2014-11-29 17:27:09 +0000 debug.test: {"json":"message"} # こんな感じのログが出力されるはず


Forwarderのconf設定

$ vi ~/fluent/fluent.conf
# Nginx access logの設定
<source>
  type tail # 
  path /var/log/nginx/access.log # nginxのaccess logのpath
  format nginx # fileのフォーマット
  tag nginx.access # tag名
  pos_file /var/log/fluent/nginx.access.pos # position fileを保存しておくpath
</source>

# Rails errorの設定
<source>
  type tail
  path RAILS_ROOT/log/rails.log # Railsのlogのpath指定
  format multiline # 複数行のログを送りたいときに指定
  format_firstline /.*[eE]rror.*/ # Errorもしくはerrorを含む行からformatNの条件を満たすログまでを送信する
  format1 /(?<error>.*[eE]rror.*)\n\n/ # 改行が連続している部分まで送信する
  tag rails.error # tag名
  pos_file /var/log/fluent/rails.error.pos # position fileを保存しておくpath
</source>

<match *.*> # この条件にmatchするtagを下記の条件でごにょごにょする
  type forward
  buffer_type memory # Fluentdの内部バッファリングにmemoryを使用
  buffer_chunk_limit 256m # チャンクのサイズ
  buffer_queue_limit 128 # チャンクキューの長さ
  flush_interval 5s # データフラッシュの間隔
  <server>
    host aggregator_host # aggregatorのIP
    port aggregator_port # aggregatorのfluentの使用portを指定
  </server>
</match>

Aggregatorのconf設定
今回はelasticsearchへの送信とlocalにlog fileとして保存を行う設定です。

$ vi ~/fluent/fluent.conf
<source>
  type forward
  port aggregator_port
</source>

# tag名がnginx.*の設定
<match nginx.*>
  type copy
  <store>
    index_name nginx
    type_name nginx
    type elasticsearch
    include_tag_key true # tag keyの設定
    tag_key @log_name # tag key名
    host localhost # elasticsearchのhost
    port 9200 # elasticsearchのport
    logstash_format true # Kibana用にlogstashフォーマットで出力するオプション
    flush_interval 3s
  </store>

  # localに保存したいので設定
  <store>
    type file
    path /var/log/fluent/nginx.access_log # 保存する際のpath
  </store>
</match>

# tag名がrails.*の設定
<match rails.*>
  type copy
  <store>
    index_name rails
    type_name rails
    type elasticsearch
    include_tag_key true
    tag_key @log_name
    host localhost
    port 9200
    logstash_format true
    logstash_prefix rails
    flush_interval 3s
  </store>

  # localに保存したいので設定
  <store>
    type file
    path /var/log/fluent/rails.access_log # 保存する際のpath
  </store>
</match>


Aggregatorでpluginのinstall

$ fluent-gem install fluent-plugin-elasticsearch
# fluent-gemのコマンドが無いって言われた場合
$ vi ~/.bashrc
+ export PATH="$HOME/.rbenv/versions/2.x.x/bin/:$PATH" # rubyのversionは環境に合わせて変更
$ source ~/.bashrc

confを更新したのでfluentを再起動します。
以上でfluentの設定は終わりー

fluent.confのformatに関して

Forwarderのconfのformatに関してですが
formatで設定された正規表現を使ってログの文字列に対してRubyのmatchを使っているイメージ
なのでRuby正規表現の名前付きキャプチャ等を理解していると設定が楽になるかと思います。

Elasticsearchのセットアップ

今回はAggregatorのserverでelasticsearchを動作させる

$ sudo yum install curl-devel java-1.7.0-openjdk
# elasticsearchもyumでinstallする
$ sudo vi /etc/yum.repos.d/elasticsearch.repo
+ [elasticsearch-1.3]
+ name=Elasticsearch repository for 1.3.x packages
+ baseurl=http://packages.elasticsearch.org/elasticsearch/1.3/centos
+ gpgcheck=1
+ gpgkey=http://packages.elasticsearch.org/GPG-KEY-elasticsearch
+ enabled=1
$ sudo yum install elasticsearch

Kibanaのセットアップ

kibanaもAggregatorのserverにいれる
kibanaへのアクセスはnginxを使うのでnginxも一緒に入れるよ

nginxのセットアップ
$ sudo yum install nginx
$ vi /etc/nginx/conf.d/kibana.conf
server {
    server_name localhost;

    location /kibana/ {
         root /usr/share/nginx/html;
         index index.html index.htm;
    }
}
kibanaのセットアップ
$ wget https://download.elasticsearch.org/kibana/kibana/kibana-3.1.1.tar.gz
$ tar xvzf kibana-3.1.1.tar.gz
$ mv kibana-3.1.1 /usr/share/nginx/html/kibana
$ cd /usr/share/nginx/html/kibana
$ vi config.js 
# 32行目 elasticsearch: "http://"+window.location.hostname+":9200",
# 上記をAggregatorのhost nameに変更

動作確認

設定が完了したのでAggregatorでミドルウェアを起動させる

$ sudo /etc/init.d/nginx start
$ sudo /etc/init.d/elasticsearch start

これでhttp://aggregator_host/kibanaにアクセスするとこのようにkibanaの画面が表示されるはずです。f:id:shiro-16:20141130033707p:plain


抜けている部分があるかもしれませんが
こんな感じで導入は終了です。
fluentのconfの設定をいじって各々の環境や要件に合わせたログ収集を行えば幸せになれるのではないでしょうか
fluentのその他の設定は下記を参考にしてください。