QA@IT

Rails のログに,アクセス元IP アドレスやセッション変数を追記する方法

6665 PV

質問

Rails 3.2.11 で,リクエストの様々な情報をログに残したいと思っています.

特に下の2つですが,ActiveSupport::LogSubscriber を利用しつつrequestsession オブジェクトにアクセスしログに残す方法はありますか?

request.remote_ip
session[:user_id]

Rails.logger をカスタマイズし 出力を加工することはできるのですが,requestsession オブジェクトにアクセスする方法がわかりません.

背景

ログ用に lograge というgem を使っているため,ActiveSupport::LogSubscriber の拡張とActiveSupport::Notifications::Event を使って実装できるとうれしいです.

参考

標準のActiveSupport::Notifications::Event の中身

以下のように,event.payload にはrequest オブジェクトの一部がString として格納されています.
このままではsessionrequest にアクセスできなさそうです.

From: /path/to/myapp/config/application.rb @ line 65 :

    60:     # Version of your assets, change this if you want to expire all your assets
    61:     config.assets.version = '1.0'
    62:
    63:     # Enable lograge
    64:     config.lograge.enabled = true
 => 65:     config.lograge.custom_options = ->(event){ binding.pry }
    66:   end
    67: end

[1] pry(Myapp::Application)> event
=> #<ActiveSupport::Notifications::Event:0x00000005b05810
 @duration=1003.062372,
 @end=2013-05-13 14:12:15 +0900,
 @name="process_action.action_controller",
 @payload=
  {:controller=>"SomethingsController",
   :action=>"index",
   :params=>{"action"=>"index", "controller"=>"somethings"},
   :format=>:html,
   :method=>"GET",
   :path=>"/somethings",
   :status=>200,
   :view_runtime=>714.8272919999999,
   :db_runtime=>0},
 @time=2013-05-13 14:12:14 +0900,
 @transaction_id="1ce1d9096062737f43e4">

ActionController::Base 拡張による実装

https://github.com/roidrage/lograge/issues/10 のようにActionController::Base 内でpayload に新たな文字列をセットすれば実現できそうですが,これが良いアプローチかどうか自信がありません.

追記

# config/application.rb
config.log_tags = [:remote_ip]

により,request.remote_ip をログに含めることができました.
次に,request.session[:user_id] にアクセスするための方法を調べたので 追記します.

結果的には http://stackoverflow.com/questions/10811393/how-to-log-user-name-in-rails を参考にし,Rails::Rack::Logger middleware の評価を後ろに回せば 動きました.

標準では次のようになっているmiddleware 群が

Rails.configuration.middleware.instance_variable_get(:@middlewares)
=> [ActionDispatch::Static,
 Rack::Lock,
 #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000003e3be50>,
 Rack::Runtime,
 Rack::MethodOverride,
 ActionDispatch::RequestId,
 Rails::Rack::Logger,
 ActionDispatch::ShowExceptions,
 ActionDispatch::DebugExceptions,
 ActionDispatch::RemoteIp,
 ActionDispatch::Reloader,
 ActionDispatch::Callbacks,
 ActiveRecord::ConnectionAdapters::ConnectionManagement,
 ActiveRecord::QueryCache,
 ActionDispatch::Cookies,
 ActionDispatch::Session::CookieStore,
 ActionDispatch::Flash,
 ActionDispatch::ParamsParser,
 ActionDispatch::Head,
 Rack::ConditionalGet,
 Rack::ETag,
 ActionDispatch::BestStandardsSupport]

次のような順序に変わります.

Rails.configuration.middleware.instance_variable_get(:@middlewares)
=> [ActionDispatch::Static,
 Rack::Lock,
 #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x0000000434fd10>,
 Rack::Runtime,
 Rack::MethodOverride,
 ActionDispatch::RequestId,
 ActionDispatch::RemoteIp,
 ActionDispatch::Cookies,
 ActionDispatch::Session::CookieStore,
 Rails::Rack::Logger,
 ActionDispatch::ShowExceptions,
 ActionDispatch::DebugExceptions,
 ActionDispatch::Reloader,
 ActionDispatch::Callbacks,
 ActiveRecord::ConnectionAdapters::ConnectionManagement,
 ActiveRecord::QueryCache,
 ActionDispatch::Flash,
 ActionDispatch::ParamsParser,
 ActionDispatch::Head,
 Rack::ConditionalGet,
 Rack::ETag,
 ActionDispatch::BestStandardsSupport]

これでrequest.session にもアクセスできそうです.最終的には次のような設定になっています.
このソリューションの良し悪しはよく分かりませんが...動いているようには見えます.

# config/application.rb
config.middleware.delete ActionDispatch::RemoteIp
config.middleware.delete ActionDispatch::Cookies
config.middleware.delete ActionDispatch::Session::CookieStore
config.middleware.insert_before Rails::Rack::Logger, ActionDispatch::RemoteIp config.middleware.insert_before Rails::Rack::Logger, ActionDispatch::Cookies
config.middleware.insert_before Rails::Rack::Logger, ActionDispatch::Session::CookieStore

config.log_tags = [:remote_ip, ->(request){ request.session[:user_id] }]
  • remote_ip は config.log_tags に設定すれば記録出来るようです。
    http://railscasts.com/episodes/318-upgrading-to-rails-3-2
    -
  • ありがとうございます.Rails3.2 からconfig.log_tags というしくみができたんですね.remote_ip はアドバイス頂いたrailscast#318 通りで動きました.

    (moro さんが回答欄に書いて頂いたように,accept したいのですが...どうでしょう?)
    -

回答

znzさんのコメントにある log_tags を使うのがよさそうですね。

http://stackoverflow.com/questions/9582200/add-session-id-to-each-log-in-rails などを見つけました。

この記事によれば、log_tagsにはProcを渡せるために、そこでリクエストからセッションIDなどを取ってくるのがよさそうです。ほぼこの通りにできるのではないでしょうか。

オフトピですが、このQはどうみてもznzさんがベストアンサー賞だと思うので、気づいてAを書いてくれると良いなあと思いました。

編集 履歴 (0)
  • ありがとうございます.
    アドバイス頂いたものそのままではrequest.session にうまくアクセスできませんでした.
    -
  • (理解が追いついておりませんが) http://stackoverflow.com/questions/10811393/how-to-log-user-name-in-rails のようにrack middleware の評価順を変える必要があるようです.調べた結果は質問に追記しようと思います. -
ウォッチ

この質問への回答やコメントをメールでお知らせします。