Class: NewRelic::TransactionSample

Inherits:
Object
  • Object
show all
Includes:
TransactionAnalysis
Defined in:
lib/new_relic/transaction_sample.rb

Defined Under Namespace

Classes: CompositeSegment, FakeSegment, Segment, SummarySegment

Constant Summary collapse

EMPTY_ARRAY =
[].freeze
@@start_time =
Time.now

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from TransactionAnalysis

#breakdown_data, #database_time, #render_time, #sql_segments

Constructor Details

#initialize(time = Time.now.to_f, sample_id = nil) ⇒ TransactionSample

Returns a new instance of TransactionSample.



334
335
336
337
338
339
340
# File 'lib/new_relic/transaction_sample.rb', line 334

def initialize(time = Time.now.to_f, sample_id = nil)
  @sample_id = sample_id || object_id
  @start_time = time
  @root_segment = create_segment 0.0, "ROOT"
  @params = {}
  @params[:request_params] = {}
end

Instance Attribute Details

#paramsObject

Returns the value of attribute params.



20
21
22
# File 'lib/new_relic/transaction_sample.rb', line 20

def params
  @params
end

#profileObject

Returns the value of attribute profile.



329
330
331
# File 'lib/new_relic/transaction_sample.rb', line 329

def profile
  @profile
end

#root_segmentObject

Returns the value of attribute root_segment.



20
21
22
# File 'lib/new_relic/transaction_sample.rb', line 20

def root_segment
  @root_segment
end

#sample_idObject (readonly)

Returns the value of attribute sample_id.



332
333
334
# File 'lib/new_relic/transaction_sample.rb', line 332

def sample_id
  @sample_id
end

Class Method Details

.close_connectionsObject



315
316
317
318
319
320
321
322
323
324
325
# File 'lib/new_relic/transaction_sample.rb', line 315

def close_connections
  @@connections ||= {}
  @@connections.values.each do |connection|
    begin
      connection.disconnect!
    rescue
    end
  end

  @@connections = {}
end

.get_connection(config) ⇒ Object



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/new_relic/transaction_sample.rb', line 298

def get_connection(config)
  @@connections ||= {}

  connection = @@connections[config]

  return connection if connection

  begin
    connection = ActiveRecord::Base.send("#{config[:adapter]}_connection", config)
    @@connections[config] = connection
  rescue => e
    NewRelic::Agent.agent.log.error("Caught exception #{e} trying to get connection to DB for explain. Control: #{config}")
    NewRelic::Agent.agent.log.error(e.backtrace.join("\n"))
    nil
  end
end

.obfuscate_sql(sql) ⇒ Object



294
295
296
# File 'lib/new_relic/transaction_sample.rb', line 294

def obfuscate_sql(sql)
  NewRelic::Agent.instance.obfuscator.call(sql)
end

Instance Method Details

#analyzeObject



466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'lib/new_relic/transaction_sample.rb', line 466

def analyze
  sample = self
  original_path_string = nil
  loop do
    original_path_string = sample.path_string.to_s
    new_sample = sample.dup
    new_sample.root_segment = sample.root_segment.dup
    new_sample.root_segment.called_segments = analyze_called_segments(root_segment.called_segments)
    sample = new_sample
    return sample if sample.path_string.to_s == original_path_string
  end

end

#count_segmentsObject



342
343
344
# File 'lib/new_relic/transaction_sample.rb', line 342

def count_segments
  @root_segment.count_segments - 1    # don't count the root segment
end

#create_segment(relative_timestamp, metric_name, segment_id = nil) ⇒ Object

Raises:

  • (TypeError)


384
385
386
387
# File 'lib/new_relic/transaction_sample.rb', line 384

def create_segment(relative_timestamp, metric_name, segment_id = nil)
  raise TypeError.new("Frozen Transaction Sample") if frozen?
  NewRelic::TransactionSample::Segment.new(relative_timestamp, metric_name, segment_id)
end

#durationObject



389
390
391
# File 'lib/new_relic/transaction_sample.rb', line 389

def duration
  root_segment.duration
end

#each_segment(&block) ⇒ Object



393
394
395
# File 'lib/new_relic/transaction_sample.rb', line 393

def each_segment(&block)
  @root_segment.each_segment(&block)
end

#find_segment(id) ⇒ Object



401
402
403
# File 'lib/new_relic/transaction_sample.rb', line 401

def find_segment(id)
  @root_segment.find_segment(id)
end

#omit_segments_with(regex) ⇒ Object

return a new transaction sample that treats segments with the given regular expression in their name as if they were never called at all. This allows us to strip out segments from traces captured in development environment that would not normally show up in production (like Rails/Application Code Loading)



431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/new_relic/transaction_sample.rb', line 431

def omit_segments_with(regex)
  regex = Regexp.new(regex)

  sample = TransactionSample.new(@start_time, sample_id)

  params.each {|k,v| sample.params[k] = v}

  delta = build_segment_with_omissions(sample, 0.0, @root_segment, sample.root_segment, regex)
  sample.root_segment.end_trace(@root_segment.exit_timestamp - delta)
  sample.profile = self.profile
  sample
end

#path_stringObject



380
381
382
# File 'lib/new_relic/transaction_sample.rb', line 380

def path_string
  @root_segment.path_string
end

#prepare_to_send(options = {}) ⇒ Object

return a new transaction sample that can be sent to the RPM service. this involves potentially one or more of the following options

:explain_sql : run EXPLAIN on all queries whose response times equal the value for this key
    (for example :explain_sql => 2.0 would explain everything over 2 seconds.  0.0 would explain everything.)
:keep_backtraces : keep backtraces, significantly increasing size of trace (off by default)
:record_sql => [ :raw | :obfuscated] : copy over the sql, obfuscating if necessary


451
452
453
454
455
456
457
458
459
460
461
462
463
464
# File 'lib/new_relic/transaction_sample.rb', line 451

def prepare_to_send(options={})
  sample = TransactionSample.new(@start_time, sample_id)

  sample.params.merge! self.params

  begin
    build_segment_for_transfer(sample, @root_segment, sample.root_segment, options)
  ensure
    self.class.close_connections
  end

  sample.root_segment.end_trace(@root_segment.exit_timestamp)
  sample
end

#start_timeObject



376
377
378
# File 'lib/new_relic/transaction_sample.rb', line 376

def start_time
  Time.at(@start_time)
end

#timestampObject

offset from start of app



359
360
361
# File 'lib/new_relic/transaction_sample.rb', line 359

def timestamp
  @start_time - @@start_time.to_f
end

#to_json(options = {}) ⇒ Object

Used in the server only



364
365
366
367
368
369
370
371
372
# File 'lib/new_relic/transaction_sample.rb', line 364

def to_json(options = {}) #:nodoc:
  map = {:sample_id => @sample_id,
    :start_time => @start_time,
    :root_segment => @root_segment}
  if @params && !@params.empty?
    map[:params] = @params
  end
  map.to_json
end

#to_sObject



405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/new_relic/transaction_sample.rb', line 405

def to_s
  s = "Transaction Sample collected at #{start_time}\n"
  s << "  {\n"
  s << "  Path: #{params[:path]} \n"

  params.each do |k,v|
    next if k == :path
    s << "  #{k}: " <<
    case v
      when Enumerable then v.map(&:to_s).sort.join("; ")
      when String then v
      when Float then '%6.3s' % v
      when nil then ''
    else
      raise "unexpected value type for #{k}: '#{v}' (#{v.class})"
    end << "\n"
  end
  s << "  }\n\n"
  s <<  @root_segment.to_debug_str(0)
end

#to_s_compactObject



397
398
399
# File 'lib/new_relic/transaction_sample.rb', line 397

def to_s_compact
  @root_segment.to_s_compact
end

#truncate(max) ⇒ Object



346
347
348
349
350
351
352
353
354
355
356
# File 'lib/new_relic/transaction_sample.rb', line 346

def truncate(max)
  original_count = count_segments

  return if original_count <= max

  @root_segment.truncate(max-1)

  if params[:segment_count].nil?
    params[:segment_count] = original_count
  end
end