edge
更多信息请访问 rubyonrails.org: 更多 Ruby on Rails

Active Support仪表盘

Active Support是Rails核心的一部分,提供了Ruby语言扩展、实用工具和其他功能。其中之一就是仪表盘API,可以在应用程序内部测量发生在Ruby代码中的某些操作,例如Rails应用程序或框架本身内部的操作。然而,它不仅限于Rails,如果需要的话,也可以在其他Ruby脚本中独立使用。

在本指南中,您将学习如何使用Active Support的仪表盘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|
  # 自定义内容
  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|
  # 自定义内容
  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(以毫秒为单位)
  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(以毫秒为单位)
  event.payload   # => {:extra=>information}

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

您还可以订阅与正则表达式匹配的事件。这使您可以同时订阅多个事件。以下是如何订阅来自ActionController的所有事件:

ActiveSupport::Notifications.subscribe(/action_controller/) do |*args|
  # 检查所有ActionController事件
end

3 在浏览器中查看仪表盘的时间

Rails实现了服务器计时标准,以使时间信息在Web浏览器中可用。要启用此功能,请编辑您的环境配置(通常是development.rb,因为它在开发中使用最多),并包含以下内容:

  config.server_timing = true

配置完成后(包括重新启动服务器),您可以转到浏览器的开发者工具窗格,然后选择网络并重新加载页面。然后,您可以选择Rails服务器的任何请求,在计时选项卡中查看服务器计时。有关此操作的示例,请参阅Firefox文档

4 Rails框架钩子

在Ruby on Rails框架中,提供了许多用于常见事件的钩子。以下是这些事件及其有效负载的详细信息。

4.1 Action Controller

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 Action Controller — 缓存

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 Action Dispatch

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 Action View

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 从缓存中获取的部分的数量

只有在使用cached: true渲染集合时,才会包含:cache_hits键。 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 由Mail gem生成的消息ID
: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: "...", # 省略以保持简洁
  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 如果此读取是命中的话
: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

仅在使用MemCacheStoreRedisCacheStore时触发此事件。

: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

仅在使用RedisCacheStoreFileStoreMemoryStore时触发此事件。

: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 — Messages

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 — 存储服务

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 文件或 Blob 是否存在

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 一个包含两个元素的数组。异常类名和消息
:exception_object 异常对象

6 创建自定义事件

添加自己的事件也很容易。Active Support 将为您处理所有繁重的工作。只需调用 ActiveSupport::Notifications.instrument,并提供一个 namepayload 和一个块。通知将在块返回后发送。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 指南,以验证问题是否已经修复或尚未修复。 请参阅 Ruby on Rails 指南准则 以了解样式和规范。

如果您发现需要修复但无法自行修复的问题,请 提交问题

最后但同样重要的是,欢迎您在 官方 Ruby on Rails 论坛 上讨论有关 Ruby on Rails 文档的任何问题。