# File lib/puppet/util/instrumentation.rb, line 145 def self.[](key) synchronize { @listeners[key.intern] } end
# File lib/puppet/util/instrumentation.rb, line 151 def self.[]=(key, value) synchronize { @listeners[key.intern] = value rehash } end
# File lib/puppet/util/instrumentation.rb, line 137 def self.clear synchronize { @listeners = {} @listeners_of = {} @id = 0 } end
# File lib/puppet/util/instrumentation.rb, line 73 def self.each_listener(label) synchronize { @listeners_of[label] ||= @listeners.select do |k,l| l.listen_to?(label) end }.each do |l| yield l end end
# File lib/puppet/util/instrumentation.rb, line 127 def self.init # let's init our probe indirection require 'puppet/util/instrumentation/indirection_probe' synchronize { @listeners ||= {} @listeners_of ||= {} instance_loader(:listener).loadall } end
Triggers an instrumentation
Call this method around the instrumentation point
Puppet::Util::Instrumentation.instrument(:my_long_computation) do ... a long computation end
This will send an event to all the listeners of “my_long_computation”. Note: this method uses ruby yield directive to call the instrumented code. It is usually way slower than calling start and stop directly around the instrumented code. For high traffic code path, it is thus advisable to not use this method.
# File lib/puppet/util/instrumentation.rb, line 36 def self.instrument(label, data = {}) id = self.start(label, data) yield ensure self.stop(label, id, data) end
Adds a new listener
Usage:
Puppet::Util::Instrumentation.new_listener(:my_instrumentation, pattern) do def notify(label, data) ... do something for data... end end
It is possible to use a “pattern”. The listener will be notified only if the pattern match the label of the event. The pattern can be a symbol, a string or a regex. If no pattern is provided, then the listener will be called for every events
# File lib/puppet/util/instrumentation.rb, line 97 def self.new_listener(name, options = {}, &block) Puppet.debug "new listener called #{name}" name = name.intern listener = genclass(name, :hash => instance_hash(:listener), :block => block) listener.send(:define_method, :name) do name end subscribe(listener.new, options[:label_pattern], options[:event]) end
# File lib/puppet/util/instrumentation.rb, line 63 def self.publish(label, event, data) each_listener(label) do |k,l| l.notify(label, event, data) end end
Triggers a “start” instrumentation event
Important note:
For proper use, the data hash instance used for start should also be used when calling stop. The idea is to use the current scope where start is called to retain a reference to 'data' so that it is possible to send it back to stop. This way listeners can match start and stop events more easily.
# File lib/puppet/util/instrumentation.rb, line 51 def self.start(label, data) data[:started] = Time.now publish(label, :start, data) data[:id] = next_id end
Triggers a “stop” instrumentation event
# File lib/puppet/util/instrumentation.rb, line 58 def self.stop(label, id, data) data[:finished] = Time.now publish(label, :stop, data) end
# File lib/puppet/util/instrumentation.rb, line 107 def self.subscribe(listener, label_pattern, event) synchronize { raise "Listener #{listener.name} is already subscribed" if @listeners.include?(listener.name) Puppet.debug "registering instrumentation listener #{listener.name}" @listeners[listener.name] = Listener.new(listener, label_pattern, event) listener.subscribed if listener.respond_to?(:subscribed) rehash } end
# File lib/puppet/util/instrumentation.rb, line 117 def self.unsubscribe(listener) synchronize { Puppet.warning("#{listener.name} hasn't been registered but asked to be unregistered") unless @listeners.include?(listener.name) Puppet.info "unregistering instrumentation listener #{listener.name}" @listeners.delete(listener.name) listener.unsubscribed if listener.respond_to?(:unsubscribed) rehash } end