ActiveRecordで、あるSQLが発行された時に、そのSQLが実行されるDBのコネクション情報を調べたいときがある。
Hoge.find() したときにどういうSQLが発行されているのかというのはdevelopment環境ならデフォルトでdevelopment.logにクエリログが出る。
このログ処理は active_record/connection_adapters/abstract_adapter.rb に書かれてる。
# active_record/connection_adapters/abstract_adapter.rb 198 def log(sql, name) 199 name ||= "SQL" 200 @instrumenter.instrument("sql.active_record", 201 :sql => sql, :name => name, :connection_id => object_id) do 202 yield 203 end 204 rescue Exception => e 205 message = "#{e.class.name}: #{e.message}: #{sql}" 206 @logger.debug message if @logger 207 raise translate_exception(e, message) 208 end 209 210 def translate_exception(e, message) 211 # override in derived class 212 ActiveRecord::StatementInvalid.new(message) 213 end
これをフックして処理を書けばいい気がするけど、クエリログがオフになってる環境ではこのメソッドは実行されないのでちょっと不便。
だからこう書くことにする。*1
::ActiveRecord::ConnectionAdapters::Mysql2Adapter.class_eval do def execute_with_logging(sql, name = nil) result = execute_without_logging(sql, name) # ここで解析処理を書く。 # DBの情報は @config というハッシュに入ってる。 # たとえば @config[:database] でDB名、 @config[:username] でDBのユーザ名が取得可能 result end alias_method_chain :execute, :logging end
ActiveRecordが発行するSQLは必ずDBアダプタのexecuteメソッドで実行されるので、それをフックしている。