Spec-Zone.ru › Ruby on Rails 5.2

module ActiveSupport::Notifications

Уведомления

ActiveSupport::Notifications предоставляет API для инструментирования Ruby.

Инструментаторы

Для инструментирования события нужно сделать следующее:

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 this notification
  payload # => Hash, the payload
end

Например, давайте сохраним все события «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 данных будет содержать само исключение в качестве значения.

Как показывает предыдущий пример, класс 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», которые инструментируются во время выполнения блока. Обработчик автоматически отписывается после этого.

Ручная отписка

Метод subscribe возвращает объект подписчика:

subscriber = ActiveSupport::Notifications.subscribe("render") do |*args|
  ...
end

Чтобы предотвратить вызов этого блока, просто отпишитесь, передав эту ссылку:

ActiveSupport::Notifications.unsubscribe(subscriber)

Вы также можете отписаться, передав имя объекта подписчика. Обратите внимание, что это отпишет все подписки с данным именем:

ActiveSupport::Notifications.unsubscribe("render")

Очередь по умолчанию

Уведомления поставляются с реализацией очереди, которая потребляет и публикует события для всех подписчиков логов. Вы можете использовать любую реализацию очереди, которую хотите.

Атрибуты

notifier[RW]

Общедоступные методы класса

instrument(name, payload = {}) { |payload| ... } Показать исходный код
# File activesupport/lib/active_support/notifications.rb, line 166
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() Показать исходный код
# File activesupport/lib/active_support/notifications.rb, line 189
def instrumenter
  InstrumentationRegistry.instance.instrumenter_for(notifier)
end
publish(name, *args) Показать исходный код
# File activesupport/lib/active_support/notifications.rb, line 162
def publish(name, *args)
  notifier.publish(name, *args)
end
subscribe(*args, &block) Показать исходный код
# File activesupport/lib/active_support/notifications.rb, line 174
def subscribe(*args, &block)
  notifier.subscribe(*args, &block)
end
subscribed(callback, *args) { || ... } Показать исходный код
# File activesupport/lib/active_support/notifications.rb, line 178
def subscribed(callback, *args, &block)
  subscriber = subscribe(*args, &callback)
  yield
ensure
  unsubscribe(subscriber)
end
unsubscribe(subscriber_or_name) Показать исходный код
# File activesupport/lib/active_support/notifications.rb, line 185
def unsubscribe(subscriber_or_name)
  notifier.unsubscribe(subscriber_or_name)
end

© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API