# File lib/puppet/util/instrumentation.rb, line 134 def self.[](key) @listeners[key.intern] end
# File lib/puppet/util/instrumentation.rb, line 138 def self.[]=(key, value) @listeners[key.intern] = value rehash end
# File lib/puppet/util/instrumentation.rb, line 128 def self.clear @listeners = {} @listeners_of = {} @id = 0 end
# File lib/puppet/util/instrumentation.rb, line 72 def self.each_listener(label) @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 120 def self.init # let's init our probe indirection require 'puppet/util/instrumentation/indirection_probe' @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 35 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 94 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 62 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 50 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 57 def self.stop(label, id, data) data[:finished] = Time.now publish(label, :stop, data) end
# File lib/puppet/util/instrumentation.rb, line 104 def self.subscribe(listener, label_pattern, event) 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 112 def self.unsubscribe(listener) 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