更多内容 rubyonrails.org: More Ruby on Rails

Active Support 监测程序

Active Support 是 Rails 核心的一部分,提供 Ruby 语言扩展、实用方法等。其中包括一份监测 API,在应用中可以用它测度 Ruby 代码(如 Rails 应用或框架自身)中的特定操作。不过,这个 API 不限于只能在 Rails 中使用,如果愿意,也可以在其他 Ruby 脚本中使用。

本文教你如何使用 Active Support 中的监测 API 测度 Rails 和其他 Ruby 代码中的事件。

读完本文后,您将学到:

本文原文尚未完工!

1 监测程序简介

Active Support 提供的监测 API 允许开发者提供钩子,供其他开发者订阅。在 Rails 框架中,有很多。通过这个 API,开发者可以选择在应用或其他 Ruby 代码中发生特定事件时接收通知。

例如,Active Record 中有一个钩子,在每次使用 SQL 查询数据库时调用。开发者可以订阅这个钩子,记录特定操作执行的查询次数。还有一个钩子在控制器的动作执行前后调用,记录动作的执行时间。

在应用中甚至还可以自己创建事件,然后订阅。

2 Rails 框架中的钩子

Ruby on Rails 框架为很多常见的事件提供了钩子。下面详述。

3 Action Controller

3.1 write_fragment.action_controller

:key 完整的键
{
  key: 'posts/1-dashboard-view'
}

3.2 read_fragment.action_controller

:key 完整的键
{
  key: 'posts/1-dashboard-view'
}

3.3 expire_fragment.action_controller

:key 完整的键
{
  key: 'posts/1-dashboard-view'
}

3.4 exist_fragment?.action_controller

:key 完整的键
{
  key: 'posts/1-dashboard-view'
}

3.5 write_page.action_controller

:path 完整的路径
{
  path: '/users/1'
}

3.6 expire_page.action_controller

:path 完整的路径
{
  path: '/users/1'
}

3.7 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"
}

3.8 process_action.action_controller

:controller 控制器名
:action 动作名
:params 请求参数散列,不过滤
:headers 请求首部
:format html、js、json、xml 等
:method HTTP 请求方法
: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
}

3.9 send_file.action_controller

:path 文件的完整路径

调用方可以添加额外的键。

3.10 send_data.action_controller

ActionController 在载荷(payload)中没有任何特定的信息。所有选项都传到载荷中。

3.11 redirect_to.action_controller

:status HTTP 响应码
:location 重定向的 URL
{
  status: 302,
  location: "http://localhost:3000/posts/new"
}

3.12 halted_callback.action_controller

:filter 过滤暂停的动作
{
  filter: ":halting_filter"
}

4 Action View

4.1 render_template.action_view

:identifier 模板的完整路径
:layout 使用的布局
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/index.html.erb",
  layout: "layouts/application"
}

4.2 render-partial-action-view

:identifier 模板的完整路径
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/_form.html.erb"
}

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
}

5 Active Record

5.1 sql.active_record

:sql SQL 语句
:name 操作的名称
:connection_id self.object_id
:binds 绑定的参数

适配器也会添加数据。

{
  sql: "SELECT \"posts\".* FROM \"posts\" ",
  name: "Post Load",
  connection_id: 70307250813140,
  binds: []
}

5.2 instantiation.active_record

:record_count 实例化记录的数量
:class_name 记录所属的类
{
  record_count: 1,
  class_name: "User"
}

6 Action Mailer

6.1 receive.action_mailer

:mailer 邮件程序类的名称
:message_id 邮件的 ID,由 Mail gem 生成
:subject 邮件的主题
:to 邮件的收件地址
:from 邮件的发件地址
:bcc 邮件的密送地址
: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: "..." # 为了节省空间,省略
}

6.2 deliver.action_mailer

:mailer 邮件程序类的名称
:message_id 邮件的 ID,由 Mail gem 生成
:subject 邮件的主题
:to 邮件的收件地址
:from 邮件的发件地址
:bcc 邮件的密送地址
: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: "..." # 为了节省空间,省略
}

7 Active Support

7.1 cache_read.active_support

:key 存储器中使用的键
:hit 是否读取了缓存
:super_operation 如果使用 #fetch 读取了,添加 :fetch

7.2 cache_generate.active_support

仅当使用块调用 #fetch 时使用这个事件。

:key 存储器中使用的键

写入存储器时,传给 fetch 的选项会合并到载荷中。

{
  key: 'name-of-complicated-computation'
}

7.3 cache_fetch_hit.active_support

仅当使用块调用 #fetch 时使用这个事件。

:key 存储器中使用的键

传给 fetch 的选项会合并到载荷中。

{
  key: 'name-of-complicated-computation'
}

7.4 cache_write.active_support

:key 存储器中使用的键

缓存存储器可能会添加其他键。

{
  key: 'name-of-complicated-computation'
}

7.5 cache_delete.active_support

:key 存储器中使用的键
{
  key: 'name-of-complicated-computation'
}

7.6 cache_exist?.active_support

:key 存储器中使用的键
{
  key: 'name-of-complicated-computation'
}

8 Active Job

8.1 enqueue_at.active_job

:adapter 处理作业的 QueueAdapter 对象
:job 作业对象

8.2 enqueue.active_job

:adapter 处理作业的 QueueAdapter 对象
:job 作业对象

8.3 perform_start.active_job

:adapter 处理作业的 QueueAdapter 对象
:job 作业对象

8.4 perform.active_job

:adapter 处理作业的 QueueAdapter 对象
:job 作业对象

9 Railties

9.1 load_config_initializer.railties

:initializer 从 config/initializers 中加载的初始化脚本的路径

10 Rails

10.1 deprecation.rails

:message 弃用提醒
:callstack 弃用的位置

11 订阅事件

订阅事件是件简单的事,在 ActiveSupport::Notifications.subscribe 的块中监听通知即可。

这个块接收下述参数:

  • 事件的名称

  • 开始时间

  • 结束时间

  • 事件的唯一 ID

  • 载荷(参见前述各节)

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

12 自定义事件

自己添加事件也很简单,繁重的工作都由 ActiveSupport::Notifications 代劳,我们只需调用 instrument,并传入 namepayload 和一个块。通知在块返回后发送。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

反馈

我们鼓励您帮助提高本指南的质量。

如果看到如何错字或错误,请反馈给我们。 您可以阅读我们的文档贡献指南。

您还可能会发现内容不完整或不是最新版本。 请添加缺失文档到 master 分支。请先确认 Edge Guides 是否已经修复。 关于用语约定,请查看Ruby on Rails 指南指导

无论什么原因,如果你发现了问题但无法修补它,请创建 issue

最后,欢迎到 rubyonrails-docs 邮件列表参与任何有关 Ruby on Rails 文档的讨论。

中文翻译反馈

贡献:https://github.com/ruby-china/guides