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

Extended by:
TraceExecutionScoped
Included in:
NewRelic::Agent::MethodTracer, TraceExecutionScoped
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



99
100
101
# File 'lib/new_relic/agent/method_tracer.rb', line 99

def agent_instance
  NewRelic::Agent.instance
end

#get_stats_scoped(first_name, scoped_metric_only) ⇒ Object

returns a scoped metric stat for the specified name



120
121
122
# File 'lib/new_relic/agent/method_tracer.rb', line 120

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



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

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

#has_parent?Boolean

Returns:

  • (Boolean)


199
200
201
# File 'lib/new_relic/agent/method_tracer.rb', line 199

def has_parent?
  !NewRelic::Agent::Transaction.parent.nil?
end

#log_errors(code_area) ⇒ Object

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



157
158
159
160
161
# File 'lib/new_relic/agent/method_tracer.rb', line 157

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

#metrics_for_current_transaction(first_name, other_names, options) ⇒ Object



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/new_relic/agent/method_tracer.rb', line 180

def metrics_for_current_transaction(first_name, other_names, options)
  metrics = []

  if !options[:scoped_metric_only]
    metrics += other_names.map { |n| NewRelic::MetricSpec.new(n) }
  end

  if options[:metric]
    if !options[:scoped_metric_only]
      metrics << NewRelic::MetricSpec.new(first_name)
    end
    if NewRelic::Agent::Transaction.in_transaction? && !options[:transaction]
      metrics << NewRelic::MetricSpec.new(first_name, StatsEngine::MetricStats::SCOPE_PLACEHOLDER)
    end
  end

  metrics
end

#metrics_for_parent_transaction(first_name, options) ⇒ Object



203
204
205
206
207
208
209
# File 'lib/new_relic/agent/method_tracer.rb', line 203

def metrics_for_parent_transaction(first_name, options)
  if has_parent? && options[:metric] && options[:transaction]
    [NewRelic::MetricSpec.new(first_name, StatsEngine::MetricStats::SCOPE_PLACEHOLDER)]
  else
    []
  end
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



151
152
153
# File 'lib/new_relic/agent/method_tracer.rb', line 151

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.



140
141
142
# File 'lib/new_relic/agent/method_tracer.rb', line 140

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

#record_metrics(first_name, other_names, duration, exclusive, options) ⇒ Object



211
212
213
214
215
216
217
218
219
220
# File 'lib/new_relic/agent/method_tracer.rb', line 211

def record_metrics(first_name, other_names, duration, exclusive, options)
  metrics = metrics_for_current_transaction(first_name, other_names, options)
  stat_engine.record_metrics_internal(metrics, duration, exclusive)

  parent_metrics = metrics_for_parent_transaction(first_name, options)
  parent_metrics.each do |metric|
    parent_txn = NewRelic::Agent::Transaction.parent
    parent_txn.stats_hash.record(metric, duration, exclusive)
  end
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



131
132
133
# File 'lib/new_relic/agent/method_tracer.rb', line 131

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

#stat_engineObject

Shorthand to return the current statistics engine



115
116
117
# File 'lib/new_relic/agent/method_tracer.rb', line 115

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)


110
111
112
# File 'lib/new_relic/agent/method_tracer.rb', line 110

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.



251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/new_relic/agent/method_tracer.rb', line 251

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
  start_time, expected_scope = trace_execution_scoped_header(options)
  begin
    yield
  ensure
    trace_execution_scoped_footer(start_time, first_name, metric_names, expected_scope, options)
  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.



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

def trace_execution_scoped_footer(t0, first_name, metric_names, expected_scope, options, t1=Time.now.to_f)
  log_errors("trace_method_execution footer") do
    pop_flag!(options[:force])
    if expected_scope
      scope = stat_engine.pop_scope(expected_scope, first_name, t1)
      duration = t1 - t0
      exclusive = duration - scope.children_time
      record_metrics(first_name, metric_names, duration, exclusive, options)
    end
  end
end

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



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

def trace_execution_scoped_header(options, t0=Time.now.to_f)
  scope = log_errors("trace_execution_scoped header") do
    push_flag!(options[:force])
    scope = stat_engine.push_scope(:method_tracer, 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)


104
105
106
# File 'lib/new_relic/agent/method_tracer.rb', line 104

def traced?
  NewRelic::Agent.is_execution_traced?
end