RailsでRails.benchmarkメソッドをどこからでも呼び出せるようになった(翻訳)
Railsの最新の変更によって、benchmark
メソッドを任意の場所から呼び出せるようになりました(#40734)。
変更前
変更前は、ビューやコントローラで以下のようにbenchmark
を呼べます。
<% benchmark '=== Processing invoices ===' do %>
<%= process_invoices %>
<% end %>
しかし、モデルやサービスなどにあるメソッドのベンチマークを取りたいときは以下のように書く必要がありました。
require 'benchmark'
def process
logger.info("=== Processing invoices ===")
logger.info Benchmark.measure { process_invoices }
# or
logger.info Benchmark.realtime { process_invoices }
end
出力されるログは以下のようになります。
=== Processing invoices ===
0.406537 0.082624 0.489161 ( 0.503110)
0.5047359999734908
特定のメソッドやコードの実行に要する時間を測定する場合は、次のように書けます。唯一の問題は、ベンチマークを行う必要が生じるたびにクラスにモジュールをinclude
しなければならないことです。
mattr_accessor :logger, default: Rails.logger
extend ActiveSupport::Benchmarkable
include ActiveSupport::Benchmarkable
def process
benchmark("=== Processing invoices ===") { process_invoices }
end
上のスニペットは、操作ごとに要した時間を以下のようにログに出力します。
Started GET "/companies/1/invoices" for ::1 at 2021-02-24 16:38:59 +0530
Processing by CompaniesController#invoices as HTML
Parameters: {"id"=>"1"}
=== Processing invoices === (402.1ms)
Rendered companies/invoices.html.erb within layouts/application (Duration: 1.5ms | Allocations: 426)
Rendered layout layouts/application.html.erb (Duration: 13.0ms | Allocations: 4003)
Completed 200 OK in 427ms (Views: 14.3ms | ActiveRecord: 1.0ms | Allocations: 7079)
変更後
今回の変更により、以下のようにbenchmark
メソッドをどこでも使えるようになりました。従来のようにベンチマークのためだけにモジュールを追加する必要はありません。
def process
Rails.benchmark("=== Processing invoices ===") do
logger.debug("=== Processing started ===")
process_invoices
logger.debug("=== Processing done ===")
end
end
上のコードは、以下のようにログレベルに応じたログを出力します(デフォルトのログレベルは:info
です)。
Started GET "/companies/1/invoices" for ::1 at 2021-02-24 16:40:35 +0530
Processing by CompaniesController#invoices as HTML
Parameters: {"id"=>"1"}
=== Processing started ===
=== Processing done ===
=== Processing invoices === (400.7ms)
Rendered companies/invoices.html.erb within layouts/application (Duration: 1.1ms | Allocations: 426)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered layout layouts/application.html.erb (Duration: 7.6ms | Allocations: 4025)
Completed 200 OK in 417ms (Views: 8.3ms | ActiveRecord: 0.9ms | Allocations: 7397)
benchmark
には以下の2つのオプションを渡せます。
level
- ログレベル(
:debug
、:info
、:warn
、:error
)を設定することで、詳細なログを特定の環境でのみ出力するようにできます。デフォルトのログレベルは:info
です。 silence
- このオプションを指定すると、ブロック内にあるベンチマークのタイミング情報以外のログ出力をすべて抑制します。
オプションの例
def process
Rails.benchmark("=== Processing invoices ===", level: :debug, silence: true) do
logger.debug("=== This won't be logged ===")
process_invoices
logger.debug("=== This won't be logged ===")
end
end
上のメソッドは、コストの高い処理に要した時間をログレベル:debug
で表示します。Rails.benchmark
ブロック内の他のログはサーバーログに出力されません。今回の例では、Rails.benchmark
ブロック内の最初と最後の行が出力されなくなります。
Started GET "/companies/1/invoices" for ::1 at 2021-02-24 16:13:44 +0530
Processing by CompaniesController#invoices as HTML
Parameters: {"id"=>"1"}
=== Processing invoices === (404.6ms)
Rendered companies/invoices.html.erb within layouts/application (Duration: 3.4ms | Allocations: 1111)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered layout layouts/application.html.erb (Duration: 18.5ms | Allocations: 7370)
Completed 200 OK in 458ms (Views: 22.7ms | ActiveRecord: 0.9ms | Allocations: 14473)
概要
原著者の許諾を得て翻訳・公開いたします。