通知¶ ↑
ActiveSupport::Notifications 提供了一个 Ruby 的插桩 API。
插桩器¶ ↑
要插桩一个事件,你只需要这样做:
ActiveSupport::Notifications.instrument('render', extra: :information) do render plain: 'Foo' end
这会先执行代码块,然后一旦完成就通知所有订阅者。
在上面的例子中,render 是事件的名称,其余部分称为有效负载。有效负载是一种机制,允许插桩器将额外信息传递给订阅者。有效负载由一个哈希组成,其内容是任意的,并且通常取决于事件。
订阅者¶ ↑
你可以通过注册一个订阅者来消费这些事件及其提供的信息。
ActiveSupport::Notifications.subscribe('render') do |event| event.name # => "render" event.duration # => 10 (in milliseconds) event.payload # => { extra: :information } event.allocations # => 1826 (objects) end
Event 对象记录 CPU 时间和内存分配。如果你不需要这些,也可以传递一个接受五个参数的代码块。
ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload| name # => String, name of the event (such as 'render' from above) start # => Time, when the instrumented block started execution finish # => Time, when the instrumented block ended execution id # => String, unique ID for the instrumenter that fired the event payload # => Hash, the payload end
在这里,start 和 finish 值代表挂钟时间。如果你关心准确性,可以注册一个单调订阅者。
ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload| name # => String, name of the event (such as 'render' from above) start # => Float, monotonic time when the instrumented block started execution finish # => Float, monotonic time when the instrumented block ended execution id # => String, unique ID for the instrumenter that fired the event payload # => Hash, the payload end
例如,让我们将所有“render”事件存储在一个数组中:
events = [] ActiveSupport::Notifications.subscribe('render') do |event| events << event end
该代码会立即返回,你只是订阅了“render”事件。代码块会被保存,并在有人插桩“render”时被调用。
ActiveSupport::Notifications.instrument('render', extra: :information) do render plain: 'Foo' end event = events.first event.name # => "render" event.duration # => 10 (in milliseconds) event.payload # => { extra: :information } event.allocations # => 1826 (objects)
如果在该特定插桩过程中发生异常,有效负载将有一个名为 :exception 的键,其值为一个包含两个元素的数组:一个字符串,包含异常类的名称,以及异常消息。有效负载的 :exception_object 键将包含异常本身作为值。
event.payload[:exception] # => ["ArgumentError", "Invalid value"] event.payload[:exception_object] # => #<ArgumentError: Invalid value>
正如前面的示例所示,ActiveSupport::Notifications::Event 类能够接收传入的参数,并为该数据提供面向对象的接口。
也可以将响应 call 方法的对象作为第二个参数传递给 subscribe 方法,而不是传递一个代码块。
module ActionController class PageRequest def call(name, started, finished, unique_id, payload) Rails.logger.debug ['notification:', name, started, finished, unique_id, payload].join(' ') end end end ActiveSupport::Notifications.subscribe('process_action.action_controller', ActionController::PageRequest.new)
导致日志中出现以下输出,包括一个包含有效负载的哈希:
notification: process_action.action_controller 2012-04-13 01:08:35 +0300 2012-04-13 01:08:35 +0300 af358ed7fab884532ec7 {
controller: "Devise::SessionsController",
action: "new",
params: {"action"=>"new", "controller"=>"devise/sessions"},
format: :html,
method: "GET",
path: "/login/sign_in",
status: 200,
view_runtime: 279.3080806732178,
db_runtime: 40.053
}
你也可以订阅所有名称匹配特定正则表达式的事件。
ActiveSupport::Notifications.subscribe(/render/) do |*args| ... end
甚至可以不传递任何参数给 subscribe,在这种情况下,你将订阅所有事件。
临时订阅¶ ↑
有时你不想在应用程序的整个生命周期内订阅某个事件。有两种方法可以取消订阅。
警告:插桩框架是为长期运行的订阅者设计的,请谨慎使用此功能,因为它会清除一些内部缓存,从而对性能产生负面影响。
在代码块运行期间订阅¶ ↑
你可以在某些代码块运行期间临时订阅某个事件。例如,在
callback = lambda {|event| ... }
ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
...
end
回调将在代码块执行期间被调用,以响应所有“sql.active_record”事件的插桩。回调在执行完毕后会自动取消订阅。
要记录 started 和 finished 值(使用单调时间),请为 subscribed 方法指定可选的 :monotonic 选项。:monotonic 选项默认为 false。
callback = lambda {|name, started, finished, unique_id, payload| ... }
ActiveSupport::Notifications.subscribed(callback, "sql.active_record", monotonic: true) do
...
end
手动取消订阅¶ ↑
subscribe 方法返回一个订阅者对象。
subscriber = ActiveSupport::Notifications.subscribe("render") do |event|
...
end
要阻止该代码块被调用,只需通过传递该引用来取消订阅。
ActiveSupport::Notifications.unsubscribe(subscriber)
你也可以通过传递订阅者对象的名称来取消订阅。请注意,这将取消订阅所有具有给定名称的订阅。
ActiveSupport::Notifications.unsubscribe("render")
使用正则表达式或其他模式匹配对象的订阅者将继续订阅与其原始模式匹配的所有事件,除非这些事件匹配传递给 unsubscribe 的字符串。
subscriber = ActiveSupport::Notifications.subscribe(/render/) { } ActiveSupport::Notifications.unsubscribe('render_template.action_view') subscriber.matches?('render_template.action_view') # => false subscriber.matches?('render_partial.action_view') # => true
默认队列¶ ↑
Notifications 自带了一个队列实现,该实现会消费事件并将其发布给所有日志订阅者。你可以使用任何你想要的队列实现。
- 类 ActiveSupport::Notifications::Event
- 类 ActiveSupport::Notifications::Fanout
- 类 ActiveSupport::Notifications::InstrumentationSubscriberError
- 类 ActiveSupport::Notifications::Instrumenter
- I
- M
- P
- S
- U
Attributes
| [RW] | notifier |
类公共方法
instrument(name, payload = {}) 链接
Source: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 208 def instrument(name, payload = {}) if notifier.listening?(name) instrumenter.instrument(name, payload) { yield payload if block_given? } else yield payload if block_given? end end
instrumenter() 链接
Source: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 269 def instrumenter registry[notifier] ||= Instrumenter.new(notifier) end
monotonic_subscribe(pattern = nil, callback = nil, &block) 链接
执行与 subscribe 相同的功能,但 start 和 finish 代码块参数使用的是单调时间而不是挂钟时间。单调时间不会向前或向后跳转(由于 NTP 或夏令时)。当时间持续时间的准确性很重要时,请使用 monotonic_subscribe。例如,计算两个事件之间经过的时间。
Source: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 254 def monotonic_subscribe(pattern = nil, callback = nil, &block) notifier.subscribe(pattern, callback, monotonic: true, &block) end
publish(name, *args) 链接
Source: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 200 def publish(name, *args) notifier.publish(name, *args) end
subscribe(pattern = nil, callback = nil, &block) 链接
使用传递的 block 订阅给定事件名称。
你可以通过传递一个 String 来匹配精确的事件名称,或者通过传递一个 Regexp 来匹配所有匹配模式的事件来订阅事件。
如果传递给方法的代码块只接受一个参数,它将向该代码块传递一个 Event 对象。
ActiveSupport::Notifications.subscribe(/render/) do |event| @event = event end
否则,block 将接收五个关于事件信息的参数。
ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload| name # => String, name of the event (such as 'render' from above) start # => Time, when the instrumented block started execution finish # => Time, when the instrumented block ended execution id # => String, unique ID for the instrumenter that fired the event payload # => Hash, the payload end
如果传递了无效的事件名称类型,则会引发错误。
ActiveSupport::Notifications.subscribe(:render) {|event| ...}
#=> ArgumentError (pattern must be specified as a String, Regexp or empty)
Source: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 244 def subscribe(pattern = nil, callback = nil, &block) notifier.subscribe(pattern, callback, monotonic: false, &block) end
subscribed(callback, pattern = nil, monotonic: false, &block) 链接
Source: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 258 def subscribed(callback, pattern = nil, monotonic: false, &block) subscriber = notifier.subscribe(pattern, callback, monotonic: monotonic) yield ensure unsubscribe(subscriber) end
unsubscribe(subscriber_or_name) 链接
Source: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 265 def unsubscribe(subscriber_or_name) notifier.unsubscribe(subscriber_or_name) end