Module: NewRelic::Agent::MethodTracer::InstanceMethods

Defined in:
lib/new_relic/agent/method_tracer.rb

Constant Summary collapse

EMPTY_ARRAY =
[].freeze

Instance Method Summary collapse

Instance Method Details

#trace_execution_scoped(metric_names, options = {}) ⇒ Object

Trace a given block with stats and keep track of the caller. See NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer for a description of the arguments. metric_names is either a single name or an array of metric names. If more than one metric is passed, the produce_metric option only applies to the first. The others are always recorded. Only the first metric is pushed onto the scope stack.

Generally you pass an array of metric names if you want to record the metric under additional categories, but generally this *should never ever be done*. Most of the time you can aggregate on the server.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/new_relic/agent/method_tracer.rb', line 106

def trace_execution_scoped(metric_names, options={})

  return yield unless NewRelic::Agent.is_execution_traced? || options[:force]

  produce_metric               = options[:metric] != false
  deduct_call_time_from_parent = options[:deduct_call_time_from_parent] != false
  scoped_metric_only           = produce_metric && options[:scoped_metric_only]
  t0 = Time.now
  if metric_names.instance_of? Array
    first_name = metric_names.first
    metric_stats = []
    metric_stats << NewRelic::Agent.instance.stats_engine.get_stats(first_name, true, scoped_metric_only) if produce_metric
    metric_names[1..-1].each do | name |
      metric_stats << NewRelic::Agent.instance.stats_engine.get_stats_no_scope(name)
    end
  else
    first_name = metric_names
    if produce_metric
      metric_stats = [NewRelic::Agent.instance.stats_engine.get_stats(first_name, true, scoped_metric_only)]
    else
      metric_stats = EMPTY_ARRAY
    end
  end

  begin
    # Keep a reference to the scope we are pushing so we can do a sanity check making
    # sure when we pop we get the one we 'expected'
    NewRelic::Agent.instance.push_trace_execution_flag(true) if options[:force]
    expected_scope = NewRelic::Agent.instance.stats_engine.push_scope(first_name, t0.to_f, deduct_call_time_from_parent)
  rescue => e
    NewRelic::Control.instance.log.error("Caught exception in trace_method_execution header. Metric name = #{first_name}, exception = #{e}")
    NewRelic::Control.instance.log.error(e.backtrace.join("\n"))
  end

  begin
    yield
  ensure
    t1 = Time.now
    duration = (t1 - t0).to_f

    begin
      NewRelic::Agent.instance.pop_trace_execution_flag if options[:force]
      if expected_scope
        scope = NewRelic::Agent.instance.stats_engine.pop_scope expected_scope, duration, t1.to_f
        exclusive = duration - scope.children_time
        metric_stats.each { |stats| stats.trace_call(duration, exclusive) }
      end
    rescue => e
      NewRelic::Control.instance.log.error("Caught exception in trace_method_execution footer. Metric name = #{first_name}, exception = #{e}")
      NewRelic::Control.instance.log.error(e.backtrace.join("\n"))
    end
  end
end

#trace_execution_unscoped(metric_names, options = {}) ⇒ Object Also known as: trace_method_execution_no_scope

Trace a given block with stats assigned to the given metric_name. It does not provide scoped measurements, meaning whatever is being traced will not ‘blame the Controller’–that is to say appear in the breakdown chart. This is code is inlined in #add_method_tracer.

  • metric_names is a single name or an array of names of metrics

  • :force => true will force the metric to be captured even when tracing is disabled with NewRelic::Agent#disable_all_tracing



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/new_relic/agent/method_tracer.rb', line 68

def trace_execution_unscoped(metric_names, options={})
  return yield unless NewRelic::Agent.is_execution_traced?
  t0 = Time.now
  stats = Array(metric_names).map do | metric_name |
    NewRelic::Agent.instance.stats_engine.get_stats_no_scope metric_name
  end
  begin
    NewRelic::Agent.instance.push_trace_execution_flag(true) if options[:force]
    yield
  ensure
    NewRelic::Agent.instance.pop_trace_execution_flag if options[:force]
    duration = (Time.now - t0).to_f              # for some reason this is 3 usec faster than Time - Time
    stats.each { |stat| stat.trace_call(duration) }
  end
end

#trace_method_execution(metric_names, push_scope, produce_metric, deduct_call_time_from_parent, &block) ⇒ Object

Deprecated: original method preserved for API backward compatibility. Use either #trace_execution_scoped or #trace_execution_unscoped



51
52
53
54
55
56
57
58
# File 'lib/new_relic/agent/method_tracer.rb', line 51

def trace_method_execution(metric_names, push_scope, produce_metric, deduct_call_time_from_parent, &block) #:nodoc:
  if push_scope
    trace_execution_scoped(metric_names, :metric => produce_metric,
                                              :deduct_call_time_from_parent => deduct_call_time_from_parent, &block)
  else
    trace_execution_unscoped(metric_names, &block)
  end
end

#trace_method_execution_with_scope(metric_names, produce_metric, deduct_call_time_from_parent, scoped_metric_only = false, &block) ⇒ Object

Deprecated. Use #trace_execution_scoped, a version with an options hash.



87
88
89
90
91
92
# File 'lib/new_relic/agent/method_tracer.rb', line 87

def trace_method_execution_with_scope(metric_names, produce_metric, deduct_call_time_from_parent, scoped_metric_only=false, &block) #:nodoc:
  trace_execution_scoped(metric_names,
                       :metric => produce_metric,
                       :deduct_call_time_from_parent => deduct_call_time_from_parent,
                       :scoped_metric_only => scoped_metric_only, &block)
end