notifications.rb 2.4 KB
Newer Older
1
require 'active_support/core_ext/module/delegation'
J
José Valim 已提交
2 3

module ActiveSupport
4 5
  # Notifications provides an instrumentation API for Ruby. To instrument an
  # action in Ruby you just need to do:
J
José Valim 已提交
6
  #
7
  #   ActiveSupport::Notifications.instrument(:render, :extra => :information) do
J
José Valim 已提交
8 9 10
  #     render :text => "Foo"
  #   end
  #
11
  # You can consume those events and the information they provide by registering
12
  # a log subscriber. For instance, let's store all instrumented events in an array:
J
José Valim 已提交
13
  #
14 15
  #   @events = []
  #
16 17
  #   ActiveSupport::Notifications.subscribe do |*args|
  #     @events << ActiveSupport::Notifications::Event.new(*args)
18
  #   end
J
José Valim 已提交
19
  #
20
  #   ActiveSupport::Notifications.instrument(:render, :extra => :information) do
J
José Valim 已提交
21 22 23
  #     render :text => "Foo"
  #   end
  #
24
  #   event = @events.first
J
José Valim 已提交
25
  #   event.name      #=> :render
26
  #   event.duration  #=> 10 (in milliseconds)
J
José Valim 已提交
27 28
  #   event.payload   #=> { :extra => :information }
  #
29
  # When subscribing to Notifications, you can pass a pattern, to only consume
30 31
  # events that match the pattern:
  #
32
  #   ActiveSupport::Notifications.subscribe(/render/) do |event|
33 34 35
  #     @render_events << event
  #   end
  #
36
  # Notifications ships with a queue implementation that consumes and publish events
37
  # to log subscribers in a thread. You can use any queue implementation you want.
J
José Valim 已提交
38
  #
39
  module Notifications
40 41 42
    autoload :Instrumenter, 'active_support/notifications/instrumenter'
    autoload :Event, 'active_support/notifications/instrumenter'
    autoload :Fanout, 'active_support/notifications/fanout'
43

44 45
    @instrumenters = Hash.new { |h,k| h[k] = notifier.listening?(k) }

46
    class << self
47
      attr_writer :notifier
48 49
      delegate :publish, :unsubscribe, :to => :notifier

J
José Valim 已提交
50
      def instrument(name, payload = {})
51
        if @instrumenters[name]
J
José Valim 已提交
52
          instrumenter.instrument(name, payload) { yield payload if block_given? }
53
        else
J
José Valim 已提交
54
          yield payload if block_given?
55 56 57 58 59 60 61 62 63 64 65 66 67
        end
      end

      def subscribe(*args, &block)
        notifier.subscribe(*args, &block).tap do
          @instrumenters.clear
        end
      end

      def unsubscribe(*args)
        notifier.unsubscribe(*args)
        @instrumenters.clear
      end
68

69
      def notifier
70
        @notifier ||= Fanout.new
71
      end
72 73 74 75

      def instrumenter
        Thread.current[:"instrumentation_#{notifier.object_id}"] ||= Instrumenter.new(notifier)
      end
76
    end
J
José Valim 已提交
77 78
  end
end