Class: NewRelic::Agent::Instrumentation::ActiveRecordSubscriber

Inherits:
Object
  • Object
show all
Includes:
NewRelic::Agent::Instrumentation
Defined in:
lib/new_relic/agent/instrumentation/active_record_subscriber.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.subscribed?Boolean

Returns:

  • (Boolean)


15
16
17
18
19
20
# File 'lib/new_relic/agent/instrumentation/active_record_subscriber.rb', line 15

def self.subscribed?
  # TODO: need to talk to Rails core about an API for this,
  # rather than digging through Listener ivars
  ActiveSupport::Notifications.notifier.listeners_for('sql.active_record') \
    .find{|l| l.instance_variable_get(:@delegate).class == self }
end

Instance Method Details

#active_record_config_for_event(event) ⇒ Object



84
85
86
87
88
89
90
91
92
# File 'lib/new_relic/agent/instrumentation/active_record_subscriber.rb', line 84

def active_record_config_for_event(event)
  return unless event.payload[:connection_id] && NewRelic::LanguageSupport.object_space_enabled?

  # TODO: This will not work for JRuby and in any case we want
  # this to be part of the event meta data so it doesn't have
  # to be dug out of an ivar.
  connection = ObjectSpace._id2ref(event.payload[:connection_id])
  connection.instance_variable_get(:@config) if connection
end

#base_metric(event) ⇒ Object



79
80
81
82
# File 'lib/new_relic/agent/instrumentation/active_record_subscriber.rb', line 79

def base_metric(event)
  ActiveRecordHelper.metric_for_name(event.payload[:name]) ||
    ActiveRecordHelper.metric_for_sql(NewRelic::Helper.correctly_encoded(event.payload[:sql]))
end

#call(*args) ⇒ Object



22
23
24
25
26
27
28
# File 'lib/new_relic/agent/instrumentation/active_record_subscriber.rb', line 22

def call(*args)
  return unless NewRelic::Agent.is_execution_traced?

  event = ActiveSupport::Notifications::Event.new(*args)
  record_metrics(event)
  notice_sql(event)
end

#get_explain_plan(config, query) ⇒ Object



30
31
32
33
34
35
36
37
38
# File 'lib/new_relic/agent/instrumentation/active_record_subscriber.rb', line 30

def get_explain_plan( config, query )
  connection = NewRelic::Agent::Database.get_connection(config) do
    ::ActiveRecord::Base.send("#{config[:adapter]}_connection",
                              config)
  end
  if connection && connection.respond_to?(:execute)
    return connection.execute("EXPLAIN #{query}")
  end
end

#notice_sql(event) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/new_relic/agent/instrumentation/active_record_subscriber.rb', line 40

def notice_sql(event)
  config = active_record_config_for_event(event)
  metric = base_metric(event)

  # enter transaction trace segment
  scope = NewRelic::Agent.instance.stats_engine.push_scope(:active_record, event.time)

  NewRelic::Agent.instance.transaction_sampler \
    .notice_sql(event.payload[:sql], config,
                Helper.milliseconds_to_seconds(event.duration),
                &method(:get_explain_plan))

  NewRelic::Agent.instance.sql_sampler \
    .notice_sql(event.payload[:sql], metric, config,
                Helper.milliseconds_to_seconds(event.duration),
                &method(:get_explain_plan))

  # exit transaction trace segment
  NewRelic::Agent.instance.stats_engine.pop_scope(scope, metric, event.end)
end

#record_metrics(event) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/new_relic/agent/instrumentation/active_record_subscriber.rb', line 61

def record_metrics(event)
  base = base_metric(event)
  NewRelic::Agent.instance.stats_engine.record_metrics(base,
                      Helper.milliseconds_to_seconds(event.duration),
                      :scoped => true)

  other_metrics = ActiveRecordHelper.rollup_metrics_for(base)
  if config = active_record_config_for_event(event)
    other_metrics << ActiveRecordHelper.remote_service_metric(config[:adapter], config[:host])
  end

  other_metrics.compact.each do |metric_name|
    NewRelic::Agent.instance.stats_engine.record_metrics(metric_name,
                                    Helper.milliseconds_to_seconds(event.duration),
                                    :scoped => false)
  end
end