Active SupportはRailsのコア機能のひとつであり、Ruby言語の拡張、ユーティリティなどを提供するものです。Active Supportに含まれているInstrumentation APIは、Rubyコードで発生する特定の動作の計測に利用できます。Railsアプリケーション内部やフレームワーク自身も計測できますが、必要であればRails以外のRubyスクリプトなども測定できます。
本ガイドでは、RailsなどのRubyコード内のイベント計測に使う、Active Support内のInstrumentation APIについて解説します。
このガイドの内容:
Active Supportが提供するInstrumentation APIを使ってフックを開発すると、他の開発者がそこにフックできるようになります。フックの多くは、Railsフレームワーク向けです。このAPIをアプリケーションで実装すると、アプリケーション(またはRubyコード片)内部でイベントが発生したときに通知を受け取れるよう他の開発者が設定できます。
たとえばActive Recordには、データベースへのSQLクエリが発行されるたびに呼び出されるフックが用意されていますこのフックをサブスクライブ(購読)すると、特定のアクションでのクエリ実行数を追跡できます。他に、コントローラのアクション実行中に呼び出されるフックもあります。このフックは、たとえば特定のアクション実行に要する時間の測定に利用できます。
もちろん、アプリケーション内に独自のイベントを作成し、後で自分でサブスクライブして測定することもできます。
Ruby on Railsでは、フレームワーク内の主なイベント向けのフックが多数提供されています詳しくは次をご覧ください。
キー | 値 |
---|---|
:key |
完全なキー |
{ key: 'posts/1-dashboard-view' }
キー | 値 |
---|---|
:key |
完全なキー |
{ key: 'posts/1-dashboard-view' }
Key | Value |
---|---|
:key |
完全なキー |
{ key: 'posts/1-dashboard-view' }
キー | 値 |
---|---|
:key |
完全なキー |
{ key: 'posts/1-dashboard-view' }
キー | 値 |
---|---|
:path |
完全なパス |
{ path: '/users/1' }
キー | 値 |
---|---|
:path |
完全なパス |
{ path: '/users/1' }
キー | 値 |
---|---|
:controller |
コントローラ名 |
:action |
アクション |
:params |
リクエストパラメータのハッシュ(フィルタされたパラメータは含まない) |
:headers |
リクエスト ヘッダー |
:format |
html/js/json/xml など |
:method |
HTTP リクエストメソッド(verb) |
:path |
リクエスト パス |
{ controller: "PostsController", action: "new", params: { "action" => "new", "controller" => "posts" }, headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>, format: :html, method: "GET", path: "/posts/new" }
キー | 値 |
---|---|
:controller |
コントローラ名 |
:action |
アクション |
:params |
リクエストパラメータのハッシュ(フィルタされたパラメータは含まない) |
:headers |
リクエスト ヘッダー |
:format |
html/js/json/xml など |
:method |
HTTP リクエストメソッド(verb) |
:path |
リクエスト パス |
:status |
HTTP ステータスコード |
:view_runtime |
ビューでかかった合計時間(ms) |
:db_runtime |
データベースへのクエリ実行にかかった時間(ms) |
{ controller: "PostsController", action: "index", params: {"action" => "index", "controller" => "posts"}, headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>, format: :html, method: "GET", path: "/posts", status: 200, view_runtime: 46.848, db_runtime: 0.157 }
キー | 値 |
---|---|
:path |
ファイルへの完全なパス |
呼び出し側でキーが追加される可能性があります。
ActionController
自身は、ペイロードに情報を持ちません。オプションは、すべてペイロード経由で渡されます。
キー | 値 |
---|---|
:status |
HTTP レスポンス コード |
:location |
リダイレクト先URL |
{ status: 302, location: "http://localhost:3000/posts/new" }
キー | 値 |
---|---|
:filter |
アクションを停止させたフィルタ |
{ filter: ":halting_filter" }
キー | 値 |
---|---|
:identifier |
テンプレートへの完全なパス |
:layout |
該当のレイアウト |
{ identifier: "/Users/adam/projects/notifications/app/views/posts/index.html.erb", layout: "layouts/application" }
キー | 値 |
---|---|
:identifier |
テンプレートへの完全なパス |
{ identifier: "/Users/adam/projects/notifications/app/views/posts/_form.html.erb" }
キー | 値 |
---|---|
:sql |
SQL文 |
:name |
操作の名前 |
:connection_id |
self.object_id |
:binds |
パラメータの割り当て(バインド) |
アダプタも独自のデータを追加します。
{ sql: "SELECT \"posts\".* FROM \"posts\" ", name: "Post Load", connection_id: 70307250813140, binds: [] }
Key | Value |
---|---|
:record_count |
レコードのインスタンス数 |
:class_name |
レコードのクラス |
{ record_count: 1, class_name: "User" }
キー | 値 |
---|---|
:mailer |
メイラークラス名 |
:message_id |
Mail gemが生成したメッセージID |
:subject |
メールの件名 |
:to |
メールの宛先 |
:from |
メールの差出人 |
:bcc |
メールのBCCアドレス |
:cc |
メールのCCアドレス |
:date |
メールの日付 |
:mail |
メールのエンコード形式 |
{ mailer: "Notification", message_id: "4f5b5491f1774_181b23fc3d4434d38138e5@mba.local.mail", subject: "Rails Guides", to: ["users@rails.com", "ddh@rails.com"], from: ["me@rails.com"], date: Sat, 10 Mar 2012 14:18:09 +0100, mail: "..." #(長いので省略) }
キー | 値 |
---|---|
:mailer |
メイラークラス名 |
:message_id |
Mail gemが生成したメッセージID |
:subject |
メールの件名 |
:to |
メールの宛先 |
:from |
メールの差出人 |
:bcc |
メールのBCCアドレス |
:cc |
メールのCCアドレス |
:date |
メールの日付 |
:mail |
メールのエンコード形式 |
{ mailer: "Notification", message_id: "4f5b5491f1774_181b23fc3d4434d38138e5@mba.local.mail", subject: "Rails Guides", to: ["users@rails.com", "ddh@rails.com"], from: ["me@rails.com"], date: Sat, 10 Mar 2012 14:18:09 +0100, mail: "..." #(長いので省略) }
キー | 値 |
---|---|
:key |
ストアで使われるキー |
:hit |
ヒットしたかどうか |
:super_operation |
読み出しで#fetch が指定されている場合に:fetch を追加 |
このイベントは、#fetch
をブロック付きで使用した場合にのみ使われます。
キー | 値 |
---|---|
:key |
ストアで使われるキー |
fetchに渡されたオプションは、ストアへの書き込み時にペイロードとマージされます。
{ key: 'name-of-complicated-computation' }
このイベントは、#fetch
をブロック付きで使用した場合にのみ使われます。
キー | 値 |
---|---|
:key |
ストアで使われるキー |
fetchに渡されたオプションは、ペイロードとマージされます。
{ key: 'name-of-complicated-computation' }
キー | 値 |
---|---|
:key |
ストアで使われるキー |
キャッシュストアが独自のキーを追加することがあります。
{ key: 'name-of-complicated-computation' }
キー | 値 |
---|---|
:key |
ストアで使われるキー |
{ key: 'name-of-complicated-computation' }
キー | 値 |
---|---|
:key |
ストアで使われるキー |
{ key: 'name-of-complicated-computation' }
キー | 値 |
---|---|
:adapter |
ジョブを処理するQueueAdapterオブジェクト |
:job |
Jobオブジェクト |
キー | 値 |
---|---|
:adapter |
ジョブを処理するQueueAdapterオブジェクト |
:job |
Jobオブジェクト |
キー | 値 |
---|---|
:adapter |
ジョブを処理するQueueAdapterオブジェクト |
:job |
Jobオブジェクト |
キー | 値 |
---|---|
:adapter |
ジョブを処理するQueueAdapterオブジェクト |
:job |
Jobオブジェクト |
キー | 値 |
---|---|
:initializer |
config/initializers から読み込まれたイニシャライザへのパス |
キー | 値 |
---|---|
:message |
非推奨機能の警告メッセージ |
:callstack |
非推奨警告の発生元 |
イベントは簡単にサブスクライブできます。ActiveSupport::Notifications.subscribe
をブロック付きで
記述すれば、すべての通知をリッスンできます。
ブロックでは以下の引数を利用できます。
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, started, finished, unique_id, data| # 自分のコードをここに書く Rails.logger.info "#{name} Received!" end
ブロックの引数を毎回定義しなくても済むよう、次のようなブロック付きの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 (in milliseconds) event.payload # => {:extra=>information} Rails.logger.info "#{event} Received!" end
ほとんどのデータはすぐに利用できます。次はデータの取り出し方の例です。
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |*args| data = args.extract_options! data # { extra: :information } end
正規表現に一致するイベントだけをサブスクライブすることもできます。
さまざまなイベントを一括でサブスクライブしたい場合に便利です。次は、ActionController
のイベントをすべて登録する場合の例です。
ActiveSupport::Notifications.subscribe /action_controller/ do |*args| # ActionControllerの全イベントをチェック end
独自のイベントを自由に追加できます。イベント追加は、ActiveSupport::Notifications
メソッドで
すべてまかなえます。name
、payload
、ブロックを指定してinstrument
を呼び出すだけで追加完了します。
通知は、ブロックが戻ってから送信されます。ActiveSupport
では、開始時刻、終了時刻、
ユニーク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
独自のイベントを作成するときは、Railsの規則に従ってください。形式は「event.library
」を使います
たとえば、アプリケーションがツイートを送信するのであれば、イベント名はtweet.twitter
となります。
Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。