aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/notifications.rb
diff options
context:
space:
mode:
authorJoshua Peek <josh@joshpeek.com>2009-10-14 19:50:06 -0500
committerJoshua Peek <josh@joshpeek.com>2009-10-14 19:50:36 -0500
commit8cbf825425dc8ad3770881ea4e100b9023c69ce2 (patch)
tree560e40df6aa1e888df3fe88ff4c87e1cb3b27e0e /activesupport/lib/active_support/notifications.rb
parentbf9819f73d74e19052b7b8a7a9885972a27e8876 (diff)
downloadrails-8cbf825425dc8ad3770881ea4e100b9023c69ce2.tar.gz
rails-8cbf825425dc8ad3770881ea4e100b9023c69ce2.tar.bz2
rails-8cbf825425dc8ad3770881ea4e100b9023c69ce2.zip
Rename Orchestra to Notifications [#3321 state:resolved]
Diffstat (limited to 'activesupport/lib/active_support/notifications.rb')
-rw-r--r--activesupport/lib/active_support/notifications.rb103
1 files changed, 103 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb
new file mode 100644
index 0000000000..6335686196
--- /dev/null
+++ b/activesupport/lib/active_support/notifications.rb
@@ -0,0 +1,103 @@
+require 'thread'
+
+module ActiveSupport
+ # Notifications provides an instrumentation API for Ruby. To instrument an action
+ # in Ruby you just need to:
+ #
+ # ActiveSupport::Notifications.instrument(:render, :extra => :information) do
+ # render :text => "Foo"
+ # end
+ #
+ # Those actions are consumed by listeners. A listener is anything that responds
+ # to push. You can even register an array:
+ #
+ # @listener = []
+ # ActiveSupport::Notifications.register @listener
+ #
+ # ActiveSupport::Notifications.instrument(:render, :extra => :information) do
+ # render :text => "Foo"
+ # end
+ #
+ # event #=> ActiveSupport::Notifications::Event
+ # event.name #=> :render
+ # event.duration #=> 10 (in miliseconds)
+ # event.result #=> "Foo"
+ # event.payload #=> { :extra => :information }
+ #
+ # Notifications ships with a default listener implementation which puts events in
+ # a stream and consume them in a Thread. This implementation is thread safe
+ # and is available at ActiveSupport::Notifications::Listener.
+ #
+ module Notifications
+ @stacked_events = Hash.new { |h,k| h[k] = [] }
+ @listeners = []
+
+ def self.instrument(name, payload=nil)
+ stack = @stacked_events[Thread.current.object_id]
+ event = Event.new(name, stack.last, payload)
+ stack << event
+ event.result = yield
+ event
+ ensure
+ event.finish!
+ stack.delete(event)
+ @listeners.each { |s| s.push(event) }
+ end
+
+ def self.register(listener)
+ @listeners << listener
+ end
+
+ def self.unregister(listener)
+ @listeners.delete(listener)
+ end
+
+ class Event
+ attr_reader :name, :time, :duration, :parent, :thread_id, :payload
+ attr_accessor :result
+
+ def initialize(name, parent=nil, payload=nil)
+ @name = name
+ @time = Time.now
+ @thread_id = Thread.current.object_id
+ @parent = parent
+ @payload = payload
+ end
+
+ def finish!
+ @duration = 1000 * (Time.now.to_f - @time.to_f)
+ end
+ end
+
+ class Listener
+ attr_reader :mutex, :signaler, :thread
+
+ def initialize
+ @mutex, @signaler = Mutex.new, ConditionVariable.new
+ @stream = []
+ @thread = Thread.new do
+ loop do
+ (event = @stream.shift) ? consume(event) : wait
+ end
+ end
+ end
+
+ def wait
+ @mutex.synchronize do
+ @signaler.wait(@mutex)
+ end
+ end
+
+ def push(event)
+ @mutex.synchronize do
+ @stream.push(event)
+ @signaler.broadcast
+ end
+ end
+
+ def consume(event)
+ raise NotImplementedError
+ end
+ end
+ end
+end