Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails: Rails.benchmarkメソッドをどこからでも呼び出せるようになった(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

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)

関連記事

Railsの使わない機能をオフにする(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。