Class: NewRelic::Agent::TransactionSampler

Inherits:
Object
  • Object
show all
Defined in:
lib/new_relic/agent/transaction_sampler.rb

Defined Under Namespace

Modules: Shim

Constant Summary collapse

BUILDER_KEY =
:transaction_sample_builder
MAX_DATA_LENGTH =
16384
MAX_SQL_LENGTH =

some statements (particularly INSERTS with large BLOBS may be very large; we should trim them to a maximum usable length config is the driver configuration for the connection duration is seconds, float value.

16384

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeTransactionSampler

Returns a new instance of TransactionSampler.



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/new_relic/agent/transaction_sampler.rb', line 19

def initialize
  @samples = []
  @harvest_count = 0
  @max_samples = 100
  @random_sample = nil
  config = NewRelic::Control.instance
  sampler_config = config.fetch('transaction_tracer', {})
  @segment_limit = sampler_config.fetch('limit_segments', 4000)
  @stack_trace_threshold = sampler_config.fetch('stack_trace_threshold', 0.500).to_f
  @samples_lock = Mutex.new
end

Instance Attribute Details

#disabledObject (readonly)

Returns the value of attribute disabled.



17
18
19
# File 'lib/new_relic/agent/transaction_sampler.rb', line 17

def disabled
  @disabled
end

#last_sampleObject (readonly)

Returns the value of attribute last_sample.



17
18
19
# File 'lib/new_relic/agent/transaction_sampler.rb', line 17

def last_sample
  @last_sample
end

#random_samplingObject

Returns the value of attribute random_sampling.



16
17
18
# File 'lib/new_relic/agent/transaction_sampler.rb', line 16

def random_sampling
  @random_sampling
end

#samplesObject (readonly)

Returns the value of attribute samples.



17
18
19
# File 'lib/new_relic/agent/transaction_sampler.rb', line 17

def samples
  @samples
end

#sampling_rateObject

Returns the value of attribute sampling_rate.



16
17
18
# File 'lib/new_relic/agent/transaction_sampler.rb', line 16

def sampling_rate
  @sampling_rate
end

#stack_trace_thresholdObject

Returns the value of attribute stack_trace_threshold.



16
17
18
# File 'lib/new_relic/agent/transaction_sampler.rb', line 16

def stack_trace_threshold
  @stack_trace_threshold
end

Instance Method Details

#current_sample_idObject



31
32
33
34
# File 'lib/new_relic/agent/transaction_sampler.rb', line 31

def current_sample_id
  b=builder
  b and b.sample_id
end

#disableObject



41
42
43
44
# File 'lib/new_relic/agent/transaction_sampler.rb', line 41

def disable
  @disabled = true
  NewRelic::Agent.instance.stats_engine.remove_transaction_sampler self
end

#enableObject



36
37
38
39
# File 'lib/new_relic/agent/transaction_sampler.rb', line 36

def enable
  @disabled = false
  NewRelic::Agent.instance.stats_engine.transaction_sampler = self
end

#harvest(previous = nil, slow_threshold = 2.0) ⇒ Object

get the set of collected samples, merging into previous samples, and clear the collected sample list.



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/new_relic/agent/transaction_sampler.rb', line 171

def harvest(previous = nil, slow_threshold = 2.0)
  return [] if disabled
  result = []
  previous ||= []

  previous = [previous] unless previous.is_a?(Array)

  previous_slowest = previous.inject(nil) {|a,ts| (a) ? ((a.duration > ts.duration) ? a : ts) : ts}

  @samples_lock.synchronize do

    if @random_sampling
      @harvest_count += 1

      if (@harvest_count % @sampling_rate) == 0
        result << @random_sample if @random_sample
      else
        @random_sample = nil   # if we don't nil this out, then we won't send the slowest if slowest == @random_sample
      end
    end

    slowest = @slowest_sample
    @slowest_sample = nil

    if slowest && slowest != @random_sample && slowest.duration >= slow_threshold
      if previous_slowest.nil? || previous_slowest.duration < slowest.duration
        result << slowest
      else
        result << previous_slowest
      end
    end

    @random_sample = nil
    @last_sample = nil
  end
  # Truncate the samples at 2100 segments. The UI will clamp them at 2000 segments anyway.
  # This will save us memory and bandwidth.
  result.each { |sample| sample.truncate(@segment_limit) }
  result
end

#ignore_transactionObject



121
122
123
# File 'lib/new_relic/agent/transaction_sampler.rb', line 121

def ignore_transaction
  builder.ignore_transaction if builder
end

#notice_first_scope_push(time) ⇒ Object



51
52
53
# File 'lib/new_relic/agent/transaction_sampler.rb', line 51

def notice_first_scope_push(time)
  start_builder(time.to_f) unless disabled
end

#notice_nosql(key, duration) ⇒ Object

duration is seconds, float value.



164
165
166
# File 'lib/new_relic/agent/transaction_sampler.rb', line 164

def notice_nosql(key, duration)
  notice_extra_data(key, duration, :key)
end

#notice_pop_scope(scope, time = Time.now) ⇒ Object



85
86
87
88
89
# File 'lib/new_relic/agent/transaction_sampler.rb', line 85

def notice_pop_scope(scope, time = Time.now)
  return unless builder
  raise "frozen already???" if builder.sample.frozen?
  builder.trace_exit(scope, time.to_f)
end

#notice_profile(profile) ⇒ Object



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

def notice_profile(profile)
  builder.set_profile(profile) if builder
end

#notice_push_scope(scope, time = Time.now) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/new_relic/agent/transaction_sampler.rb', line 55

def notice_push_scope(scope, time=Time.now)

  return unless builder

  builder.trace_entry(scope, time.to_f)

  # in developer mode, capture the stack trace with the segment.
  # this is cpu and memory expensive and therefore should not be
  # turned on in production mode
  if NewRelic::Control.instance.developer_mode?
    segment = builder.current_segment
    if segment
      # Strip stack frames off the top that match /new_relic/agent/
      trace = caller
      while trace.first =~/\/lib\/new_relic\/agent\//
        trace.shift
      end

      trace = trace[0..39] if trace.length > 40
      segment[:backtrace] = trace
    end
  end
end

#notice_scope_empty(time = Time.now) ⇒ Object

This is called when we are done with the transaction. We’ve unwound the stack to the top level.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/new_relic/agent/transaction_sampler.rb', line 93

def notice_scope_empty(time=Time.now)

  last_builder = builder
  return unless last_builder

  last_builder.finish_trace(time.to_f)
  clear_builder
  return if last_builder.ignored?

  @samples_lock.synchronize do
    @last_sample = last_builder.sample

    @random_sample = @last_sample if @random_sampling

    # ensure we don't collect more than a specified number of samples in memory
    @samples << @last_sample if NewRelic::Control.instance.developer_mode?
    @samples.shift while @samples.length > @max_samples

    if @slowest_sample.nil? || @slowest_sample.duration < @last_sample.duration
      @slowest_sample = @last_sample
    end
  end
end

#notice_sql(sql, config, duration) ⇒ Object



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

def notice_sql(sql, config, duration)
  if Thread::current[:record_sql] != false
    notice_extra_data(sql, duration, :sql, config, :connection_config)
  end
end

#notice_transaction(path, uri = nil, params = {}) ⇒ Object



117
118
119
# File 'lib/new_relic/agent/transaction_sampler.rb', line 117

def notice_transaction(path, uri=nil, params={})
  builder.set_transaction_info(path, uri, params) if !disabled && builder
end

#notice_transaction_cpu_time(cpu_time) ⇒ Object



128
129
130
# File 'lib/new_relic/agent/transaction_sampler.rb', line 128

def notice_transaction_cpu_time(cpu_time)
  builder.set_transaction_cpu_time(cpu_time) if builder
end

#reset!Object

reset samples without rebooting the web server



213
214
215
216
# File 'lib/new_relic/agent/transaction_sampler.rb', line 213

def reset!
  @samples = []
  @last_sample = nil
end

#scope_depthObject



79
80
81
82
83
# File 'lib/new_relic/agent/transaction_sampler.rb', line 79

def scope_depth
  return 0 unless builder

  builder.scope_depth
end