class NewRelic::Agent::Transaction

This class represents a single transaction (usually mapping to one web request or background job invocation) instrumented by the Ruby agent.

@api public

Constants

APDEX_ALL_METRIC
APDEX_F
APDEX_METRIC
APDEX_OTHER_METRIC
APDEX_OTHER_TXN_METRIC_PREFIX
APDEX_S
APDEX_T
APDEX_TXN_METRIC_PREFIX
CONTROLLER_MIDDLEWARE_PREFIX
CONTROLLER_PREFIX
EMPTY_SUMMARY_METRICS
FAILED_TO_STOP_MESSAGE
GRAPE_PREFIX
GUID_LENGTH
HEX_DIGITS
JRUBY_CPU_TIME_ERROR
MIDDLEWARE_PREFIX
MIDDLEWARE_SUMMARY_METRICS
NESTED_TRACE_STOP_OPTIONS
OTHER_SUMMARY_METRIC
OTHER_TRANSACTION_PREFIX
QUEUE_TIME_METRIC
RACK_PREFIX
RAKE_PREFIX
SINATRA_PREFIX
SUBTRANSACTION_PREFIX

for nested transactions

TASK_PREFIX
TRACE_OPTIONS_SCOPED
TRACE_OPTIONS_UNSCOPED
TRANSACTION_NAMING_SOURCES
WEB_SUMMARY_METRIC
WEB_TRANSACTION_CATEGORIES

Attributes

apdex_start[RW]

A Time instance used for calculating the apdex score, which might end up being @start, or it might be further upstream if we can find a request header for the queue entry time

attributes[R]
cat_path_hashes[R]
category[R]
exceptions[RW]
filtered_params[RW]
frame_stack[R]
gc_start_snapshot[R]
guid[R]
http_response_code[RW]
jruby_cpu_start[RW]
metrics[R]
payload[R]
process_cpu_start[RW]
raw_synthetics_header[RW]

Fields for tracking synthetics requests

response_content_length[RW]
response_content_type[RW]
start_time[RW]

A Time instance for the start time, never nil

synthetics_payload[RW]

Fields for tracking synthetics requests

transaction_trace[R]

Populated with the trace sample once this transaction is completed.

Public Class Methods

abort_transaction!() click to toggle source

Indicate that you don't want to keep the currently saved transaction information

# File lib/new_relic/agent/transaction.rb, line 184
def self.abort_transaction! #THREAD_LOCAL_ACCESS
  state = NewRelic::Agent::TransactionState.tl_get
  txn = state.current_transaction
  txn.abort_transaction!(state) if txn
end
add_agent_attribute(key, value, default_destinations) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 224
def self.add_agent_attribute(key, value, default_destinations)
  if txn = tl_current
    txn.add_agent_attribute(key, value, default_destinations)
  else
    NewRelic::Agent.logger.debug "Attempted to add agent attribute: #{key} without transaction"
  end
end
apdex_bucket(duration, failed, apdex_t) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 211
def self.apdex_bucket(duration, failed, apdex_t)
  case
  when failed
    :apdex_f
  when duration <= apdex_t
    :apdex_s
  when duration <= 4 * apdex_t
    :apdex_t
  else
    :apdex_f
  end
end
merge_untrusted_agent_attributes(attributes, prefix, default_destinations) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 236
def self.merge_untrusted_agent_attributes(attributes, prefix, default_destinations)
  if txn = tl_current
    txn.merge_untrusted_agent_attributes(attributes, prefix, default_destinations)
  else
    NewRelic::Agent.logger.debug "Attempted to merge untrusted attributes without transaction"
  end
end
nested_transaction_name(name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 174
def self.nested_transaction_name(name)
  if name.start_with?(CONTROLLER_PREFIX) || name.start_with?(OTHER_TRANSACTION_PREFIX)
    "#{SUBTRANSACTION_PREFIX}#{name}"
  else
    name
  end
end
new(category, options) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 260
def initialize(category, options)
  @frame_stack = []
  @has_children = false

  self.default_name = options[:transaction_name]
  @overridden_name    = nil
  @frozen_name      = nil

  @category = category
  @start_time = Time.now
  @apdex_start = options[:apdex_start_time] || @start_time
  @jruby_cpu_start = jruby_cpu_time
  @process_cpu_start = process_cpu
  @gc_start_snapshot = NewRelic::Agent::StatsEngine::GCProfiler.take_snapshot
  @filtered_params = options[:filtered_params] || {}

  @exceptions = {}
  @metrics = TransactionMetrics.new
  @guid = generate_guid
  @cat_path_hashes = nil

  @ignore_this_transaction = false
  @ignore_apdex = false
  @ignore_enduser = false
  @ignore_trace = false

  @attributes = Attributes.new(NewRelic::Agent.instance.attribute_filter)

  merge_request_parameters(@filtered_params)

  if request = options[:request]
    @request_attributes = RequestAttributes.new request
  else
    @request_attributes = nil
  end
end
notice_error(e, options={}) click to toggle source

See NewRelic::Agent#notice_error for options and commentary

# File lib/new_relic/agent/transaction.rb, line 191
def self.notice_error(e, options={}) #THREAD_LOCAL_ACCESS
  state = NewRelic::Agent::TransactionState.tl_get
  txn = state.current_transaction
  if txn
    txn.notice_error(e, options)
  elsif NewRelic::Agent.instance
    NewRelic::Agent.instance.error_collector.notice_error(e, options)
  end
end
recording_web_transaction?() click to toggle source

Returns truthy if the current in-progress transaction is considered a a web transaction (as opposed to, e.g., a background transaction).

@api public

# File lib/new_relic/agent/transaction.rb, line 206
def self.recording_web_transaction? #THREAD_LOCAL_ACCESS
  txn = tl_current
  txn && txn.recording_web_transaction?
end
set_default_transaction_name(name, category = nil, node_name = nil) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 78
def self.set_default_transaction_name(name, category = nil, node_name = nil) #THREAD_LOCAL_ACCESS
  txn  = tl_current
  name = txn.make_transaction_name(name, category)
  txn.name_last_frame(node_name || name)
  txn.set_default_transaction_name(name, category)
end
set_overriding_transaction_name(name, category = nil) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 85
def self.set_overriding_transaction_name(name, category = nil) #THREAD_LOCAL_ACCESS
  txn = tl_current
  return unless txn

  name = txn.make_transaction_name(name, category)

  txn.name_last_frame(name)
  txn.set_overriding_transaction_name(name, category)
end
start(state, category, options) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 110
def self.start(state, category, options)
  category ||= :controller
  txn = state.current_transaction

  if txn
    txn.create_nested_frame(state, category, options)
  else
    txn = start_new_transaction(state, category, options)
  end

  txn
rescue => e
  NewRelic::Agent.logger.error("Exception during Transaction.start", e)
  nil
end
start_new_transaction(state, category, options) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 126
def self.start_new_transaction(state, category, options)
  txn = Transaction.new(category, options)
  state.reset(txn)
  txn.start(state)
  txn
end
stop(state, end_time=Time.now) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 135
def self.stop(state, end_time=Time.now)
  txn = state.current_transaction

  if txn.nil?
    NewRelic::Agent.logger.error(FAILED_TO_STOP_MESSAGE)
    return
  end

  nested_frame = txn.frame_stack.pop

  if txn.frame_stack.empty?
    txn.stop(state, end_time, nested_frame)
    state.reset
  else
    nested_name = nested_transaction_name(nested_frame.name)

    if nested_name.start_with?(MIDDLEWARE_PREFIX)
      summary_metrics = MIDDLEWARE_SUMMARY_METRICS
    else
      summary_metrics = EMPTY_SUMMARY_METRICS
    end

    NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped_footer(
      state,
      nested_frame.start_time.to_f,
      nested_name,
      summary_metrics,
      nested_frame,
      NESTED_TRACE_STOP_OPTIONS,
      end_time.to_f)
  end

  :transaction_stopped
rescue => e
  state.reset
  NewRelic::Agent.logger.error("Exception during Transaction.stop", e)
  nil
end
tl_current() click to toggle source

Return the currently active transaction, or nil.

# File lib/new_relic/agent/transaction.rb, line 74
def self.tl_current
  TransactionState.tl_get.current_transaction
end
wrap(state, name, category, options = {}) { || ... } click to toggle source
# File lib/new_relic/agent/transaction.rb, line 95
def self.wrap(state, name, category, options = {})
  Transaction.start(state, category, options.merge(:transaction_name => name))

  begin
    # We shouldn't raise from Transaction.start, but only wrap the yield
    # to be absolutely sure we don't report agent problems as app errors
    yield
  rescue => e
    Transaction.notice_error(e)
    raise e
  ensure
    Transaction.stop(state)
  end
end

Public Instance Methods

abort_transaction!(state) click to toggle source

Call this to ensure that the current transaction trace is not saved To fully ignore all metrics and errors, use ignore! instead.

# File lib/new_relic/agent/transaction.rb, line 440
def abort_transaction!(state)
  @ignore_trace = true
end
add_agent_attribute(key, value, default_destinations) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 232
def add_agent_attribute(key, value, default_destinations)
  @attributes.add_agent_attribute(key, value, default_destinations)
end
add_custom_attributes(p) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 852
def add_custom_attributes(p)
  attributes.merge_custom_attributes(p)
end
add_custom_parameters(p)
apdex_bucket(duration, current_apdex_t) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 794
def apdex_bucket(duration, current_apdex_t)
  self.class.apdex_bucket(duration, had_error?, current_apdex_t)
end
apdex_t() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 827
def apdex_t
  transaction_specific_apdex_t || Agent.config[:apdex_t]
end
append_apdex_perf_zone(duration, payload) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 677
def append_apdex_perf_zone(duration, payload)
  if recording_web_transaction?
    bucket = apdex_bucket(duration, apdex_t)
  elsif background_apdex_t = transaction_specific_apdex_t
    bucket = apdex_bucket(duration, background_apdex_t)
  end

  return unless bucket

  bucket_str = case bucket
  when :apdex_s then APDEX_S
  when :apdex_t then APDEX_T
  when :apdex_f then APDEX_F
  else nil
  end
  payload[:apdex_perf_zone] = bucket_str if bucket_str
end
append_cat_info(state, duration, payload) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 695
def append_cat_info(state, duration, payload)
  return unless include_guid?(state, duration)
  payload[:guid] = guid

  return unless state.is_cross_app?
  trip_id             = cat_trip_id(state)
  path_hash           = cat_path_hash(state)
  referring_path_hash = cat_referring_path_hash(state)

  payload[:cat_trip_id]             = trip_id             if trip_id
  payload[:cat_referring_path_hash] = referring_path_hash if referring_path_hash

  if path_hash
    payload[:cat_path_hash] = path_hash

    alternate_path_hashes = cat_path_hashes - [path_hash]
    unless alternate_path_hashes.empty?
      payload[:cat_alternate_path_hashes] = alternate_path_hashes
    end
  end
end
append_referring_transaction_guid_to(state, payload) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 725
def append_referring_transaction_guid_to(state, payload)
  referring_guid = NewRelic::Agent.instance.cross_app_monitor.client_referring_transaction_guid(state)
  if referring_guid
    payload[:referring_transaction_guid] = referring_guid
  end
end
append_synthetics_to(state, payload) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 717
def append_synthetics_to(state, payload)
  return unless is_synthetics_request?

  payload[:synthetics_resource_id] = synthetics_resource_id
  payload[:synthetics_job_id]      = synthetics_job_id
  payload[:synthetics_monitor_id]  = synthetics_monitor_id
end
assign_agent_attributes() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 533
def assign_agent_attributes
  default_destinations = AttributeFilter::DST_TRANSACTION_TRACER |
                         AttributeFilter::DST_TRANSACTION_EVENTS |
                         AttributeFilter::DST_ERROR_COLLECTOR

  if http_response_code
    add_agent_attribute(:httpResponseCode, http_response_code.to_s, default_destinations)
  end

  if response_content_length
    add_agent_attribute(:'response.headers.contentLength', response_content_length.to_i, default_destinations)
  end

  if response_content_type
    add_agent_attribute(:'response.headers.contentType', response_content_type, default_destinations)
  end

  if @request_attributes
    @request_attributes.assign_agent_attributes self
  end

  display_host = Agent.config[:'process_host.display_name']
  unless display_host == NewRelic::Agent::Hostname.get
    add_agent_attribute(:'host.displayName', display_host, default_destinations)
  end
end
assign_intrinsics(state) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 560
def assign_intrinsics(state)
  if gc_time = calculate_gc_time
    attributes.add_intrinsic_attribute(:gc_time, gc_time)
  end

  if burn = cpu_burn
    attributes.add_intrinsic_attribute(:cpu_time, burn)
  end

  if is_synthetics_request?
    attributes.add_intrinsic_attribute(:synthetics_resource_id, synthetics_resource_id)
    attributes.add_intrinsic_attribute(:synthetics_job_id, synthetics_job_id)
    attributes.add_intrinsic_attribute(:synthetics_monitor_id, synthetics_monitor_id)
  end

  if state.is_cross_app?
    attributes.add_intrinsic_attribute(:trip_id, cat_trip_id(state))
    attributes.add_intrinsic_attribute(:path_hash, cat_path_hash(state))
  end
end
background_summary_metrics() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 455
def background_summary_metrics
  segments = @frozen_name.split('/')
  if segments.size > 2
    ["OtherTransaction/#{segments[1]}/all", OTHER_SUMMARY_METRIC]
  else
    []
  end
end
best_name() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 386
def best_name
  @frozen_name  || @overridden_name ||
    @default_name || NewRelic::Agent::UNKNOWN_METRIC
end
calculate_gc_time() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 581
def calculate_gc_time
  gc_stop_snapshot = NewRelic::Agent::StatsEngine::GCProfiler.take_snapshot
  NewRelic::Agent::StatsEngine::GCProfiler.record_delta(gc_start_snapshot, gc_stop_snapshot)
end
cat_path_hash(state) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 625
def cat_path_hash(state)
  referring_path_hash = cat_referring_path_hash(state) || '0'
  seed = referring_path_hash.to_i(16)
  result = NewRelic::Agent.instance.cross_app_monitor.path_hash(best_name, seed)
  record_cat_path_hash(result)
  result
end
cat_referring_path_hash(state) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 640
def cat_referring_path_hash(state)
  NewRelic::Agent.instance.cross_app_monitor.client_referring_transaction_path_hash(state)
end
cat_trip_id(state) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 621
def cat_trip_id(state)
  NewRelic::Agent.instance.cross_app_monitor.client_referring_transaction_trip_id(state) || guid
end
commit!(state, end_time, outermost_node_name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 513
def commit!(state, end_time, outermost_node_name)
  assign_agent_attributes
  assign_intrinsics(state)

  @transaction_trace = transaction_sampler.on_finishing_transaction(state, self, end_time)
  sql_sampler.on_finishing_transaction(state, @frozen_name)

  record_summary_metrics(outermost_node_name, end_time)
  record_apdex(state, end_time) unless ignore_apdex?
  record_queue_time

  generate_payload(state, start_time, end_time)

  record_exceptions
  record_transaction_event

  merge_metrics
  send_transaction_finished_event
end
cpu_burn() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 871
def cpu_burn
  normal_cpu_burn || jruby_cpu_burn
end
create_nested_frame(state, category, options) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 335
def create_nested_frame(state, category, options)
  @has_children = true
  if options[:filtered_params] && !options[:filtered_params].empty?
    @filtered_params = options[:filtered_params]
    merge_request_parameters(options[:filtered_params])
  end

  frame_stack.push NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped_header(state, Time.now.to_f)
  name_last_frame(options[:transaction_name])

  set_default_transaction_name(options[:transaction_name], category)
end
default_name=(name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 331
def default_name=(name)
  @default_name = Helper.correctly_encoded(name)
end
freeze_name_and_execute_if_not_ignored() { || ... } click to toggle source
# File lib/new_relic/agent/transaction.rb, line 403
def freeze_name_and_execute_if_not_ignored
  if !name_frozen?
    name = promoted_transaction_name(best_name)
    name = NewRelic::Agent.instance.transaction_rules.rename(name)
    @name_frozen = true

    if name.nil?
      ignore!
      @frozen_name = best_name
    else
      @frozen_name = name
    end
  end

  if block_given? && !@ignore_this_transaction
    yield
  end
end
generate_payload(state, start_time, end_time) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 600
def generate_payload(state, start_time, end_time)
  duration = end_time.to_f - start_time.to_f
  @payload = {
    :name                 => @frozen_name,
    :bucket               => recording_web_transaction? ? :request : :background,
    :start_timestamp      => start_time.to_f,
    :duration             => duration,
    :metrics              => @metrics,
    :attributes           => @attributes,
    :error                => false
  }
  append_cat_info(state, duration, @payload)
  append_apdex_perf_zone(duration, @payload)
  append_synthetics_to(state, @payload)
  append_referring_transaction_guid_to(state, @payload)
end
had_error?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 787
def had_error?
  @exceptions.each do |exception, _|
    return true unless NewRelic::Agent.instance.error_collector.error_is_ignored?(exception)
  end
  false
end
ignore!() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 885
def ignore!
  @ignore_this_transaction = true
end
ignore?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 889
def ignore?
  @ignore_this_transaction
end
ignore_apdex!() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 893
def ignore_apdex!
  @ignore_apdex = true
end
ignore_apdex?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 897
def ignore_apdex?
  @ignore_apdex
end
ignore_enduser!() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 901
def ignore_enduser!
  @ignore_enduser = true
end
ignore_enduser?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 905
def ignore_enduser?
  @ignore_enduser
end
ignore_trace?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 909
def ignore_trace?
  @ignore_trace
end
include_guid?(state, duration) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 617
def include_guid?(state, duration)
  state.is_cross_app? || is_synthetics_request?
end
influences_transaction_name?(category) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 382
def influences_transaction_name?(category)
  !category || frame_stack.size == 1 || similar_category?(category)
end
instrumentation_state() click to toggle source

This transaction-local hash may be used as temprory storage by instrumentation that needs to pass data from one instrumentation point to another.

For example, if both A and B are instrumented, and A calls B but some piece of state needed by the instrumentation at B is only available at A, the instrumentation at A may write into the hash, call through, and then remove the key afterwards, allowing the instrumentation at B to read the value in between.

Keys should be symbols, and care should be taken to not generate key names dynamically, and to ensure that keys are removed upon return from the method that creates them.

# File lib/new_relic/agent/transaction.rb, line 323
def instrumentation_state
  @instrumentation_state ||= {}
end
is_synthetics_request?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 644
def is_synthetics_request?
  synthetics_payload != nil && raw_synthetics_header != nil
end
jruby_cpu_burn() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 880
def jruby_cpu_burn
  return unless @jruby_cpu_start
  jruby_cpu_time - @jruby_cpu_start
end
log_frozen_name(name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 377
def log_frozen_name(name)
  NewRelic::Agent.logger.warn("Attempted to rename transaction to '#{name}' after transaction name was already frozen as '#{@frozen_name}'.")
  nil
end
make_transaction_name(name, category=nil) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 352
def make_transaction_name(name, category=nil)
  namer = Instrumentation::ControllerInstrumentation::TransactionNamer
  "#{namer.prefix_for_category(self, category)}#{name}"
end
merge_metrics() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 732
def merge_metrics
  NewRelic::Agent.instance.stats_engine.merge_transaction_metrics!(@metrics, best_name)
end
merge_request_parameters(params) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 348
def merge_request_parameters(params)
  merge_untrusted_agent_attributes(params, :'request.parameters', AttributeFilter::DST_NONE)
end
merge_untrusted_agent_attributes(attributes, prefix, default_destinations) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 244
def merge_untrusted_agent_attributes(attributes, prefix, default_destinations)
  @attributes.merge_untrusted_agent_attributes(attributes, prefix, default_destinations)
end
name_frozen?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 422
def name_frozen?
  @frozen_name ? true : false
end
name_last_frame(name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 373
def name_last_frame(name)
  frame_stack.last.name = name
end
name_set?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 391
def name_set?
  (@overridden_name || @default_name) ? true : false
end
needs_middleware_summary_metrics?(name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 464
def needs_middleware_summary_metrics?(name)
  name.start_with?(MIDDLEWARE_PREFIX)
end
normal_cpu_burn() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 875
def normal_cpu_burn
  return unless @process_cpu_start
  process_cpu - @process_cpu_start
end
overridden_name=(name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 327
def overridden_name=(name)
  @overridden_name = Helper.correctly_encoded(name)
end
promoted_transaction_name(name) click to toggle source
queue_time() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 764
def queue_time
  @apdex_start ? @start_time - @apdex_start : 0
end
record_apdex(state, end_time=Time.now) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 798
def record_apdex(state, end_time=Time.now)
  return unless state.is_execution_traced?

  freeze_name_and_execute_if_not_ignored do
    total_duration  = end_time - apdex_start
    action_duration = end_time - start_time

    if recording_web_transaction?
      record_apdex_metrics(APDEX_METRIC, APDEX_TXN_METRIC_PREFIX,
                           total_duration, action_duration, apdex_t)
    else
      record_apdex_metrics(APDEX_OTHER_METRIC, APDEX_OTHER_TXN_METRIC_PREFIX,
                           total_duration, action_duration, transaction_specific_apdex_t)
    end
  end
end
record_apdex_metrics(rollup_metric, transaction_prefix, total_duration, action_duration, current_apdex_t) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 815
def record_apdex_metrics(rollup_metric, transaction_prefix, total_duration, action_duration, current_apdex_t)
  return unless current_apdex_t

  apdex_bucket_global = apdex_bucket(total_duration, current_apdex_t)
  apdex_bucket_txn    = apdex_bucket(action_duration, current_apdex_t)

  @metrics.record_unscoped(rollup_metric, apdex_bucket_global, current_apdex_t)
  @metrics.record_unscoped(APDEX_ALL_METRIC, apdex_bucket_global, current_apdex_t)
  txn_apdex_metric = @frozen_name.sub(/^[^\/]+\//, transaction_prefix)
  @metrics.record_unscoped(txn_apdex_metric, apdex_bucket_txn, current_apdex_t)
end
record_cat_path_hash(hash) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 633
def record_cat_path_hash(hash)
  @cat_path_hashes ||= []
  if @cat_path_hashes.size < 10 && !@cat_path_hashes.include?(hash)
    @cat_path_hashes << hash
  end
end
record_exceptions() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 736
def record_exceptions
  error_recorded = false
  @exceptions.each do |exception, options|
    options[:uri]      ||= request_path if request_path
    options[:port]       = request_port if request_port
    options[:metric]     = best_name
    options[:attributes] = @attributes

    error_recorded = !!agent.error_collector.notice_error(exception, options) || error_recorded
  end
  payload[:error] = error_recorded if payload
end
record_queue_time() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 768
def record_queue_time
  value = queue_time
  if value > 0.0
    if value < MethodTracerHelpers::MAX_ALLOWED_METRIC_DURATION
      @metrics.record_unscoped(QUEUE_TIME_METRIC, value)
    else
      ::NewRelic::Agent.logger.log_once(:warn, :too_high_queue_time, "Not recording unreasonably large queue time of #{value} s")
    end
  end
end
record_summary_metrics(outermost_node_name, end_time) click to toggle source

The summary metrics recorded by this method all end up with a duration equal to the transaction itself, and an exclusive time of zero.

# File lib/new_relic/agent/transaction.rb, line 588
def record_summary_metrics(outermost_node_name, end_time)
  metrics = summary_metrics
  metrics << @frozen_name unless @frozen_name == outermost_node_name
  @metrics.record_unscoped(metrics, end_time.to_f - start_time.to_f, 0)
end
record_transaction_event() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 758
def record_transaction_event
  agent.transaction_event_recorder.record payload
end
recording_web_transaction?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 859
def recording_web_transaction?
  web_category?(@category)
end
referer() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 297
def referer
  @request_attributes && @request_attributes.referer
end
request_path() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 301
def request_path
  @request_attributes && @request_attributes.request_path
end
request_port() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 305
def request_port
  @request_attributes && @request_attributes.port
end
send_transaction_finished_event() click to toggle source

This event is fired when the transaction is fully completed. The metric values and sampler can't be successfully modified from this event.

# File lib/new_relic/agent/transaction.rb, line 596
def send_transaction_finished_event
  agent.events.notify(:transaction_finished, payload)
end
set_default_transaction_name(name, category) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 357
def set_default_transaction_name(name, category)
  return log_frozen_name(name) if name_frozen?
  if influences_transaction_name?(category)
    self.default_name = name
    @category = category if category
  end
end
set_overriding_transaction_name(name, category) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 365
def set_overriding_transaction_name(name, category)
  return log_frozen_name(name) if name_frozen?
  if influences_transaction_name?(category)
    self.overridden_name = name
    @category = category if category
  end
end
set_user_attributes(p)
similar_category?(category) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 867
def similar_category?(category)
  web_category?(@category) == web_category?(category)
end
start(state) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 426
def start(state)
  return if !state.is_execution_traced?

  transaction_sampler.on_start_transaction(state, start_time)
  sql_sampler.on_start_transaction(state, start_time, request_path)
  NewRelic::Agent.instance.events.notify(:start_transaction)
  NewRelic::Agent::BusyCalculator.dispatcher_start(start_time)

  frame_stack.push NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped_header(state, start_time.to_f)
  name_last_frame @default_name
end
stop(state, end_time, outermost_frame) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 468
def stop(state, end_time, outermost_frame)
  return if !state.is_execution_traced?
  freeze_name_and_execute_if_not_ignored
  ignore! if user_defined_rules_ignore?

  if @has_children
    name = Transaction.nested_transaction_name(outermost_frame.name)
    trace_options = TRACE_OPTIONS_SCOPED
  else
    name = @frozen_name
    trace_options = TRACE_OPTIONS_UNSCOPED
  end

  # These metrics are recorded here instead of in record_summary_metrics
  # in order to capture the exclusive time associated with the outer-most
  # TT node.
  if needs_middleware_summary_metrics?(name)
    summary_metrics_with_exclusive_time = MIDDLEWARE_SUMMARY_METRICS
  else
    summary_metrics_with_exclusive_time = EMPTY_SUMMARY_METRICS
  end

  NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped_footer(
    state,
    start_time.to_f,
    name,
    summary_metrics_with_exclusive_time,
    outermost_frame,
    trace_options,
    end_time.to_f)

  NewRelic::Agent::BusyCalculator.dispatcher_finish(end_time)

  commit!(state, end_time, name) unless @ignore_this_transaction
end
summary_metrics() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 447
def summary_metrics
  if @frozen_name.start_with?(CONTROLLER_PREFIX)
    [WEB_SUMMARY_METRIC]
  else
    background_summary_metrics
  end
end
synthetics_account_id() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 653
def synthetics_account_id
  info = synthetics_payload or return nil
  info[1]
end
synthetics_job_id() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 663
def synthetics_job_id
  info = synthetics_payload or return nil
  info[3]
end
synthetics_monitor_id() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 668
def synthetics_monitor_id
  info = synthetics_payload or return nil
  info[4]
end
synthetics_resource_id() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 658
def synthetics_resource_id
  info = synthetics_payload or return nil
  info[2]
end
synthetics_version() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 648
def synthetics_version
  info = synthetics_payload or return nil
  info[0]
end
transaction_specific_apdex_t() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 831
def transaction_specific_apdex_t
  key = :web_transactions_apdex
  Agent.config[key] && Agent.config[key][best_name]
end
user_defined_rules_ignore?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 504
def user_defined_rules_ignore?
  return unless request_path
  return if (rules = NewRelic::Agent.config[:"rules.ignore_url_regexes"]).empty?

  rules.any? do |rule|
    request_path.match(rule)
  end
end
web_category?(category) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 863
def web_category?(category)
  WEB_TRANSACTION_CATEGORIES.include?(category)
end
with_database_metric_name(model, method, product=nil) { || ... } click to toggle source
# File lib/new_relic/agent/transaction.rb, line 836
def with_database_metric_name(model, method, product=nil)
  previous = self.instrumentation_state[:datastore_override]
  model_name = case model
               when Class
                 model.name
               when String
                 model
               else
                 model.to_s
               end
  self.instrumentation_state[:datastore_override] = [method, model_name, product]
  yield
ensure
  self.instrumentation_state[:datastore_override] = previous
end

Private Instance Methods

agent() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 936
def agent
  NewRelic::Agent.instance
end
generate_guid() click to toggle source

generate a random 64 bit uuid

# File lib/new_relic/agent/transaction.rb, line 952
def generate_guid
  guid = ''
  GUID_LENGTH.times do |a|
    guid << HEX_DIGITS[rand(16)]
  end
  guid
end
jruby_cpu_time() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 922
def jruby_cpu_time
  return nil unless @@java_classes_loaded
  threadMBean = Java::JavaLangManagement::ManagementFactory.getThreadMXBean()

  return nil unless threadMBean.isCurrentThreadCpuTimeSupported
  java_utime = threadMBean.getCurrentThreadUserTime()  # ns

  -1 == java_utime ? 0.0 : java_utime/1e9
rescue => e
  ::NewRelic::Agent.logger.log_once(:warn, :jruby_cpu_time, JRUBY_CPU_TIME_ERROR, e)
  ::NewRelic::Agent.logger.debug(JRUBY_CPU_TIME_ERROR, e)
  nil
end
process_cpu() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 915
def process_cpu
  return nil if defined? JRuby
  p = Process.times
  p.stime + p.utime
end
sql_sampler() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 944
def sql_sampler
  agent.sql_sampler
end
transaction_sampler() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 940
def transaction_sampler
  agent.transaction_sampler
end