Module: NewRelic::Agent::StatsEngine::Transactions

Included in:
NewRelic::Agent::StatsEngine
Defined in:
lib/new_relic/agent/stats_engine/transactions.rb

Overview

Handles pushing and popping elements onto an internal stack that tracks where time should be allocated in Transaction Traces

Defined Under Namespace

Modules: Shim

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#transaction_samplerObject

Returns the value of attribute transaction_sampler.



33
34
35
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 33

def transaction_sampler
  @transaction_sampler
end

Instance Method Details

#end_transactionObject

Try to clean up gracefully, otherwise we leave things hanging around on thread locals. If it looks like a transaction is still in progress, then maybe this is an inner transaction and is ignored.



119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 119

def end_transaction
  elapsed = GCProfiler.capture
  if @transaction_sampler && @transaction_sampler.last_sample
    @transaction_sampler.last_sample.params[:custom_params] ||= {}
    @transaction_sampler.last_sample.params[:custom_params][:gc_time] = elapsed
  end
  stack = scope_stack

  if stack && stack.empty?
    Thread::current[:newrelic_scope_stack] = nil
    Thread::current[:newrelic_scope_name] = nil
  end
end

#peek_scopeObject

Returns the latest ScopeStackElement



86
87
88
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 86

def peek_scope
  scope_stack.last
end

#pop_scope(expected_scope, duration, time = Time.now.to_f) ⇒ Object

Pops a scope off the transaction stack - this updates the transaction sampler that we’ve finished execution of a traced method



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 59

def pop_scope(expected_scope, duration, time=Time.now.to_f)
  stack = scope_stack
  scope = stack.pop
  fail "unbalanced pop from blame stack, got #{scope ? scope.name : 'nil'}, expected #{expected_scope ? expected_scope.name : 'nil'}" if scope != expected_scope

  if !stack.empty?
    if scope.deduct_call_time_from_parent
      stack.last.children_time += duration
    else
      stack.last.children_time += scope.children_time
    end
  end
  @transaction_sampler.notice_pop_scope(scope.name, time) if sampler_enabled?
  scope
end

#push_scope(metric, time = Time.now.to_f, deduct_call_time_from_parent = true) ⇒ Object

Pushes a scope onto the transaction stack - this generates a TransactionSample::Segment at the end of transaction execution



49
50
51
52
53
54
55
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 49

def push_scope(metric, time = Time.now.to_f, deduct_call_time_from_parent = true)
  stack = scope_stack
  @transaction_sampler.notice_push_scope metric, time if sampler_enabled?
  scope = ScopeStackElement.new(metric, deduct_call_time_from_parent)
  stack.push scope
  scope
end

#remove_transaction_sampler(l) ⇒ Object

removes a transaction sampler



43
44
45
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 43

def remove_transaction_sampler(l)
  @transaction_sampler = nil
end

#rename_scope_segment(new_name) ⇒ Object

Rename the segment associated with the last pushed scope to new_name.



80
81
82
83
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 80

def rename_scope_segment( new_name )
  self.peek_scope.name = new_name
  @transaction_sampler.rename_scope_segment( new_name )
end

#sampler_enabled?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 75

def sampler_enabled?
  @transaction_sampler && Agent.config[:'transaction_tracer.enabled']
end

#scope_nameObject

Returns the current scope name from the thread local



103
104
105
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 103

def scope_name
  Thread::current[:newrelic_scope_name]
end

#scope_name=(transaction) ⇒ Object

set the name of the transaction for the current thread, which will be used to define the scope of all traced methods called on this thread until the scope stack is empty.

currently the transaction name is the name of the controller action that is invoked via the dispatcher, but conceivably we could use other transaction names in the future if the traced application does more than service http request via controller actions



98
99
100
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 98

def scope_name=(transaction)
  Thread::current[:newrelic_scope_name] = transaction
end

#start_transaction(name = nil) ⇒ Object

Start a new transaction, unless one is already in progress



108
109
110
111
112
113
# File 'lib/new_relic/agent/stats_engine/transactions.rb', line 108

def start_transaction(name = nil)
  Thread::current[:newrelic_scope_stack] ||= []
  self.scope_name = name if name
  NewRelic::Agent.instance.events.notify(:start_transaction, name)
  GCProfiler.init
end