module NewRelic::Agent::TransactionTimeAggregator

Constants

INSTANCE_BUSY_METRIC
TransactionStats

Public Class Methods

harvest!(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME)) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 44
def harvest!(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME))
  active_threads = 0
  result = @lock.synchronize do
    # Sum up the transaction times spent in each thread
    elapsed_transaction_time = @stats.inject(0.0) do |total, (thread_id, entry)|
      total + transaction_time_in_thread(timestamp, thread_id, entry)
    end

    active_threads = @stats.size
    elapsed_harvest_time = (timestamp - @harvest_cycle_started_at) * active_threads
    @harvest_cycle_started_at = timestamp

    # Clear out the stats for all threads, _except_ the live ones
    # that have transactions still open (we'll count the rest of
    # those in a future harvest)
    @stats.keep_if do |thread_id, _|
      in_transaction?(thread_id) && thread_is_alive?(thread_id)
    end

    if elapsed_harvest_time > 0.0
      elapsed_transaction_time / elapsed_harvest_time
    else
      0.0
    end
  end

  if Agent.config[:report_instance_busy]
    NewRelic::Agent.record_metric(INSTANCE_BUSY_METRIC, result)
  end

  result
end
reset!(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME)) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 24
def reset!(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME))
  @harvest_cycle_started_at = timestamp
  @stats.clear
end
transaction_start(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME)) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 29
def transaction_start(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME))
  @lock.synchronize do
    set_transaction_start_time(timestamp)
  end
end
transaction_stop(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME), starting_thread_id = current_thread) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 35
def transaction_stop(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME), starting_thread_id = current_thread)
  @lock.synchronize do
    record_elapsed_transaction_time_until(timestamp, starting_thread_id)
    set_transaction_start_time(nil, starting_thread_id)
  end
end

Private Class Methods

current_thread() click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 98
def current_thread
  Thread.current.object_id
end
in_transaction?(thread_id = current_thread) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 94
def in_transaction?(thread_id = current_thread)
  !!@stats[thread_id].transaction_started_at
end
log_missing_elapsed_transaction_time() click to toggle source

this method has no test coverage

# File lib/new_relic/agent/transaction_time_aggregator.rb, line 149
def log_missing_elapsed_transaction_time
  # rubocop:disable Style/SafeNavigation
  transaction_name = transaction_name = Tracer.current_transaction &&
    Tracer.current_transaction.best_name ||
    'unknown'
  # rubocop:enable Style/SafeNavigation
  NewRelic::Agent.logger.warn("Unable to calculate elapsed transaction time for #{transaction_name}")
end
record_elapsed_transaction_time_until(timestamp, thread_id = current_thread) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 85
def record_elapsed_transaction_time_until(timestamp, thread_id = current_thread)
  if @stats[thread_id].transaction_started_at
    @stats[thread_id].elapsed_transaction_time +=
      (timestamp - (@stats[thread_id].transaction_started_at || 0.0))
  else
    log_missing_elapsed_transaction_time
  end
end
set_transaction_start_time(timestamp, thread_id = current_thread) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 125
def set_transaction_start_time(timestamp, thread_id = current_thread)
  @stats[thread_id].transaction_started_at = timestamp
end
split_transaction_at_harvest(timestamp, thread_id = nil) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 129
def split_transaction_at_harvest(timestamp, thread_id = nil)
  raise ArgumentError, 'thread_id required' unless thread_id

  @stats[thread_id].transaction_started_at = timestamp
  @stats[thread_id].elapsed_transaction_time = 0.0
end
thread_by_id(thread_id) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 114
def thread_by_id(thread_id)
  Thread.list.detect { |t| t.object_id == thread_id }
end
thread_is_alive?(thread_id) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 102
def thread_is_alive?(thread_id)
  thread = thread_by_id(thread_id)
  # needs else branch coverage
  thread && thread.alive? # rubocop:disable Style/SafeNavigation
rescue StandardError
  false
end
transaction_time_in_thread(timestamp, thread_id, entry) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 136
def transaction_time_in_thread(timestamp, thread_id, entry)
  return entry.elapsed_transaction_time unless in_transaction?(thread_id)

  # Count the portion of the transaction that's elapsed so far,...
  elapsed = record_elapsed_transaction_time_until(timestamp, thread_id)

  # ...then readjust the transaction start time to the next harvest
  split_transaction_at_harvest(timestamp, thread_id)

  elapsed
end

Private Instance Methods

harvest!(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME)) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 44
def harvest!(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME))
  active_threads = 0
  result = @lock.synchronize do
    # Sum up the transaction times spent in each thread
    elapsed_transaction_time = @stats.inject(0.0) do |total, (thread_id, entry)|
      total + transaction_time_in_thread(timestamp, thread_id, entry)
    end

    active_threads = @stats.size
    elapsed_harvest_time = (timestamp - @harvest_cycle_started_at) * active_threads
    @harvest_cycle_started_at = timestamp

    # Clear out the stats for all threads, _except_ the live ones
    # that have transactions still open (we'll count the rest of
    # those in a future harvest)
    @stats.keep_if do |thread_id, _|
      in_transaction?(thread_id) && thread_is_alive?(thread_id)
    end

    if elapsed_harvest_time > 0.0
      elapsed_transaction_time / elapsed_harvest_time
    else
      0.0
    end
  end

  if Agent.config[:report_instance_busy]
    NewRelic::Agent.record_metric(INSTANCE_BUSY_METRIC, result)
  end

  result
end
reset!(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME)) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 24
def reset!(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME))
  @harvest_cycle_started_at = timestamp
  @stats.clear
end
transaction_start(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME)) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 29
def transaction_start(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME))
  @lock.synchronize do
    set_transaction_start_time(timestamp)
  end
end
transaction_stop(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME), starting_thread_id = current_thread) click to toggle source
# File lib/new_relic/agent/transaction_time_aggregator.rb, line 35
def transaction_stop(timestamp = Process.clock_gettime(Process::CLOCK_REALTIME), starting_thread_id = current_thread)
  @lock.synchronize do
    record_elapsed_transaction_time_until(timestamp, starting_thread_id)
    set_transaction_start_time(nil, starting_thread_id)
  end
end