Class: NewRelic::Agent::TransactionSampler
- Inherits:
-
Object
- Object
- NewRelic::Agent::TransactionSampler
- Defined in:
- lib/new_relic/agent/transaction_sampler.rb
Overview
This class contains the logic of sampling a transaction - creation and modification of transaction samples
Defined Under Namespace
Modules: Shim
Constant Summary collapse
- MAX_DATA_LENGTH =
16384
Instance Attribute Summary collapse
-
#dev_mode_sample_buffer ⇒ Object
readonly
Returns the value of attribute dev_mode_sample_buffer.
-
#last_sample ⇒ Object
readonly
Returns the value of attribute last_sample.
-
#xray_sample_buffer ⇒ Object
readonly
Returns the value of attribute xray_sample_buffer.
Class Method Summary collapse
-
.truncate_message(message) ⇒ Object
Truncates the message to ‘MAX_DATA_LENGTH` if needed, and appends an ellipsis because it makes the trucation clearer in the UI.
Instance Method Summary collapse
-
#add_segment_parameters(params) ⇒ Object
Set parameters on the current segment.
-
#append_backtrace(segment, duration) ⇒ Object
Appends a backtrace to a segment if that segment took longer than the specified duration.
-
#append_new_message(old_message, message) ⇒ Object
Allows the addition of multiple pieces of metadata to one segment - i.e.
-
#append_previous_samples_to_buffers(previous_samples) ⇒ Object
Previous samples are added to buffers to enforce limiting rules.
- #build_database_statement(sql, config, explainer) ⇒ Object
-
#builder ⇒ Object
The current thread-local transaction sample builder.
-
#choose_samples(previous_samples) ⇒ Object
Runs previously untransmitted samples into buffers, then chooses what to send based on each buffer’s internal logic.
-
#clear_builder ⇒ Object
Sets the thread local variable storing the transaction sample builder to nil to clear it.
- #enabled? ⇒ Boolean
-
#harvest(previous = []) ⇒ Object
Gather transaction traces that we’d like to transmit to the server.
- #harvest_from_sample_buffers ⇒ Object
-
#ignore_transaction ⇒ Object
Tells the builder to ignore a transaction, if we are currently creating one.
-
#initialize ⇒ TransactionSampler
constructor
A new instance of TransactionSampler.
-
#notice_first_scope_push(time) ⇒ Object
Creates a new transaction sample builder, unless the transaction sampler is disabled.
-
#notice_nosql(key, duration) ⇒ Object
Adds non-sql metadata to a segment - generally the memcached key.
-
#notice_pop_scope(scope, time = Time.now) ⇒ Object
Informs the transaction sample builder about the end of a traced scope.
-
#notice_profile(profile) ⇒ Object
For developer mode profiling support - delegates to the builder.
-
#notice_push_scope(time = Time.now) ⇒ Object
This delegates to the builder to create a new open transaction segment for the specified scope, beginning at the optionally specified time.
-
#notice_scope_empty(txn, time = Time.now, gc_time = nil) ⇒ Object
This is called when we are done with the transaction.
-
#notice_sql(sql, config, duration, &explainer) ⇒ Object
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..
-
#notice_transaction(uri = nil, params = {}) ⇒ Object
Delegates to the builder to store the uri, and parameters if the sampler is active.
-
#notice_transaction_cpu_time(cpu_time) ⇒ Object
Sets the CPU time used by a transaction, delegates to the builder.
-
#reset! ⇒ Object
reset samples without rebooting the web server (used by dev mode).
-
#start_builder(time = nil) ⇒ Object
Checks to see if the transaction sampler is disabled, if transaction trace recording is disabled by a thread local, or if execution is untraced - if so it clears the transaction sample builder from the thread local, otherwise it generates a new transaction sample builder with the stated time as a starting point and saves it in the thread local variable.
- #store_sample(sample) ⇒ Object
Constructor Details
#initialize ⇒ TransactionSampler
Returns a new instance of TransactionSampler.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 31 def initialize @dev_mode_sample_buffer = NewRelic::Agent::Transaction::DeveloperModeSampleBuffer.new @xray_sample_buffer = NewRelic::Agent::Transaction::XraySampleBuffer.new @sample_buffers = [] @sample_buffers << @dev_mode_sample_buffer @sample_buffers << @xray_sample_buffer @sample_buffers << NewRelic::Agent::Transaction::SlowestSampleBuffer.new @sample_buffers << NewRelic::Agent::Transaction::ForcePersistSampleBuffer.new # This lock is used to synchronize access to the @last_sample # and related variables. It can become necessary on JRuby or # any 'honest-to-god'-multithreaded system @samples_lock = Mutex.new Agent.config.register_callback(:'transaction_tracer.enabled') do |enabled| if enabled threshold = Agent.config[:'transaction_tracer.transaction_threshold'] ::NewRelic::Agent.logger.debug "Transaction tracing threshold is #{threshold} seconds." else ::NewRelic::Agent.logger.debug "Transaction traces will not be sent to the New Relic service." end end Agent.config.register_callback(:'transaction_tracer.record_sql') do |config| if config == 'raw' ::NewRelic::Agent.logger.warn("Agent is configured to send raw SQL to the service") end end end |
Instance Attribute Details
#dev_mode_sample_buffer ⇒ Object (readonly)
Returns the value of attribute dev_mode_sample_buffer.
29 30 31 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 29 def dev_mode_sample_buffer @dev_mode_sample_buffer end |
#last_sample ⇒ Object (readonly)
Returns the value of attribute last_sample.
29 30 31 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 29 def last_sample @last_sample end |
#xray_sample_buffer ⇒ Object (readonly)
Returns the value of attribute xray_sample_buffer.
29 30 31 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 29 def xray_sample_buffer @xray_sample_buffer end |
Class Method Details
.truncate_message(message) ⇒ Object
Truncates the message to ‘MAX_DATA_LENGTH` if needed, and appends an ellipsis because it makes the trucation clearer in the UI
173 174 175 176 177 178 179 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 173 def self.() if .length > (MAX_DATA_LENGTH - 4) [0..MAX_DATA_LENGTH - 4] + '...' else end end |
Instance Method Details
#add_segment_parameters(params) ⇒ Object
Set parameters on the current segment.
232 233 234 235 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 232 def add_segment_parameters( params ) return unless builder params.each { |k,v| builder.current_segment[k] = v } end |
#append_backtrace(segment, duration) ⇒ Object
Appends a backtrace to a segment if that segment took longer than the specified duration
193 194 195 196 197 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 193 def append_backtrace(segment, duration) if duration >= Agent.config[:'transaction_tracer.stack_trace_threshold'] segment[:backtrace] = caller.join("\n") end end |
#append_new_message(old_message, message) ⇒ Object
Allows the addition of multiple pieces of metadata to one segment - i.e. traced method calls multiple sql queries
183 184 185 186 187 188 189 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 183 def (, ) if + ";\n" + else end end |
#append_previous_samples_to_buffers(previous_samples) ⇒ Object
Previous samples are added to buffers to enforce limiting rules
260 261 262 263 264 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 260 def append_previous_samples_to_buffers(previous_samples) @sample_buffers.each do |buffer| buffer.store_previous(previous_samples) end end |
#build_database_statement(sql, config, explainer) ⇒ Object
210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 210 def build_database_statement(sql, config, explainer) statement = Database::Statement.new(self.class.(sql)) if config statement.adapter = config[:adapter] statement.config = config end if Agent.config[:override_sql_obfuscation_adapter] statement.adapter = Agent.config[:override_sql_obfuscation_adapter] end statement.explainer = explainer statement end |
#builder ⇒ Object
The current thread-local transaction sample builder
298 299 300 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 298 def builder TransactionState.get.transaction_sample_builder end |
#choose_samples(previous_samples) ⇒ Object
Runs previously untransmitted samples into buffers, then chooses what to send based on each buffer’s internal logic
254 255 256 257 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 254 def choose_samples(previous_samples) append_previous_samples_to_buffers(previous_samples) harvest_from_sample_buffers end |
#clear_builder ⇒ Object
Sets the thread local variable storing the transaction sample builder to nil to clear it
304 305 306 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 304 def clear_builder TransactionState.get.transaction_sample_builder = nil end |
#enabled? ⇒ Boolean
62 63 64 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 62 def enabled? Agent.config[:'transaction_tracer.enabled'] || Agent.config[:developer_mode] end |
#harvest(previous = []) ⇒ Object
Gather transaction traces that we’d like to transmit to the server. choose_samples is responsible for determining the contents of that transmission, along with limits and ordering.
240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 240 def harvest(previous=[]) return [] if !enabled? # If no unsent transactions from last time, we explicitly pass nil! previous ||= [] @samples_lock.synchronize do @last_sample = nil choose_samples(previous) end end |
#harvest_from_sample_buffers ⇒ Object
266 267 268 269 270 271 272 273 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 266 def harvest_from_sample_buffers # map + flatten hit mocking issues calling to_ary on 1.9.2. We only # want a single level flatten anyway, but, as you probably already # know, Ruby 1.8.6 :/ result = [] @sample_buffers.each {|buffer| result.concat(buffer.harvest_samples)} result.uniq end |
#ignore_transaction ⇒ Object
Tells the builder to ignore a transaction, if we are currently creating one. Only causes the sample to be ignored upon end of the transaction, and does not change the metrics gathered outside of the sampler
135 136 137 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 135 def ignore_transaction builder.ignore_transaction if builder end |
#notice_first_scope_push(time) ⇒ Object
Creates a new transaction sample builder, unless the transaction sampler is disabled. Takes a time parameter for the start of the transaction sample
69 70 71 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 69 def notice_first_scope_push(time) start_builder(time.to_f) if enabled? end |
#notice_nosql(key, duration) ⇒ Object
Adds non-sql metadata to a segment - generally the memcached key
duration is seconds, float value.
227 228 229 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 227 def notice_nosql(key, duration) notice_extra_data(key, duration, :key) end |
#notice_pop_scope(scope, time = Time.now) ⇒ Object
Informs the transaction sample builder about the end of a traced scope
89 90 91 92 93 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 89 def notice_pop_scope(scope, time = Time.now) return unless builder raise "finished already???" if builder.sample.finished builder.trace_exit(scope, time.to_f) end |
#notice_profile(profile) ⇒ Object
For developer mode profiling support - delegates to the builder
140 141 142 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 140 def notice_profile(profile) builder.set_profile(profile) if builder end |
#notice_push_scope(time = Time.now) ⇒ Object
This delegates to the builder to create a new open transaction segment for the specified scope, beginning at the optionally specified time.
Note that in developer mode, this captures a stacktrace for the beginning of each segment, which can be fairly slow
79 80 81 82 83 84 85 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 79 def notice_push_scope(time=Time.now) return unless builder segment = builder.trace_entry(time.to_f) @sample_buffers.each { |sample_buffer| sample_buffer.visit_segment(segment) } return segment end |
#notice_scope_empty(txn, time = Time.now, gc_time = nil) ⇒ Object
This is called when we are done with the transaction. We’ve unwound the stack to the top level. It also clears the transaction sample builder so that it won’t continue to have scopes appended to it.
It sets various instance variables to the finished sample, depending on which settings are active. See ‘store_sample`
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 102 def notice_scope_empty(txn, time=Time.now, gc_time=nil) last_builder = builder last_builder.set_transaction_name(txn.name) if enabled? && last_builder return unless last_builder last_builder.finish_trace(time.to_f, txn.custom_parameters) clear_builder return if last_builder.ignored? @samples_lock.synchronize do @last_sample = last_builder.sample @last_sample.set_custom_param(:gc_time, gc_time) if gc_time store_sample(@last_sample) end end |
#notice_sql(sql, config, duration, &explainer) ⇒ Object
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.
203 204 205 206 207 208 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 203 def notice_sql(sql, config, duration, &explainer) if NewRelic::Agent.is_sql_recorded? statement = build_database_statement(sql, config, explainer) notice_extra_data(statement, duration, :sql) end end |
#notice_transaction(uri = nil, params = {}) ⇒ Object
Delegates to the builder to store the uri, and parameters if the sampler is active
127 128 129 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 127 def notice_transaction(uri=nil, params={}) builder.set_transaction_info(uri, params) if enabled? && builder end |
#notice_transaction_cpu_time(cpu_time) ⇒ Object
Sets the CPU time used by a transaction, delegates to the builder
145 146 147 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 145 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 (used by dev mode)
276 277 278 279 280 281 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 276 def reset! @samples_lock.synchronize do @last_sample = nil @sample_buffers.each { |sample_buffer| sample_buffer.reset! } end end |
#start_builder(time = nil) ⇒ Object
Checks to see if the transaction sampler is disabled, if transaction trace recording is disabled by a thread local, or if execution is untraced - if so it clears the transaction sample builder from the thread local, otherwise it generates a new transaction sample builder with the stated time as a starting point and saves it in the thread local variable
289 290 291 292 293 294 295 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 289 def start_builder(time=nil) if !enabled? || !NewRelic::Agent.is_transaction_traced? || !NewRelic::Agent.is_execution_traced? clear_builder else TransactionState.get.transaction_sample_builder ||= TransactionSampleBuilder.new(time) end end |
#store_sample(sample) ⇒ Object
119 120 121 122 123 |
# File 'lib/new_relic/agent/transaction_sampler.rb', line 119 def store_sample(sample) @sample_buffers.each do |sample_buffer| sample_buffer.store(sample) end end |