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

Included in:
NewRelic::Agent::MethodTracer::InstanceMethods
Defined in:
lib/new_relic/agent/method_tracer.rb

Overview

Refactored out of the previous trace_execution_scoped method, most methods in this module relate to code used in the #trace_execution_scoped method in this module

Instance Method Summary collapse

Instance Method Details

#agent_instanceObject

Shorthand to return the NewRelic::Agent.instance



102
103
104
# File 'lib/new_relic/agent/method_tracer.rb', line 102

def agent_instance
  NewRelic::Agent.instance
end

#get_metric_specs(first_name, other_names, scope, options) ⇒ Object



131
132
133
134
135
136
137
138
139
140
# File 'lib/new_relic/agent/method_tracer.rb', line 131

def get_metric_specs(first_name, other_names, scope, options)
  specs = other_names.map { |name| NewRelic::MetricSpec.new(name) }
  if options[:metric]
    if scope && scope != first_name
      specs << NewRelic::MetricSpec.new(first_name, scope)
    end
    specs << NewRelic::MetricSpec.new(first_name) unless options[:scoped_metric_only]
  end
  specs
end

#get_stats_scoped(first_name, scoped_metric_only) ⇒ Object

returns a scoped metric stat for the specified name



123
124
125
# File 'lib/new_relic/agent/method_tracer.rb', line 123

def get_stats_scoped(first_name, scoped_metric_only)
  stat_engine.get_stats(first_name, true, scoped_metric_only)
end

#get_stats_unscoped(name) ⇒ Object

Shorthand method to get stats from the stat engine



127
128
129
# File 'lib/new_relic/agent/method_tracer.rb', line 127

def get_stats_unscoped(name)
  stat_engine.get_stats_no_scope(name)
end

#log_errors(code_area, metric) ⇒ Object

helper for logging errors to the newrelic_agent.log properly. Logs the error at error level



171
172
173
174
175
# File 'lib/new_relic/agent/method_tracer.rb', line 171

def log_errors(code_area, metric)
  yield
rescue => e
  ::NewRelic::Agent.logger.error("Caught exception in #{code_area}. Metric name = #{metric}", e)
end

#pop_flag!(forced) ⇒ Object

delegates to #agent_instance to pop the trace execution flag, only if execution of this metric is forced. otherwise this is taken care of for us automatically.

This ends the forced recording of metrics within the #trace_execution_scoped block



165
166
167
# File 'lib/new_relic/agent/method_tracer.rb', line 165

def pop_flag!(forced)
  agent_instance.pop_trace_execution_flag if forced
end

#push_flag!(forced) ⇒ Object

delegates to #agent_instance to push a trace execution flag, only if execution of this metric is forced.

This causes everything scoped inside this metric to be recorded, even if the parent transaction is generally not.



154
155
156
# File 'lib/new_relic/agent/method_tracer.rb', line 154

def push_flag!(forced)
  agent_instance.push_trace_execution_flag(true) if forced
end

#set_if_nil(hash, key) ⇒ Object

Helper for setting a hash key if the hash key is nil, instead of the default ||= behavior which sets if it is false as well



145
146
147
# File 'lib/new_relic/agent/method_tracer.rb', line 145

def set_if_nil(hash, key)
  hash[key] = true if hash[key].nil?
end

#stat_engineObject

Shorthand to return the current statistics engine



118
119
120
# File 'lib/new_relic/agent/method_tracer.rb', line 118

def stat_engine
  agent_instance.stats_engine
end

#trace_disabled?(options) ⇒ Boolean

Tracing is disabled if we are not in a traced context and no force option is supplied

Returns:

  • (Boolean)


113
114
115
# File 'lib/new_relic/agent/method_tracer.rb', line 113

def trace_disabled?(options)
  !(traced? || options[:force])
end

#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.



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/new_relic/agent/method_tracer.rb', line 226

def trace_execution_scoped(metric_names, options={})
  return yield if trace_disabled?(options)
  set_if_nil(options, :metric)
  set_if_nil(options, :deduct_call_time_from_parent)
  metric_names = Array(metric_names)
  first_name = metric_names.shift
  scope = stat_engine.scope_name
  start_time, expected_scope = trace_execution_scoped_header(first_name, options)
  begin 
    yield
  ensure
    metric_specs = get_metric_specs(first_name, metric_names, scope, options)
    trace_execution_scoped_footer(start_time, first_name, metric_specs, expected_scope, options[:force])
  end
end

Handles the end of the #trace_execution_scoped method - calculating the time taken, popping the tracing flag if needed, deducting time taken by children, and tracing the subsidiary unscoped metrics if any

this method fails safely if the header does not manage to push the scope onto the stack - it simply does not trace any metrics.



202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/new_relic/agent/method_tracer.rb', line 202

def trace_execution_scoped_footer(t0, first_name, metric_specs, expected_scope, forced, t1=Time.now.to_f)
  log_errors("trace_method_execution footer", first_name) do
    duration = t1 - t0

    pop_flag!(forced)
    if expected_scope
      scope = stat_engine.pop_scope(expected_scope, duration, t1)
      exclusive = duration - scope.children_time
      stat_engine.record_metrics(metric_specs) do |stat|
        stat.record_data_point(duration, exclusive)
      end
    end
  end
end

#trace_execution_scoped_header(metric, options, t0 = Time.now.to_f) ⇒ Object

provides the header for our traced execution scoped method - gets the initial time, sets the tracing flag if needed, and pushes the scope onto the metric stack logs any errors that occur and returns the start time and the scope so that we can check for it later, to maintain sanity. If the scope stack becomes unbalanced, this transaction loses meaning.



184
185
186
187
188
189
190
191
192
# File 'lib/new_relic/agent/method_tracer.rb', line 184

def trace_execution_scoped_header(metric, options, t0=Time.now.to_f)
  scope = log_errors("trace_execution_scoped header", metric) do
    push_flag!(options[:force])
    scope = stat_engine.push_scope(metric, t0, options[:deduct_call_time_from_parent])
  end
  # needed in case we have an error, above, to always return
  # the start time.
  [t0, scope]
end

#traced?Boolean

Shorthand to return the status of tracing

Returns:

  • (Boolean)


107
108
109
# File 'lib/new_relic/agent/method_tracer.rb', line 107

def traced?
  NewRelic::Agent.is_execution_traced?
end