edge
詳細はrubyonrails.orgで: もっとRuby on Rails

アクティブサポートインストゥルメンテーション

アクティブサポートは、Rubyの言語拡張、ユーティリティ、その他のものを提供する、Railsのコアの一部です。その中には、Railsアプリケーションやフレームワーク自体内部のRubyコード内で発生する特定のアクションを計測するために使用できるインストゥルメンテーションAPIが含まれています。ただし、Railsに限定されるものではありません。必要に応じて、他のRubyスクリプトでも独立して使用することができます。

このガイドでは、アクティブサポートのインストゥルメンテーションAPIを使用して、Railsや他のRubyコード内のイベントを計測する方法について学びます。

このガイドを読み終えると、以下のことがわかります:

1 インストゥルメンテーションの紹介

アクティブサポートが提供するインストゥルメンテーションAPIを使用すると、開発者は他の開発者がフックにフックすることができるフックを提供することができます。Railsフレームワーク内には、これらのフックがいくつかあります。このAPIを使用すると、開発者は自分のアプリケーションや他のRubyコード内で特定のイベントが発生したときに通知を受けることができます。

たとえば、Active Record内には、データベース上でActive RecordがSQLクエリを使用するたびに呼び出されるフックがあります。このフックはサブスクライブされ、特定のアクション中のクエリの数を追跡するために使用することができます。また、コントローラのアクションの処理に関する別のフックもあります。これは、特定のアクションがどれくらいの時間を要したかを追跡するために使用することができます。

また、後でサブスクライブすることができるアプリケーション内で独自のイベントを作成することもできます。

2 イベントにサブスクライブする

イベントにサブスクライブするのは簡単です。ActiveSupport::Notifications.subscribeを使用して、通知をリッスンするためのブロックを使用します。

ブロックは以下の引数を受け取ります:

  • イベントの名前
  • 開始時刻
  • 終了時刻
  • イベントを発生させたインストゥルメンタの一意のID
  • イベントのペイロード
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
  # あなた自身のカスタムな処理
  Rails.logger.info "#{name} Received! (started: #{started}, finished: #{finished})" # process_action.action_controller Received (started: 2019-05-05 13:43:57 -0800, finished: 2019-05-05 13:43:58 -0800)
end

startedfinishedの正確な経過時間を計算するためにstartedfinishedの正確な経過時間を計算するためにActiveSupport::Notifications.monotonic_subscribe[]を使用する場合は、上記と同じ引数がブロックに渡されますが、startedfinishedは壁時計の時間ではなく、正確な単調増加の時間を持つ値になります。

ActiveSupport::Notifications.monotonic_subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
  # あなた自身のカスタムな処理
  Rails.logger.info "#{name} Received! (started: #{started}, finished: #{finished})" # process_action.action_controller Received (started: 1560978.425334, finished: 1560979.429234)
end

毎回ブロック引数を定義するのは面倒です。ActiveSupport::Notifications::Eventを使用して、ブロック引数からActiveSupport::Notifications::Eventを簡単に作成できます。

ActiveSupport::Notifications.subscribe "process_action.action_controller" do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)

  event.name      # => "process_action.action_controller"
  event.duration  # => 10 (ミリ秒単位)
  event.payload   # => {:extra=>information}

  Rails.logger.info "#{event} Received!"
end

また、1つの引数のみを受け取るブロックを渡すこともできます。この場合、イベントオブジェクトが渡されます。

ActiveSupport::Notifications.subscribe "process_action.action_controller" do |event|
  event.name      # => "process_action.action_controller"
  event.duration  # => 10 (ミリ秒単位)
  event.payload   # => {:extra=>information}

  Rails.logger.info "#{event} Received!"
end

正規表現に一致するイベントにもサブスクライブすることができます。これにより、複数のイベントに一度にサブスクライブすることができます。たとえば、ActionControllerからのすべてのイベントにサブスクライブするには、次のようにします。

ActiveSupport::Notifications.subscribe(/action_controller/) do |*args|
  # ActionControllerのすべてのイベントを調査する
end

3 ブラウザでインストゥルメンテーションのタイミングを表示する

Railsは、タイミング情報をWebブラウザで利用できるようにするために、Server Timingの標準を実装しています。有効にするには、環境設定(通常はdevelopment.rbが最も使用されるため)を編集して、次のようにします。

  config.server_timing = true

設定が完了したら(サーバーを再起動することも含む)、ブラウザの開発者ツールペインに移動し、ネットワークを選択してページをリロードします。その後、Railsサーバーへのリクエストを選択すると、タイミングタブでサーバータイミングが表示されます。これを行う例については、Firefoxのドキュメントを参照してください。

4 Railsフレームワークのフック

Ruby on Railsフレームワーク内には、一般的なイベントに対して提供されるフックがいくつかあります。これらのイベントとそのペイロードについては、以下で詳細に説明します。

4.1 アクションコントローラー

4.1.1 start_processing.action_controller

キー
:controller コントローラー名
:action アクション名
:params フィルタリングされていないリクエストパラメータのハッシュ
:headers リクエストヘッダー
:format html/js/json/xml など
:method HTTP リクエストの動詞
:path リクエストパス
{
  controller: "PostsController",
  action: "new",
  params: { "action" => "new", "controller" => "posts" },
  headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>,
  format: :html,
  method: "GET",
  path: "/posts/new"
}

4.1.2 process_action.action_controller

キー
:controller コントローラー名
:action アクション名
:params フィルタリングされていないリクエストパラメータのハッシュ
:headers リクエストヘッダー
:format html/js/json/xml など
:method HTTP リクエストの動詞
:path リクエストパス
:request ActionDispatch::Request オブジェクト
:response ActionDispatch::Response オブジェクト
:status HTTP ステータスコード
:view_runtime ビューでの実行時間(ミリ秒)
:db_runtime データベースクエリの実行時間(ミリ秒)
{
  controller: "PostsController",
  action: "index",
  params: {"action" => "index", "controller" => "posts"},
  headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>,
  format: :html,
  method: "GET",
  path: "/posts",
  request: #<ActionDispatch::Request:0x00007ff1cb9bd7b8>,
  response: #<ActionDispatch::Response:0x00007f8521841ec8>,
  status: 200,
  view_runtime: 46.848,
  db_runtime: 0.157
}

4.1.3 send_file.action_controller

キー
:path ファイルへの完全なパス

呼び出し元によって追加のキーが追加される場合があります。

4.1.4 send_data.action_controller

ActionController はペイロードに特定の情報を追加しません。すべてのオプションはペイロードに渡されます。

4.1.5 redirect_to.action_controller

キー
:status HTTP レスポンスコード
:location リダイレクト先の URL
:request ActionDispatch::Request オブジェクト
{
  status: 302,
  location: "http://localhost:3000/posts/new",
  request: <ActionDispatch::Request:0x00007ff1cb9bd7b8>
}

4.1.6 halted_callback.action_controller

キー
:filter アクションを停止したフィルター
{
  filter: ":halting_filter"
}

4.1.7 unpermitted_parameters.action_controller

キー
:keys 許可されていないキー
:context 以下のキーを持つハッシュ: :controller, :action, :params, :request

4.2 アクションコントローラー — キャッシュ

4.2.1 write_fragment.action_controller

キー
:key 完全なキー
{
  key: 'posts/1-dashboard-view'
}

4.2.2 read_fragment.action_controller

キー
:key 完全なキー
{
  key: 'posts/1-dashboard-view'
}

4.2.3 expire_fragment.action_controller

キー
:key 完全なキー
{
  key: 'posts/1-dashboard-view'
}

4.2.4 exist_fragment?.action_controller

キー
:key 完全なキー
{
  key: 'posts/1-dashboard-view'
}

4.3 アクションディスパッチ

4.3.1 process_middleware.action_dispatch

キー
:middleware ミドルウェアの名前

4.3.2 redirect.action_dispatch

キー
:status HTTP レスポンスコード
:location リダイレクト先の URL
:request ActionDispatch::Request オブジェクト

4.3.3 request.action_dispatch

キー
:request ActionDispatch::Request オブジェクト

4.4 アクションビュー

4.4.1 render_template.action_view

キー
:identifier テンプレートへの完全なパス
:layout 適用されるレイアウト
:locals テンプレートに渡されるローカル変数
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/index.html.erb",
  layout: "layouts/application",
  locals: { foo: "bar" }
}

4.4.2 render_partial.action_view

キー
:identifier テンプレートへの完全なパス
:locals テンプレートに渡されるローカル変数
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/_form.html.erb",
  locals: { foo: "bar" }
}

4.4.3 render_collection.action_view

キー
:identifier テンプレートへの完全なパス
:count コレクションのサイズ
:cache_hits キャッシュから取得されたパーシャルの数

:cache_hits キーは、コレクションが cached: true でレンダリングされる場合にのみ含まれます。 ruby { identifier: "/Users/adam/projects/notifications/app/views/posts/_post.html.erb", count: 3, cache_hits: 0 }

4.4.4 render_layout.action_view

キー
:identifier テンプレートのフルパス
{
  identifier: "/Users/adam/projects/notifications/app/views/layouts/application.html.erb"
}

4.5 Active Record

4.5.1 sql.active_record

キー
:sql SQLステートメント
:name 操作の名前
:connection コネクションオブジェクト
:binds バインドパラメータ
:type_casted_binds 型変換されたバインドパラメータ
:statement_name SQLステートメントの名前
:cached キャッシュされたクエリが使用された場合に true が追加されます

アダプタは独自のデータを追加することもあります。

{
  sql: "SELECT \"posts\".* FROM \"posts\" ",
  name: "Post Load",
  connection: <ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x00007f9f7a838850>,
  binds: [<ActiveModel::Attribute::WithCastValue:0x00007fe19d15dc00>],
  type_casted_binds: [11],
  statement_name: nil
}

4.5.2 strict_loading_violation.active_record

このイベントは、config.active_record.action_on_strict_loading_violation:log に設定されている場合にのみ発生します。

キー
:owner strict_loading が有効になっているモデル
:reflection ロードを試みた関連のリフレクション

4.5.3 instantiation.active_record

キー
:record_count インスタンス化されたレコードの数
:class_name レコードのクラス
{
  record_count: 1,
  class_name: "User"
}

4.6 Action Mailer

4.6.1 deliver.action_mailer

キー
:mailer メーラークラスの名前
:message_id メッセージのID、Mail gem によって生成される
:subject メールの件名
:to メールの宛先アドレス
:from メールの送信元アドレス
:bcc メールのBCCアドレス
:cc メールのCCアドレス
:date メールの日付
:mail メールのエンコードされた形式
:perform_deliveries このメッセージの配信が行われるかどうか
{
  mailer: "Notification",
  message_id: "[email protected]",
  subject: "Rails Guides",
  to: ["[email protected]", "[email protected]"],
  from: ["[email protected]"],
  date: Sat, 10 Mar 2012 14:18:09 +0100,
  mail: "...", # 省略
  perform_deliveries: true
}

4.6.2 process.action_mailer

キー
:mailer メーラークラスの名前
:action アクション
:args 引数
{
  mailer: "Notification",
  action: "welcome_email",
  args: []
}

4.7 Active Support — Caching

4.7.1 cache_read.active_support

キー
:key ストアで使用されるキー
:store ストアクラスの名前
:hit この読み取りがヒットした場合は true
:super_operation fetch で読み取りが行われた場合は :fetch

4.7.2 cache_read_multi.active_support

キー
:key ストアで使用されるキー
:store ストアクラスの名前
:hits キャッシュヒットのキー
:super_operation fetch_multi で読み取りが行われた場合は :fetch_multi

4.7.3 cache_generate.active_support

このイベントは、fetch がブロックとともに呼び出された場合にのみ発生します。

キー
:key ストアで使用されるキー
:store ストアクラスの名前

fetch に渡されたオプションは、ストアへの書き込み時にペイロードとマージされます。

{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.4 cache_fetch_hit.active_support

このイベントは、fetch がブロックとともに呼び出された場合にのみ発生します。

キー
:key ストアで使用されるキー
:store ストアクラスの名前

fetch に渡されたオプションは、ペイロードとマージされます。

{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.5 cache_write.active_support

キー
:key ストアで使用されるキー
:store ストアクラスの名前

キャッシュストアは独自のデータを追加することもあります。

{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.6 cache_write_multi.active_support

キー
:key ストアに書き込まれたキーと値
:store ストアクラスの名前

4.7.7 cache_increment.active_support

このイベントは、MemCacheStoreまたはRedisCacheStoreを使用している場合にのみ発生します。

キー
:key ストアで使用されるキー
:store ストアクラスの名前
:amount インクリメント量
{
  key: "bottles-of-beer",
  store: "ActiveSupport::Cache::RedisCacheStore",
  amount: 99
}

4.7.8 cache_decrement.active_support

このイベントは、MemcachedまたはRedisキャッシュストアを使用している場合にのみ発生します。

キー
:key ストアで使用されるキー
:store ストアクラスの名前
:amount デクリメント量
{
  key: "bottles-of-beer",
  store: "ActiveSupport::Cache::RedisCacheStore",
  amount: 1
}

4.7.9 cache_delete.active_support

キー
:key ストアで使用されるキー
:store ストアクラスの名前
{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.10 cache_delete_multi.active_support

キー
:key ストアで使用されるキー
:store ストアクラスの名前

4.7.11 cache_delete_matched.active_support

このイベントは、RedisCacheStoreFileStore、またはMemoryStoreを使用している場合にのみ発生します。

キー
:key 使用されるキーパターン
:store ストアクラスの名前
{
  key: "posts/*",
  store: "ActiveSupport::Cache::RedisCacheStore"
}

4.7.12 cache_cleanup.active_support

このイベントは、MemoryStoreを使用している場合にのみ発生します。

キー
:store ストアクラスの名前
:size クリーンアップ前のキャッシュのエントリ数
{
  store: "ActiveSupport::Cache::MemoryStore",
  size: 9001
}

4.7.13 cache_prune.active_support

このイベントは、MemoryStoreを使用している場合にのみ発生します。

キー
:store ストアクラスの名前
:key キャッシュのターゲットサイズ(バイト単位)
:from プルーニング前のキャッシュのサイズ(バイト単位)
{
  store: "ActiveSupport::Cache::MemoryStore",
  key: 5000,
  from: 9001
}

4.7.14 cache_exist?.active_support

キー
:key ストアで使用されるキー
:store ストアクラスの名前
{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.8 Active Support — メッセージ

4.8.1 message_serializer_fallback.active_support

キー
:serializer プライマリ(意図された)シリアライザ
:fallback フォールバック(実際の)シリアライザ
:serialized シリアライズされた文字列
:deserialized デシリアライズされた値
{
  serializer: :json_allow_marshal,
  fallback: :marshal,
  serialized: "\x04\b{\x06I\"\nHello\x06:\x06ETI\"\nWorld\x06;\x00T",
  deserialized: { "Hello" => "World" },
}

4.9 Active Job

4.9.1 enqueue_at.active_job

キー
:adapter ジョブを処理するQueueAdapterオブジェクト
:job ジョブオブジェクト

4.9.2 enqueue.active_job

キー
:adapter ジョブを処理するQueueAdapterオブジェクト
:job ジョブオブジェクト

4.9.3 enqueue_retry.active_job

キー
:job ジョブオブジェクト
:adapter ジョブを処理するQueueAdapterオブジェクト
:error リトライの原因となったエラー
:wait リトライの遅延

4.9.4 enqueue_all.active_job

キー
:adapter ジョブを処理するQueueAdapterオブジェクト
:jobs ジョブオブジェクトの配列

4.9.5 perform_start.active_job

キー
:adapter ジョブを処理するQueueAdapterオブジェクト
:job ジョブオブジェクト

4.9.6 perform.active_job

キー
:adapter ジョブを処理するQueueAdapterオブジェクト
:job ジョブオブジェクト
:db_runtime データベースクエリの実行にかかった時間(ミリ秒単位)

4.9.7 retry_stopped.active_job

キー
:adapter ジョブを処理するQueueAdapterオブジェクト
:job ジョブオブジェクト
:error リトライの原因となったエラー

4.9.8 discard.active_job

キー
:adapter ジョブを処理するQueueAdapterオブジェクト
:job ジョブオブジェクト
:error 破棄の原因となったエラー

4.10 Action Cable

4.10.1 perform_action.action_cable

キー
:channel_class チャネルクラスの名前
:action アクション
:data データのハッシュ

4.10.2 transmit.action_cable

キー
:channel_class チャネルクラスの名前
:data データのハッシュ
:via 経由

4.10.3 transmit_subscription_confirmation.action_cable

キー
:channel_class チャネルクラスの名前

4.10.4 transmit_subscription_rejection.action_cable

キー
:channel_class チャネルクラスの名前

4.10.5 broadcast.action_cable

キー
:broadcasting 名前付きのブロードキャスト
:message メッセージのハッシュ
:coder コーダー

4.11 Active Storage

4.11.1 preview.active_storage

キー
:key セキュアトークン

4.11.2 transform.active_storage

4.11.3 analyze.active_storage

キー
:analyzer アナライザーの名前、例:ffprobe

4.12 Active Storage — Storage Service

4.12.1 service_upload.active_storage

キー
:key セキュアトークン
:service サービスの名前
:checksum データの整合性を確保するためのチェックサム

4.12.2 service_streaming_download.active_storage

キー
:key セキュアトークン
:service サービスの名前

4.12.3 service_download_chunk.active_storage

キー
:key セキュアトークン
:service サービスの名前
:range 読み取ろうとしたバイト範囲

4.12.4 service_download.active_storage

キー
:key セキュアトークン
:service サービスの名前

4.12.5 service_delete.active_storage

キー
:key セキュアトークン
:service サービスの名前

4.12.6 service_delete_prefixed.active_storage

キー
:prefix キーのプレフィックス
:service サービスの名前

4.12.7 service_exist.active_storage

キー
:key セキュアトークン
:service サービスの名前
:exist ファイルまたはブロブが存在するかどうか

4.12.8 service_url.active_storage

キー
:key セキュアトークン
:service サービスの名前
:url 生成されたURL

4.12.9 service_update_metadata.active_storage

このイベントは、Google Cloud Storageサービスを使用している場合にのみ発生します。

キー
:key セキュアトークン
:service サービスの名前
:content_type HTTPのContent-Typeフィールド
:disposition HTTPのContent-Dispositionフィールド

4.13 Action Mailbox

4.13.1 process.action_mailbox

キー
:mailbox ActionMailbox::Baseを継承したMailboxクラスのインスタンス
:inbound_email 処理されているインバウンドメールに関するデータのハッシュ
{
  mailbox: #<RepliesMailbox:0x00007f9f7a8388>,
  inbound_email: {
    id: 1,
    message_id: "[email protected]",
    status: "processing"
  }
}

4.14 Railties

4.14.1 load_config_initializer.railties

キー
:initializer config/initializers内のロードされたイニシャライザのパス

4.15 Rails

4.15.1 deprecation.rails

キー
:message 廃止予定の警告メッセージ
:callstack 廃止予定の元の呼び出し元
:gem_name 廃止予定を報告しているgemの名前
:deprecation_horizon 廃止予定の動作が削除されるバージョン

5 例外

計測中に例外が発生した場合、ペイロードに関する情報が含まれます。

キー
:exception 2つの要素からなる配列。例外クラス名とメッセージ
:exception_object 例外オブジェクト

6 カスタムイベントの作成

独自のイベントを追加することも簡単です。Active Supportがすべての重い作業を代行してくれます。単にActiveSupport::Notifications.instrumentnamepayload、およびブロックと共に呼び出すだけです。ブロックが返った後に通知が送信されます。Active Supportは開始時間と終了時間を生成し、計測器の固有のIDを追加します。instrument呼び出しに渡されたすべてのデータがペイロードに含まれます。 以下は例です:

ActiveSupport::Notifications.instrument "my.custom.event", this: :data do
  # ここでカスタムの処理を行います
end

これで、次のようにこのイベントをリッスンできます:

ActiveSupport::Notifications.subscribe "my.custom.event" do |name, started, finished, unique_id, data|
  puts data.inspect # {:this=>:data}
end

また、ブロックを渡さずにinstrumentを呼び出すこともできます。これにより、他のメッセージング用途でインストルメンテーションインフラストラクチャを活用することができます。

ActiveSupport::Notifications.instrument "my.custom.event", this: :data

ActiveSupport::Notifications.subscribe "my.custom.event" do |name, started, finished, unique_id, data|
  puts data.inspect # {:this=>:data}
end

独自のイベントを定義する際には、Railsの規約に従う必要があります。フォーマットはevent.libraryです。アプリケーションがツイートを送信している場合、tweet.twitterという名前のイベントを作成する必要があります。

フィードバック

このガイドの品質向上にご協力ください。

タイポや事実の誤りを見つけた場合は、ぜひ貢献してください。 開始するには、ドキュメントへの貢献セクションを読んでください。

不完全なコンテンツや最新でない情報も見つかるかもしれません。 メインのドキュメントに不足しているドキュメントを追加してください。 修正済みかどうかは、まずEdge Guidesを確認してください。 スタイルと規約については、Ruby on Rails Guides Guidelinesを確認してください。

修正すべき点を見つけたが、自分で修正できない場合は、 問題を報告してください

そして最後に、Ruby on Railsのドキュメントに関するあらゆる議論は、公式のRuby on Railsフォーラムで大歓迎です。