class NewRelic::Agent::Instrumentation::NotificationsSubscriber
Public Class Methods
find_all_subscribers()
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 18 def self.find_all_subscribers # TODO: need to talk to Rails core about an API for this, # rather than digging through Listener ivars instance_variable_names = [:@subscribers, :@string_subscribers, :@other_subscribers] all_subscribers = [] notifier = ActiveSupport::Notifications.notifier instance_variable_names.each do |name| if notifier.instance_variable_defined?(name) subscribers = notifier.instance_variable_get(name) if subscribers.is_a?(Array) # Rails 5 @subscribers, and Rails 6 @other_subscribers is a # plain array of subscriber objects all_subscribers += subscribers elsif subscribers.is_a?(Hash) # Rails 6 @string_subscribers is a Hash mapping the pattern # string of a subscriber to an array of subscriber objects subscribers.values.each { |array| all_subscribers += array } end end end all_subscribers end
new()
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 9 def initialize @queue_key = ['NewRelic', self.class.name, object_id].join('-') define_exception_method end
subscribe(pattern)
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 44 def self.subscribe(pattern) if !subscribed? ActiveSupport::Notifications.subscribe(pattern, new) end end
subscribed?()
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 14 def self.subscribed? find_all_subscribers.find { |s| s.instance_variable_get(:@delegate).class == self } end
Public Instance Methods
add_segment_params(segment, payload)
click to toggle source
for subclasses
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 86 def add_segment_params(segment, payload) # no op end
define_exception_method()
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 119 def define_exception_method # we don't expect this to be called more than once, but we're being # defensive. return if defined?(exception_object) return unless defined?(::ActiveSupport::VERSION) if ::ActiveSupport::VERSION::STRING < '5.0.0' # Earlier versions of Rails did not add the exception itself to the # payload accessible via :exception_object, so we create a stand-in # error object from the given class name and message. # NOTE: no backtrace available this way, but we can notice the error # well enough to send the necessary info the UI requires to present it. def exception_object(payload) exception_class, message = payload[:exception] return nil unless exception_class NewRelic::Agent::NoticeableError.new(exception_class, message) end else def exception_object(payload) payload[:exception_object] end end end
exception_object(payload)
click to toggle source
Earlier versions of Rails did not add the exception itself to the payload accessible via :exception_object, so we create a stand-in error object from the given class name and message. NOTE: no backtrace available this way, but we can notice the error well enough to send the necessary info the UI requires to present it.
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 131 def exception_object(payload) exception_class, message = payload[:exception] return nil unless exception_class NewRelic::Agent::NoticeableError.new(exception_class, message) end
finish(name, id, payload)
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 62 def finish(name, id, payload) return unless state.is_execution_traced? finish_segment(id, payload) rescue => e log_notification_error(e, name, 'finish') end
finish_segment(id, payload)
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 76 def finish_segment(id, payload) if segment = pop_segment(id) if exception = exception_object(payload) segment.notice_error(exception) end segment.finish end end
log_notification_error(error, name, event_type)
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 95 def log_notification_error(error, name, event_type) # These are important enough failures that we want the backtraces # logged at error level, hence the explicit log_exception call. NewRelic::Agent.logger.error("Error during #{event_type} callback for event '#{name}':") NewRelic::Agent.logger.log_exception(:error, error) end
metric_name(name, payload)
click to toggle source
for subclasses
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 91 def metric_name(name, payload) "Ruby/#{name}" end
pop_segment(id)
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 106 def pop_segment(id) segment = segment_stack[id].pop segment end
push_segment(id, segment)
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 102 def push_segment(id, segment) segment_stack[id].push(segment) end
segment_stack()
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 111 def segment_stack Thread.current[@queue_key] ||= Hash.new { |h, id| h[id] = [] } end
start(name, id, payload)
click to toggle source
The agent doesn’t use the traditional ActiveSupport::Notifications.subscribe pattern due to threading issues discovered on initial instrumentation. Instead we define a start
and finish
method, which Rails responds to. See: github.com/rails/rails/issues/12069
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 54 def start(name, id, payload) return unless state.is_execution_traced? start_segment(name, id, payload) rescue => e log_notification_error(e, name, 'start') end
start_segment(name, id, payload)
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 70 def start_segment(name, id, payload) segment = Tracer.start_segment(name: metric_name(name, payload)) add_segment_params(segment, payload) push_segment(id, segment) end
state()
click to toggle source
# File lib/new_relic/agent/instrumentation/notifications_subscriber.rb, line 115 def state NewRelic::Agent::Tracer.state end