v7.1.3.2
更多資訊請至 rubyonrails.org: 更多 Ruby on Rails

主動支援儀器

主動支援是核心 Rails 的一部分,提供 Ruby 語言擴充、工具程式和其他項目。它包含的項目之一是儀器 API,可在應用程式內部使用,以衡量 Ruby 程式碼中發生的特定動作,例如 Rails 應用程式或架構本身中的動作。不過,它不限於 Rails。如果需要,可以在其他 Ruby 腳本中獨立使用。

在本指南中,您將學習如何使用主動支援的儀器 API 來衡量 Rails 和其他 Ruby 程式碼中的事件。

閱讀本指南後,您將知道

1 儀器簡介

Active Support 提供的儀器 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|
  # your own custom stuff
  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 的準確性,無法計算出精確的經過時間,請使用 ActiveSupport::Notifications.monotonic_subscribe。指定的區塊會收到與上述相同的引數,但 startedfinished 會有準確的單調時間值,而不是時鐘時間。

ActiveSupport::Notifications.monotonic_subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
  # your own custom stuff
  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.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 |event|
  event.name      # => "process_action.action_controller"
  event.duration  # => 10 (in milliseconds)
  event.payload   # => {:extra=>information}

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

您也可以訂閱符合正規表示式的事件。這讓您可以一次訂閱多個事件。以下是訂閱來自 ActionController 的所有事件的方法

ActiveSupport::Notifications.subscribe(/action_controller/) do |*args|
  # inspect all ActionController events
end

3 Rails 架構掛鉤

在 Ruby on Rails 架構中,為常見事件提供了許多掛鉤。這些事件及其有效負載的詳細資訊如下。

3.1 Action Controller

3.1.1 start_processing.action_controller

金鑰
:controller 控制器名稱
:action 動作
:request ActionDispatch::Request 物件
: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"
}

3.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
}

3.1.3 send_file.action_controller

金鑰
:path 檔案的完整路徑

呼叫者可以新增其他金鑰。

3.1.4 send_data.action_controller

ActionController 沒有將任何特定資訊新增到有效負載中。所有選項都會傳遞到有效負載。

3.1.5 redirect_to.action_controller

金鑰
:status HTTP 回應碼
:location 要重新導向到的 URL
:request ActionDispatch::Request 物件
{
  status: 302,
  location: "https://127.0.0.1:3000/posts/new",
  request: <ActionDispatch::Request:0x00007ff1cb9bd7b8>
}

3.1.6 halted_callback.action_controller

金鑰
:filter 中止動作的篩選器
{
  filter: ":halting_filter"
}

3.1.7 unpermitted_parameters.action_controller

金鑰
:keys 不允許的鍵
:context 包含下列鍵的雜湊::controller:action:params:request

3.2 Action Controller — 快取

3.2.1 write_fragment.action_controller

金鑰
:key 完整的鍵
{
  key: 'posts/1-dashboard-view'
}

3.2.2 read_fragment.action_controller

金鑰
:key 完整的鍵
{
  key: 'posts/1-dashboard-view'
}

3.2.3 expire_fragment.action_controller

金鑰
:key 完整的鍵
{
  key: 'posts/1-dashboard-view'
}

3.2.4 exist_fragment?.action_controller

金鑰
:key 完整的鍵
{
  key: 'posts/1-dashboard-view'
}

3.3 Action Dispatch

3.3.1 process_middleware.action_dispatch

金鑰
:middleware 中間件名稱

3.3.2 redirect.action_dispatch

金鑰
:status HTTP 回應碼
:location 要重新導向到的 URL
:request ActionDispatch::Request 物件

3.3.3 request.action_dispatch

金鑰
:request ActionDispatch::Request 物件

3.4 Action View

3.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" }
}

3.4.2 render_partial.action_view

金鑰
:identifier 範本的完整路徑
:locals 傳遞給範本的局部變數
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/_form.html.erb",
  locals: { foo: "bar" }
}

3.4.3 render_collection.action_view

金鑰
:identifier 範本的完整路徑
:count 集合大小
:cache_hits 從快取擷取的部分數量

僅當集合使用 cached: true 進行呈現時,才會包含 :cache_hits 鍵。

{
  identifier: "/Users/adam/projects/notifications/app/views/posts/_post.html.erb",
  count: 3,
  cache_hits: 0
}

3.4.4 render_layout.action_view

金鑰
:identifier 範本的完整路徑
{
  identifier: "/Users/adam/projects/notifications/app/views/layouts/application.html.erb"
}

3.5 Active Record

3.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
}

3.5.2 strict_loading_violation.active_record

此事件僅在 config.active_record.action_on_strict_loading_violation 設為 :log 時才會發出。

金鑰
:owner 啟用 strict_loading 的模型
:reflection 嘗試載入關聯的反射

3.5.3 instantiation.active_record

金鑰
:record_count 實例化的記錄數
:class_name 記錄的類別
{
  record_count: 1,
  class_name: "User"
}

3.6 Action Mailer

3.6.1 deliver.action_mailer

金鑰
:mailer 郵件寄送器類別名稱
:message_id 郵件 ID,由 Mail 寶石產生
:subject 郵件主旨
:to 郵件收件人地址
:from 郵件寄件人地址
:bcc 郵件密件副本地址
: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: "...", # omitted for brevity
  perform_deliveries: true
}

3.6.2 process.action_mailer

金鑰
:mailer 郵件寄送器類別名稱
:action 動作
:args 參數
{
  mailer: "Notification",
  action: "welcome_email",
  args: []
}

3.7 Active Support — 快取

3.7.1 cache_read.active_support

金鑰
:key 儲存庫中使用的金鑰
:store 儲存庫類別名稱
:hit 此讀取是否命中
:super_operation 如果讀取是使用 fetch 進行,則為 :fetch

3.7.2 cache_read_multi.active_support

金鑰
:key 儲存庫中使用的金鑰
:store 儲存庫類別名稱
:hits 快取命中的金鑰
:super_operation 如果讀取是使用 fetch_multi 進行,則為 :fetch_multi

3.7.3 cache_generate.active_support

僅當呼叫 fetch 並帶有區塊時,才會發出此事件。

金鑰
:key 儲存庫中使用的金鑰
:store 儲存庫類別名稱

傳遞給 fetch 的選項會在寫入儲存時與有效負載合併。

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

3.7.4 cache_fetch_hit.active_support

僅當呼叫 fetch 並帶有區塊時,才會發出此事件。

金鑰
:key 儲存庫中使用的金鑰
:store 儲存庫類別名稱

傳遞給 fetch 的選項會與有效負載合併。

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

3.7.5 cache_write.active_support

金鑰
:key 儲存庫中使用的金鑰
:store 儲存庫類別名稱

快取儲存也可能新增自己的資料。

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

3.7.6 cache_write_multi.active_support

金鑰
:key 寫入儲存的鍵和值
:store 儲存庫類別名稱

3.7.7 cache_increment.active_support

僅在使用 MemCacheStoreRedisCacheStore 時才會發出此事件。

金鑰
:key 儲存庫中使用的金鑰
:store 儲存庫類別名稱
:amount 遞增量
{
  key: "bottles-of-beer",
  store: "ActiveSupport::Cache::RedisCacheStore",
  amount: 99
}

3.7.8 cache_decrement.active_support

僅在使用 Memcached 或 Redis 快取儲存時才會發出此事件。

金鑰
:key 儲存庫中使用的金鑰
:store 儲存庫類別名稱
:amount 遞減量
{
  key: "bottles-of-beer",
  store: "ActiveSupport::Cache::RedisCacheStore",
  amount: 1
}

3.7.9 cache_delete.active_support

金鑰
:key 儲存庫中使用的金鑰
:store 儲存庫類別名稱
{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

3.7.10 cache_delete_multi.active_support

金鑰
:key 儲存庫中使用的金鑰
:store 儲存庫類別名稱

3.7.11 cache_delete_matched.active_support

僅在使用 RedisCacheStoreFileStoreMemoryStore 時才會發出此事件。

金鑰
:key 使用的鍵模式
:store 儲存庫類別名稱
{
  key: "posts/*",
  store: "ActiveSupport::Cache::RedisCacheStore"
}

3.7.12 cache_cleanup.active_support

僅在使用 MemoryStore 時才會發出此事件。

金鑰
:store 儲存庫類別名稱
:size 清除前快取中的條目數
{
  store: "ActiveSupport::Cache::MemoryStore",
  size: 9001
}

3.7.13 cache_prune.active_support

僅在使用 MemoryStore 時才會發出此事件。

金鑰
:store 儲存庫類別名稱
:key 快取的目標大小(以位元組為單位)
:from 修剪前快取的大小(以位元組為單位)
{
  store: "ActiveSupport::Cache::MemoryStore",
  key: 5000,
  from: 9001
}

3.7.14 cache_exist?.active_support

金鑰
:key 儲存庫中使用的金鑰
:store 儲存庫類別名稱
{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

3.8 Active Support — 訊息

3.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" },
}

3.9 Active Job

3.9.1 enqueue_at.active_job

金鑰
:adapter 處理作業的 QueueAdapter 物件
:job 作業物件

3.9.2 enqueue.active_job

金鑰
:adapter 處理作業的 QueueAdapter 物件
:job 作業物件

3.9.3 enqueue_retry.active_job

金鑰
:job 作業物件
:adapter 處理作業的 QueueAdapter 物件
:error 導致重試的錯誤
:wait 重試的延遲時間

3.9.4 enqueue_all.active_job

金鑰
:adapter 處理作業的 QueueAdapter 物件
:jobs 作業物件陣列

3.9.5 perform_start.active_job

金鑰
:adapter 處理作業的 QueueAdapter 物件
:job 作業物件

3.9.6 perform.active_job

金鑰
:adapter 處理作業的 QueueAdapter 物件
:job 作業物件
:db_runtime 執行資料庫查詢所花費的時間(毫秒)

3.9.7 retry_stopped.active_job

金鑰
:adapter 處理作業的 QueueAdapter 物件
:job 作業物件
:error 導致重試的錯誤

3.9.8 discard.active_job

金鑰
:adapter 處理作業的 QueueAdapter 物件
:job 作業物件
:error 導致捨棄的錯誤

3.10 Action Cable

3.10.1 perform_action.action_cable

金鑰
:channel_class 頻道類別名稱
:action 動作
:data 資料雜湊

3.10.2 transmit.action_cable

金鑰
:channel_class 頻道類別名稱
:data 資料雜湊
:via 透過

3.10.3 transmit_subscription_confirmation.action_cable

金鑰
:channel_class 頻道類別名稱

3.10.4 transmit_subscription_rejection.action_cable

金鑰
:channel_class 頻道類別名稱

3.10.5 broadcast.action_cable

金鑰
:broadcasting 命名廣播
:message 訊息雜湊
:coder 編碼器

3.11 Active Storage

3.11.1 preview.active_storage

金鑰
:key 安全權杖

3.11.2 transform.active_storage

3.11.3 analyze.active_storage

金鑰
:analyzer 分析器名稱,例如 ffprobe

3.12 Active Storage — 儲存服務

3.12.1 service_upload.active_storage

金鑰
:key 安全權杖
:service 服務名稱
:checksum 檢查碼用於確保完整性

3.12.2 service_streaming_download.active_storage

金鑰
:key 安全權杖
:service 服務名稱

3.12.3 service_download_chunk.active_storage

金鑰
:key 安全權杖
:service 服務名稱
:range 嘗試讀取的位元組範圍

3.12.4 service_download.active_storage

金鑰
:key 安全權杖
:service 服務名稱

3.12.5 service_delete.active_storage

金鑰
:key 安全權杖
:service 服務名稱

3.12.6 service_delete_prefixed.active_storage

金鑰
:prefix 金鑰字首
:service 服務名稱

3.12.7 service_exist.active_storage

金鑰
:key 安全權杖
:service 服務名稱
:exist 檔案或 blob 是否存在

3.12.8 service_url.active_storage

金鑰
:key 安全權杖
:service 服務名稱
:url 產生的網址

3.12.9 service_update_metadata.active_storage

僅在使用 Google Cloud Storage 服務時才會發出此事件。

金鑰
:key 安全權杖
:service 服務名稱
:content_type HTTP Content-Type 欄位
:disposition HTTP Content-Disposition 欄位

3.13 Action Mailbox

3.13.1 process.action_mailbox

金鑰
:mailbox 繼承自 ActionMailbox::Base 的 Mailbox 類別實例
:inbound_email 雜湊,其中包含有關正在處理的內部電子郵件的資料
{
  mailbox: #<RepliesMailbox:0x00007f9f7a8388>,
  inbound_email: {
    id: 1,
    message_id: "[email protected]",
    status: "processing"
  }
}

3.14 Railties

3.14.1 load_config_initializer.railties

金鑰
:initializer config/initializers 中已載入的初始化程式路徑

3.15 Rails

3.15.1 deprecation.rails

金鑰
:message 不建議使用的警告
:callstack 不建議使用的來源
:gem_name 報告不建議使用的寶石名稱
:deprecation_horizon 將移除不建議使用行為的版本

4 例外

如果在任何儀器化過程中發生例外,酬載將包含有關它的資訊。

金鑰
:exception 包含兩個元素的陣列。例外類別名稱和訊息
:exception_object 例外物件

5 建立自訂事件

新增自己的事件也很容易。Active Support 會為您處理所有繁重的工作。只需呼叫 ActiveSupport::Notifications.instrument,並提供 namepayload 和區塊。通知會在區塊傳回後傳送。Active Support 會產生開始和結束時間,並新增儀器的唯一 ID。傳遞到 instrument 呼叫的所有資料都會傳遞到 payload 中。

以下是範例

ActiveSupport::Notifications.instrument "my.custom.event", this: :data do
  # do your custom stuff here
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 的事件。

回饋

我們鼓勵您協助提升本指南的品質。

如果您發現任何錯字或事實錯誤,請協助我們修正。首先,您可以閱讀我們的 文件貢獻 部分。

您也可能會發現不完整或過時的內容。請為 main 新增任何遺漏的文件。請務必先查看 Edge Guides,以驗證問題是否已在 main 分支中修正。查看 Ruby on Rails Guides Guidelines 以了解樣式和慣例。

如果您發現需要修正的內容,但無法自行修正,請 開啟問題

最後,歡迎在 官方 Ruby on Rails 論壇 上討論任何與 Ruby on Rails 文件相關的議題。