通知
ActiveSupport::Notifications
为 Ruby 提供了一个仪器 API。
仪器
要对事件进行仪器化,您只需执行以下操作
ActiveSupport::Notifications.instrument('render', extra: :information) do
render plain: 'Foo'
end
这首先执行代码块,然后在完成后通知所有订阅者。
在上面的示例中,render
是事件的名称,其余部分称为有效负载。有效负载是一种机制,允许仪器将额外信息传递给订阅者。有效负载由一个哈希组成,其内容是任意的,通常取决于事件。
订阅者
您可以通过注册订阅者来使用这些事件及其提供的信息。
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 # => Monotonic time, when the instrumented block started execution
finish # => Monotonic 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
值表示单调时间。
例如,让我们将所有“render”事件存储在一个数组中
events = []
ActiveSupport::Notifications.subscribe('render') do |*args|
events << ActiveSupport::Notifications::Event.new(*args)
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 }
subscribe
调用中的代码块按顺序获取事件的名称、开始时间戳、结束时间戳、一个包含该事件仪器化程序的唯一标识符的字符串(类似于“535801666f04d0298cd6”)以及一个包含有效负载的哈希。
如果在该特定仪器化期间发生异常,则有效负载将包含一个键 :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 {|*args| ... }
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 |*args|
...
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
附带一个队列实现,该实现会将事件消费并发布到所有日志订阅者。您可以使用任何您想要的队列实现。
- CLASS ActiveSupport::Notifications::Event
- CLASS ActiveSupport::Notifications::Fanout
- CLASS ActiveSupport::Notifications::InstrumentationSubscriberError
- CLASS ActiveSupport::Notifications::Instrumenter
- I
- M
- P
- S
- U
属性
[RW] | 通知器 |
类公共方法
instrument(name, payload = {}) 链接
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 204 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() 链接
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 268 def instrumenter registry[notifier] ||= Instrumenter.new(notifier) end
monotonic_subscribe(pattern = nil, callback = nil, &block) 链接
执行与 subscribe 相同的功能,但 start
和 finish
块参数使用单调时间而不是挂钟时间。单调时间不会向前或向后跳跃(由于 NTP 或夏令时)。当时间持续时间的准确性很重要时,使用 monotonic_subscribe
。例如,计算两个事件之间的经过时间。
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 253 def monotonic_subscribe(pattern = nil, callback = nil, &block) notifier.subscribe(pattern, callback, monotonic: true, &block) end
publish(name, *args) 链接
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 196 def publish(name, *args) notifier.publish(name, *args) end
subscribe(pattern = nil, callback = nil, &block) 链接
使用传递的 block
订阅给定事件名称。
您可以通过传递 String
来匹配确切的事件名称,或通过传递 Regexp
来匹配所有与模式匹配的事件来订阅事件。
ActiveSupport::Notifications.subscribe(/render/) do |*args|
@event = ActiveSupport::Notifications::Event.new(*args)
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/) do |event|
@event = event
end
如果传递了无效的事件名称类型,则会引发错误。
ActiveSupport::Notifications.subscribe(:render) {|*args| ...}
#=> ArgumentError (pattern must be specified as a String, Regexp or empty)
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 243 def subscribe(pattern = nil, callback = nil, &block) notifier.subscribe(pattern, callback, monotonic: false, &block) end
subscribed(callback, pattern = nil, monotonic: false, &block) 链接
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 257 def subscribed(callback, pattern = nil, monotonic: false, &block) subscriber = notifier.subscribe(pattern, callback, monotonic: monotonic) yield ensure unsubscribe(subscriber) end
unsubscribe(subscriber_or_name) 链接
来源:显示 | 在 GitHub 上
# File activesupport/lib/active_support/notifications.rb, line 264 def unsubscribe(subscriber_or_name) notifier.unsubscribe(subscriber_or_name) end