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: 'posts/1-dashboard-view'
}
3.2 read_fragment.action_controller
{
key: 'posts/1-dashboard-view'
}
3.3 expire_fragment.action_controller
{
key: 'posts/1-dashboard-view'
}
3.4 exist_fragment?.action_controller
{
key: 'posts/1-dashboard-view'
}
3.5 write_page.action_controller
3.6 expire_page.action_controller
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
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: ":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: "/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 |
绑定的参数 |
:cached |
使用缓存的查询时为 true
|
{
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
时使用这个事件。
写入存储器时,传给 fetch
的选项会合并到载荷中。
{
key: 'name-of-complicated-computation'
}
7.3 cache_fetch_hit.active_support
仅当使用块调用 #fetch
时使用这个事件。
{
key: 'name-of-complicated-computation'
}
7.4 cache_write.active_support
{
key: 'name-of-complicated-computation'
}
7.5 cache_delete.active_support
{
key: 'name-of-complicated-computation'
}
7.6 cache_exist?.active_support
{
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 |
作业对象 |
键 |
值 |
:adapter |
处理作业的 QueueAdapter 对象 |
: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
,并传入 name
、payload
和一个块。通知在块返回后发送。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。