Spec-Zone.ru › Ruby on Rails 7.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 |event|
  event.name          # => "render"
  event.duration      # => 10 (in milliseconds)
  event.payload       # => { extra: :information }
  event.allocations   # => 1826 (objects)
end

Event объекты записывают время ЦП и объемы памяти. Если это не нужно, можно также передать блок, который принимает пять аргументов:

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

Атрибуты

notifier[RW]

Открытые методы класса

instrument(name, payload = {}) { |payload| ... } Показать исходный код
# 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() Показать исходный код
# File activesupport/lib/active_support/notifications.rb, line 269
def instrumenter
  registry[notifier] ||= Instrumenter.new(notifier)
end
monotonic_subscribe(pattern = nil, callback = nil, &block) Показать исходный код
# 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

Выполняет ту же функцию, что и subscribe, но аргументы блока start и finish указаны в монотонном времени, а не в реальном времени. Монотонное время не будет перескакивать вперёд или назад (из-за NTP или перехода на летнее время). Используйте monotonic_subscribe , когда точность продолжительности времени имеет значение. Например, для вычисления времени, прошедшего между двумя событиями.

publish(name, *args) Показать исходный код
# File activesupport/lib/active_support/notifications.rb, line 200
def publish(name, *args)
  notifier.publish(name, *args)
end
subscribe(pattern = nil, callback = nil, &block) Показать исходный код
# File activesupport/lib/active_support/notifications.rb, line 244
def subscribe(pattern = nil, callback = nil, &block)
  notifier.subscribe(pattern, callback, monotonic: false, &block)
end

Подписывается на указанное имя события с переданным 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)
subscribed(callback, pattern = nil, monotonic: false) { || ... } Показать исходный код
# 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) Показать исходный код
# File activesupport/lib/active_support/notifications.rb, line 265
def unsubscribe(subscriber_or_name)
  notifier.unsubscribe(subscriber_or_name)
end

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

Spec-Zone.ru

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