Class: OneApm::Agent::Instrumentation::ActiveRecordSubscriber

Inherits:
EventedSubscriber show all
Defined in:
lib/one_apm/inst/rails4/active_record_subscriber.rb

Constant Summary collapse

OA_CACHED_QUERY_NAME =
'CACHE'.freeze

Instance Method Summary collapse

Methods inherited from EventedSubscriber

#event_stack, #initialize, #log_notification_error, #pop_event, #push_event, subscribe, subscribed?

Constructor Details

This class inherits a constructor from OneApm::Agent::Instrumentation::EventedSubscriber

Instance Method Details

#active_record_config_for_event(event) ⇒ Object



88
89
90
91
92
93
94
95
# File 'lib/one_apm/inst/rails4/active_record_subscriber.rb', line 88

def active_record_config_for_event(event)
  return unless event.payload[:connection_id]

  connections = ::ActiveRecord::Base.connection_handler.connection_pool_list.map { |handler| handler.connections }.flatten
  connection = connections.detect { |cnxn| cnxn.object_id == event.payload[:connection_id] }

  connection.instance_variable_get(:@config) if connection
end

#finish(name, id, payload) ⇒ Object



22
23
24
25
26
27
28
29
30
31
# File 'lib/one_apm/inst/rails4/active_record_subscriber.rb', line 22

def finish(name, id, payload)
  return if payload[:name] == OA_CACHED_QUERY_NAME
  state = OneApm::TransactionState.tl_get
  return unless state.is_execution_traced?
  event = pop_event(id)
  record_metrics(event)
  notice_sql(state, event)
rescue => e
  log_notification_error(e, name, 'finish')
end

#generate_metrics(event) ⇒ Object



66
67
68
69
70
71
72
# File 'lib/one_apm/inst/rails4/active_record_subscriber.rb', line 66

def generate_metrics(event)
  @config  ||= active_record_config_for_event(event)
  @product ||= ActiveRecordHelper.database_info(@config)
  operation = operation(event)
  model_name = ActiveRecordHelper.model_for_name(event.payload[:name])
  ActiveRecordHelper.metric_for(@product, operation, model_name)
end

#get_explain_plan(config, query) ⇒ Object



33
34
35
36
37
38
39
40
41
# File 'lib/one_apm/inst/rails4/active_record_subscriber.rb', line 33

def get_explain_plan( config, query )
  connection = OneApm::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(state, event) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/one_apm/inst/rails4/active_record_subscriber.rb', line 43

def notice_sql(state, event)
  stack  = state.traced_method_stack
  config = active_record_config_for_event(event)

  base, *other_metrics = generate_metrics(event)

  # enter transaction trace segment
  frame = stack.push_frame(state, :active_record, event.time)

  OneApm::Manager.agent.transaction_sampler \
    .notice_sql(event.payload[:sql], config,
                Helper.milliseconds_to_seconds(event.duration),
                state, &method(:get_explain_plan))

  OneApm::Manager.agent.sql_sampler \
    .notice_sql(event.payload[:sql], base, config,
                Helper.milliseconds_to_seconds(event.duration),
                state, &method(:get_explain_plan))

  # exit transaction trace segment
  stack.pop_frame(state, frame, base, event.end)
end

#operation(event) ⇒ Object



83
84
85
86
# File 'lib/one_apm/inst/rails4/active_record_subscriber.rb', line 83

def operation(event)
  ActiveRecordHelper.operator_for_name(event.payload[:name]) ||
    ActiveRecordHelper.operator_for_sql(OneApm::Helper.correctly_encoded(event.payload[:sql]))
end

#record_metrics(event) ⇒ Object



74
75
76
77
78
79
80
81
# File 'lib/one_apm/inst/rails4/active_record_subscriber.rb', line 74

def record_metrics(event)
  base, *other_metrics = generate_metrics(event)

  OneApm::Manager.agent.stats_engine.tl_record_scoped_and_unscoped_metrics(
    base, other_metrics,
    Helper.milliseconds_to_seconds(event.duration)
  )
end

#start(name, id, payload) ⇒ Object



14
15
16
17
18
19
20
# File 'lib/one_apm/inst/rails4/active_record_subscriber.rb', line 14

def start(name, id, payload)
  return if payload[:name] == OA_CACHED_QUERY_NAME
  return unless OneApm::Manager.tl_is_execution_traced?
  super
rescue => e
  log_notification_error(e, name, 'start')
end