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

ACTION_CABLE_PREFIX
APDEX_ALL_METRIC
APDEX_F
APDEX_METRIC
APDEX_OTHER_METRIC
APDEX_OTHER_TXN_METRIC_PREFIX
APDEX_S
APDEX_T
APDEX_TXN_METRIC_PREFIX
CONTROLLER_PREFIX
GRAPE_PREFIX
JRUBY_CPU_TIME_ERROR
MESSAGE_PREFIX
MIDDLEWARE_PREFIX
MIDDLEWARE_SUMMARY_METRICS
NESTED_TRANSACTION_PREFIX

for nested transactions

OTHER_SUMMARY_METRIC
OTHER_TRANSACTION_PREFIX
QUEUE_TIME_METRIC
RACK_PREFIX
RAKE_PREFIX
RODA_PREFIX
SINATRA_PREFIX
TASK_PREFIX
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]
category[R]
duration[R]
end_time[R]
exceptions[RW]
filtered_params[RW]
gc_start_snapshot[R]
guid[R]
http_response_code[RW]
jruby_cpu_start[RW]
logs[R]
metrics[R]
nesting_max_depth[R]
parent_span_id[RW]
payload[R]
priority[W]
process_cpu_start[RW]
raw_synthetics_header[RW]

Fields for tracking synthetics requests

raw_synthetics_info_header[RW]

Fields for tracking synthetics requests

response_content_length[RW]
response_content_type[RW]
sampled[W]
segments[R]
start_time[RW]

A Time instance for the start time, never nil

synthetics_info_payload[RW]

Fields for tracking synthetics requests

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

discards the currently saved transaction information

# File lib/new_relic/agent/transaction.rb, line 135
def self.abort_transaction!
  if txn = Tracer.current_transaction
    txn.abort_transaction!
  end
end
add_agent_attribute(key, value, default_destinations) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 175
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 162
def self.apdex_bucket(duration, failed, apdex_t)
  case
  when failed
    :apdex_f
  when duration <= apdex_t
    :apdex_s
  when duration <= apdex_t * 4
    :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 189
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
name_from_partial(partial_name, category) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 114
def self.name_from_partial(partial_name, category)
  namer = Instrumentation::ControllerInstrumentation::TransactionNamer
  "#{namer.prefix_for_category(self, category)}#{partial_name}"
end
nested_transaction_name(name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 126
def self.nested_transaction_name(name)
  if name.start_with?(CONTROLLER_PREFIX, OTHER_TRANSACTION_PREFIX)
    "#{NESTED_TRANSACTION_PREFIX}#{name}"
  else
    name
  end
end
new(category, options) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 214
def initialize(category, options) # rubocop:disable Metrics/AbcSize
  @nesting_max_depth = 0
  @current_segment_by_thread = {}
  @current_segment_lock = Mutex.new
  @segments = []

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

  @category = category
  @start_time = Process.clock_gettime(Process::CLOCK_REALTIME)
  @end_time = nil
  @duration = nil

  @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
  @logs = PrioritySampledBuffer.new(NewRelic::Agent.instance.log_event_aggregator.capacity)
  @guid = NewRelic::Agent::GuidGenerator.generate_guid

  @ignore_this_transaction = false
  @ignore_apdex = options.fetch(:ignore_apdex, false)
  @ignore_enduser = options.fetch(:ignore_enduser, false)
  @ignore_trace = false

  @sampled = nil
  @priority = nil

  @starting_thread_id = Thread.current.object_id
  @starting_segment_key = current_segment_key

  @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 142
def self.notice_error(e, options = {})
  if txn = Tracer.current_transaction
    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 155
def self.recording_web_transaction? # THREAD_LOCAL_ACCESS
  NewRelic::Agent.record_api_supportability_metric(:recording_web_transaction?)

  txn = tl_current
  txn&.recording_web_transaction?
end
set_default_transaction_name(partial_name, category = nil) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 100
def self.set_default_transaction_name(partial_name, category = nil) # THREAD_LOCAL_ACCESS
  txn = tl_current
  name = name_from_partial(partial_name, category || txn.category)
  txn.set_default_transaction_name(name, category)
end
set_overriding_transaction_name(partial_name, category = nil) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 106
def self.set_overriding_transaction_name(partial_name, category = nil) # THREAD_LOCAL_ACCESS
  txn = tl_current
  return unless txn

  name = name_from_partial(partial_name, category || txn.category)
  txn.set_overriding_transaction_name(name, category)
end
start_new_transaction(state, category, options) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 119
def self.start_new_transaction(state, category, options)
  txn = Transaction.new(category, options)
  state.reset(txn)
  txn.start(options)
  txn
end
tl_current() click to toggle source

Return the currently active transaction, or nil.

# File lib/new_relic/agent/transaction.rb, line 96
def self.tl_current
  Tracer.current_transaction
end

Public Instance Methods

abort_transaction!() 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 497
def abort_transaction!
  @ignore_trace = true
end
add_agent_attribute(key, value, default_destinations) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 183
def add_agent_attribute(key, value, default_destinations)
  @attributes.add_agent_attribute(key, value, default_destinations)
  # the following line needs else branch coverage
  current_segment.add_agent_attribute(key, value) if current_segment # rubocop:disable Style/SafeNavigation
end
add_custom_attributes(p) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 893
def add_custom_attributes(p)
  attributes.merge_custom_attributes(p)
end
add_log_event(event) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 897
def add_log_event(event)
  logs.append(event: event)
end
apdex_bucket(duration, current_apdex_t) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 828
def apdex_bucket(duration, current_apdex_t)
  self.class.apdex_bucket(duration, had_error_affecting_apdex?, current_apdex_t)
end
apdex_t() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 859
def apdex_t
  transaction_specific_apdex_t || Agent.config[:apdex_t]
end
append_apdex_perf_zone(payload) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 727
def append_apdex_perf_zone(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
  end
  payload[:apdex_perf_zone] = bucket_str if bucket_str
end
append_synthetics_to(payload) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 744
def append_synthetics_to(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
  payload[:synthetics_type] = synthetics_info('type')
  payload[:synthetics_initiator] = synthetics_info('initiator')

  synthetics_additional_attributes do |key, value|
    payload[key] = value
  end
end
assign_agent_attributes() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 586
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(:'http.statusCode', http_response_code, 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

  @request_attributes&.assign_agent_attributes(self)

  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() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 611
def assign_intrinsics
  attributes.add_intrinsic_attribute(:priority, priority)

  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)
    attributes.add_intrinsic_attribute(:synthetics_type, synthetics_info('type'))
    attributes.add_intrinsic_attribute(:synthetics_initiator, synthetics_info('initiator'))

    synthetics_additional_attributes do |key, value|
      attributes.add_intrinsic_attribute(key, value)
    end
  end

  distributed_tracer.assign_intrinsics
end
assign_segment_dt_attributes() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 579
def assign_segment_dt_attributes
  dt_payload = distributed_tracer.trace_state_payload || distributed_tracer.distributed_trace_payload
  parent_attributes = {}
  DistributedTraceAttributes.copy_parent_attributes(self, dt_payload, parent_attributes)
  parent_attributes.each { |k, v| initial_segment.add_agent_attribute(k, v) }
end
background_summary_metrics() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 509
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 380
def best_name
  @frozen_name ||
    @overridden_name ||
    @default_name ||
    NewRelic::Agent::UNKNOWN_METRIC
end
Also aliased as: transaction_name
calculate_gc_time() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 644
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
calculate_transport_duration(distributed_trace_payload) click to toggle source

This method returns transport_duration in seconds. Transport duration is stored in milliseconds on the payload, but it’s needed in seconds for metrics and intrinsics.

# File lib/new_relic/agent/transaction.rb, line 652
def calculate_transport_duration(distributed_trace_payload)
  return unless distributed_trace_payload

  duration = start_time - (distributed_trace_payload.timestamp / 1000.0)
  [duration, 0].max
end
commit!(outermost_node_name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 557
def commit!(outermost_node_name)
  generate_payload
  assign_intrinsics

  finalize_segments

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

  record_summary_metrics(outermost_node_name)
  record_total_time_metrics
  record_apdex unless ignore_apdex?
  record_queue_time
  distributed_tracer.record_metrics

  record_exceptions
  record_transaction_event
  record_log_events
  merge_metrics
  send_transaction_finished_event
end
cpu_burn() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 913
def cpu_burn
  normal_cpu_burn || jruby_cpu_burn
end
create_initial_segment(options = {}) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 447
def create_initial_segment(options = {})
  segment = create_segment(@default_name, options)
  segment.record_scoped_metric = false
end
create_nested_segment(category, options) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 473
def create_nested_segment(category, options)
  if options[:filtered_params] && !options[:filtered_params].empty?
    @filtered_params = options[:filtered_params]
    merge_request_parameters(options[:filtered_params])
  end

  @ignore_apdex = options[:ignore_apdex] if options.key?(:ignore_apdex)
  @ignore_enduser = options[:ignore_enduser] if options.key?(:ignore_enduser)

  nest_initial_segment if segments.length == 1
  nested_name = self.class.nested_transaction_name(options[:transaction_name])

  segment = create_segment(nested_name, options)
  set_default_transaction_name(options[:transaction_name], category)
  segment
end
create_segment(name, options = {}) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 452
def create_segment(name, options = {})
  summary_metrics = nil

  if name.start_with?(MIDDLEWARE_PREFIX)
    summary_metrics = MIDDLEWARE_SUMMARY_METRICS
  end

  @nesting_max_depth += 1

  segment = Tracer.start_segment(
    name: name,
    unscoped_metrics: summary_metrics
  )

  # #code_information will glean the code info out of the options hash
  # if it exists or noop otherwise
  segment.code_information = options

  segment
end
current_segment() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 274
def current_segment
  current_segment_by_thread[current_segment_key] ||
    current_segment_by_thread[parent_segment_key] ||
    current_segment_by_thread[@starting_segment_key]
end
current_segment_key() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 266
def current_segment_key
  Tracer.current_segment_key
end
default_name=(name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 347
def default_name=(name)
  @default_name = Helper.correctly_encoded(name)
end
distributed_tracer() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 288
def distributed_tracer
  @distributed_tracer ||= DistributedTracer.new(self)
end
finish() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 522
def finish
  return unless state.is_execution_traced? && initial_segment

  @end_time = Process.clock_gettime(Process::CLOCK_REALTIME)
  @duration = @end_time - @start_time
  freeze_name_and_execute_if_not_ignored

  if nesting_max_depth == 1
    initial_segment.name = @frozen_name
  end

  initial_segment.transaction_name = @frozen_name
  assign_segment_dt_attributes
  assign_agent_attributes
  initial_segment.finish

  NewRelic::Agent::TransactionTimeAggregator.transaction_stop(@end_time, @starting_thread_id)

  commit!(initial_segment.name) unless @ignore_this_transaction
rescue => e
  NewRelic::Agent.logger.error('Exception during Transaction#finish', e)
  nil
ensure
  state.reset
end
finished?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 443
def finished?
  initial_segment&.finished?
end
freeze_name_and_execute_if_not_ignored() { || ... } click to toggle source
# File lib/new_relic/agent/transaction.rb, line 399
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() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 673
def generate_payload
  @payload = {
    :name => @frozen_name,
    :bucket => recording_web_transaction? ? :request : :background,
    :start_timestamp => start_time,
    :duration => duration,
    :metrics => @metrics,
    :attributes => @attributes,
    :error => false,
    :priority => priority
  }

  distributed_tracer.append_payload(@payload)
  append_apdex_perf_zone(@payload)
  append_synthetics_to(@payload)
end
had_error_affecting_apdex?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 818
def had_error_affecting_apdex?
  @exceptions.each do |exception, options|
    ignored = NewRelic::Agent.instance.error_collector.error_is_ignored?(exception)
    expected = options[:expected]

    return true unless ignored || expected
  end
  false
end
ignore!() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 929
def ignore!
  @ignore_this_transaction = true
end
ignore?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 933
def ignore?
  @ignore_this_transaction
end
ignore_apdex!() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 937
def ignore_apdex!
  @ignore_apdex = true
end
ignore_apdex?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 941
def ignore_apdex?
  @ignore_apdex
end
ignore_enduser!() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 945
def ignore_enduser!
  @ignore_enduser = true
end
ignore_enduser?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 949
def ignore_enduser?
  @ignore_enduser
end
ignore_trace?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 953
def ignore_trace?
  @ignore_trace
end
include_guid?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 690
def include_guid?
  distributed_tracer.is_cross_app? || is_synthetics_request?
end
influences_transaction_name?(category) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 376
def influences_transaction_name?(category)
  !category || nesting_max_depth == 1 || similar_category?(category)
end
initial_segment() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 439
def initial_segment
  segments.first
end
instrumentation_state() click to toggle source

This transaction-local hash may be used as temporary 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 339
def instrumentation_state
  @instrumentation_state ||= {}
end
is_synthetics_request?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 694
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 923
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 371
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
merge_metrics() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 758
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 351
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 197
def merge_untrusted_agent_attributes(attributes, prefix, default_destinations)
  @attributes.merge_untrusted_agent_attributes(attributes, prefix, default_destinations)
  current_segment&.merge_untrusted_agent_attributes(attributes, prefix, default_destinations)
end
name_frozen?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 418
def name_frozen?
  @frozen_name ? true : false
end
needs_middleware_summary_metrics?(name) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 518
def needs_middleware_summary_metrics?(name)
  name.start_with?(MIDDLEWARE_PREFIX)
end
nest_initial_segment() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 490
def nest_initial_segment
  self.initial_segment.name = self.class.nested_transaction_name(initial_segment.name)
  initial_segment.record_scoped_metric = true
end
normal_cpu_burn() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 917
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 343
def overridden_name=(name)
  @overridden_name = Helper.correctly_encoded(name)
end
parent_segment_key() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 270
def parent_segment_key
  (::Fiber.current.nr_parent_key if ::Fiber.current.respond_to?(:nr_parent_key)) || (::Thread.current.nr_parent_key if ::Thread.current.respond_to?(:nr_parent_key))
end
priority() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 309
def priority
  @priority ||= (sampled? ? rand + 1.0 : rand).round(NewRelic::PRIORITY_PRECISION)
end
promoted_transaction_name(name) click to toggle source

End common interface

queue_time() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 803
def queue_time
  @apdex_start ? @start_time - @apdex_start : 0
end
record_apdex() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 832
def record_apdex
  return unless state.is_execution_traced?

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

  total_duration = end_time - apdex_start
  apdex_bucket_global = apdex_bucket(total_duration, current_apdex_t)
  apdex_bucket_txn = apdex_bucket(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_exception(exception, options, error_recorded) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 770
def record_exception(exception, options, error_recorded)
  options[:uri] ||= request_path if request_path
  options[:port] = request_port if request_port
  options[:metric] = best_name
  options[:attributes] = @attributes

  span_id = options.delete(:span_id)
  !!agent.error_collector.notice_error(exception, options, span_id) || error_recorded
end
record_exceptions() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 762
def record_exceptions
  error_recorded = false
  @exceptions.each do |exception, options|
    error_recorded = record_exception(exception, options, error_recorded)
  end
  payload&.[]=(:error, error_recorded)
end
record_log_events() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 799
def record_log_events
  agent.log_event_aggregator.record_batch(self, @logs.to_a)
end
record_queue_time() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 807
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) 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 661
def record_summary_metrics(outermost_node_name)
  metrics = summary_metrics
  metrics << @frozen_name unless @frozen_name == outermost_node_name
  @metrics.record_unscoped(metrics, duration, 0)
end
record_transaction_event() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 795
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 901
def recording_web_transaction?
  web_category?(@category)
end
referer() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 313
def referer
  @request_attributes&.referer
end
remove_current_segment_by_thread_id(id) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 284
def remove_current_segment_by_thread_id(id)
  @current_segment_lock.synchronize { current_segment_by_thread.delete(id) }
end
request_path() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 317
def request_path
  @request_attributes&.request_path
end
request_port() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 321
def request_port
  @request_attributes&.port
end
sampled?() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 292
def sampled?
  return false unless Agent.config[:'distributed_tracing.enabled']

  if @sampled.nil?
    @sampled = NewRelic::Agent.instance.adaptive_sampler.sampled?
  end
  @sampled
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 669
def send_transaction_finished_event
  agent.events.notify(:transaction_finished, payload)
end
set_current_segment(new_segment) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 280
def set_current_segment(new_segment)
  @current_segment_lock.synchronize { current_segment_by_thread[current_segment_key] = new_segment }
end
set_default_transaction_name(name, category) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 355
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 364
def set_overriding_transaction_name(name, category)
  return log_frozen_name(name) if name_frozen?

  self.overridden_name = name
  @category = category if category
end
similar_category?(category) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 909
def similar_category?(category)
  web_category?(@category) == web_category?(category)
end
start(options = {}) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 422
def start(options = {})
  return if !state.is_execution_traced?

  sql_sampler.on_start_transaction(state, request_path)
  NewRelic::Agent.instance.events.notify(:start_transaction)
  NewRelic::Agent::TransactionTimeAggregator.transaction_start(start_time)

  ignore! if user_defined_rules_ignore?

  create_initial_segment(options)
  Segment.merge_untrusted_agent_attributes( \
    @filtered_params,
    :'request.parameters',
    AttributeFilter::DST_SPAN_EVENTS
  )
end
state() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 262
def state
  NewRelic::Agent::Tracer.state
end
summary_metrics() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 501
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 703
def synthetics_account_id
  info = synthetics_payload or return nil
  info[1]
end
synthetics_additional_attributes() { |new_key, v| ... } click to toggle source
# File lib/new_relic/agent/transaction.rb, line 637
def synthetics_additional_attributes(&block)
  synthetics_info('attributes')&.each do |k, v|
    new_key = "synthetics_#{NewRelic::LanguageSupport.snakeize(k.to_s)}".to_sym
    yield(new_key, v.to_s)
  end
end
synthetics_info(key) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 723
def synthetics_info(key)
  synthetics_info_payload[key] if synthetics_info_payload
end
synthetics_job_id() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 713
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 718
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 708
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 698
def synthetics_version
  info = synthetics_payload or return nil
  info[0]
end
threshold() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 868
def threshold
  source_class = Agent.config.source(:'transaction_tracer.transaction_threshold').class
  if source_class == Configuration::DefaultSource
    apdex_t * 4
  else
    Agent.config[:'transaction_tracer.transaction_threshold']
  end
end
trace_id() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 301
def trace_id
  @trace_id ||= NewRelic::Agent::GuidGenerator.generate_guid(32)
end
trace_id=(value) click to toggle source
# File lib/new_relic/agent/transaction.rb, line 305
def trace_id=(value)
  @trace_id = value
end
transaction_name()

For common interface with Trace

Alias for: best_name
transaction_specific_apdex_t() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 863
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 548
def user_defined_rules_ignore?
  return false unless request_path
  return false 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 905
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 877
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 982
def agent
  NewRelic::Agent.instance
end
jruby_cpu_time() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 966
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 959
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 990
def sql_sampler
  agent.sql_sampler
end
transaction_sampler() click to toggle source
# File lib/new_relic/agent/transaction.rb, line 986
def transaction_sampler
  agent.transaction_sampler
end