newrelic_rpm 2.13.0.beta5 → 2.13.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of newrelic_rpm might be problematic. Click here for more details.

Files changed (86) hide show
  1. data/CHANGELOG +4 -0
  2. data/lib/new_relic/agent.rb +50 -50
  3. data/lib/new_relic/agent/agent.rb +24 -19
  4. data/lib/new_relic/agent/busy_calculator.rb +22 -22
  5. data/lib/new_relic/agent/chained_call.rb +3 -3
  6. data/lib/new_relic/agent/error_collector.rb +19 -19
  7. data/lib/new_relic/agent/instrumentation/active_record_instrumentation.rb +11 -11
  8. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +2 -2
  9. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +43 -43
  10. data/lib/new_relic/agent/instrumentation/data_mapper.rb +6 -6
  11. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +2 -2
  12. data/lib/new_relic/agent/instrumentation/memcache.rb +8 -8
  13. data/lib/new_relic/agent/instrumentation/merb/controller.rb +4 -4
  14. data/lib/new_relic/agent/instrumentation/metric_frame.rb +307 -303
  15. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +8 -8
  16. data/lib/new_relic/agent/instrumentation/rack.rb +2 -2
  17. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +10 -10
  18. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +3 -3
  19. data/lib/new_relic/agent/instrumentation/rails/errors.rb +5 -5
  20. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +5 -5
  21. data/lib/new_relic/agent/instrumentation/sinatra.rb +5 -5
  22. data/lib/new_relic/agent/instrumentation/sunspot.rb +1 -1
  23. data/lib/new_relic/agent/method_tracer.rb +55 -55
  24. data/lib/new_relic/agent/sampler.rb +42 -38
  25. data/lib/new_relic/agent/samplers/cpu_sampler.rb +4 -4
  26. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +7 -7
  27. data/lib/new_relic/agent/samplers/memory_sampler.rb +11 -11
  28. data/lib/new_relic/agent/samplers/object_sampler.rb +1 -1
  29. data/lib/new_relic/agent/shim_agent.rb +20 -16
  30. data/lib/new_relic/agent/stats_engine.rb +3 -3
  31. data/lib/new_relic/agent/stats_engine/metric_stats.rb +28 -28
  32. data/lib/new_relic/agent/stats_engine/samplers.rb +16 -16
  33. data/lib/new_relic/agent/stats_engine/transactions.rb +25 -25
  34. data/lib/new_relic/agent/transaction_sampler.rb +68 -69
  35. data/lib/new_relic/agent/worker_loop.rb +13 -13
  36. data/lib/new_relic/collection_helper.rb +6 -6
  37. data/lib/new_relic/command.rb +14 -14
  38. data/lib/new_relic/commands/deployments.rb +19 -19
  39. data/lib/new_relic/commands/install.rb +25 -15
  40. data/lib/new_relic/control.rb +25 -25
  41. data/lib/new_relic/control/configuration.rb +17 -17
  42. data/lib/new_relic/control/frameworks/external.rb +3 -3
  43. data/lib/new_relic/control/frameworks/merb.rb +6 -6
  44. data/lib/new_relic/control/frameworks/rails.rb +17 -17
  45. data/lib/new_relic/control/frameworks/rails3.rb +11 -27
  46. data/lib/new_relic/control/frameworks/ruby.rb +6 -6
  47. data/lib/new_relic/control/frameworks/sinatra.rb +4 -4
  48. data/lib/new_relic/control/instrumentation.rb +8 -8
  49. data/lib/new_relic/control/logging_methods.rb +13 -13
  50. data/lib/new_relic/control/profiling.rb +2 -2
  51. data/lib/new_relic/control/server_methods.rb +17 -17
  52. data/lib/new_relic/delayed_job_injection.rb +1 -1
  53. data/lib/new_relic/histogram.rb +73 -71
  54. data/lib/new_relic/local_environment.rb +45 -45
  55. data/lib/new_relic/merbtasks.rb +1 -1
  56. data/lib/new_relic/metric_data.rb +5 -5
  57. data/lib/new_relic/metric_parser.rb +22 -22
  58. data/lib/new_relic/metric_parser/action_mailer.rb +4 -4
  59. data/lib/new_relic/metric_parser/active_merchant.rb +8 -8
  60. data/lib/new_relic/metric_parser/active_record.rb +2 -2
  61. data/lib/new_relic/metric_parser/apdex.rb +86 -51
  62. data/lib/new_relic/metric_parser/controller.rb +10 -10
  63. data/lib/new_relic/metric_parser/controller_cpu.rb +5 -5
  64. data/lib/new_relic/metric_parser/errors.rb +1 -1
  65. data/lib/new_relic/metric_parser/external.rb +3 -3
  66. data/lib/new_relic/metric_parser/mem_cache.rb +2 -2
  67. data/lib/new_relic/metric_parser/other_transaction.rb +7 -7
  68. data/lib/new_relic/metric_parser/view.rb +5 -5
  69. data/lib/new_relic/metric_parser/web_frontend.rb +1 -1
  70. data/lib/new_relic/metric_parser/web_service.rb +1 -1
  71. data/lib/new_relic/metric_spec.rb +13 -13
  72. data/lib/new_relic/noticed_error.rb +4 -4
  73. data/lib/new_relic/rack/developer_mode.rb +33 -33
  74. data/lib/new_relic/rack/metric_app.rb +2 -2
  75. data/lib/new_relic/recipes.rb +9 -9
  76. data/lib/new_relic/stats.rb +57 -57
  77. data/lib/new_relic/timer_lib.rb +2 -2
  78. data/lib/new_relic/transaction_analysis.rb +19 -19
  79. data/lib/new_relic/transaction_sample.rb +101 -101
  80. data/lib/new_relic/url_rule.rb +3 -3
  81. data/lib/new_relic/version.rb +10 -10
  82. data/lib/newrelic_rpm.rb +6 -4
  83. data/lib/tasks/all.rb +1 -1
  84. data/newrelic_rpm.gemspec +3 -3
  85. data/test/new_relic/rack/episodes_test.rb +1 -0
  86. metadata +24 -42
@@ -1,7 +1,7 @@
1
1
 
2
2
  module NewRelic
3
3
  COLLAPSE_SEGMENTS_THRESHOLD = 2
4
-
4
+
5
5
  MYSQL_EXPLAIN_COLUMNS = [
6
6
  "Id",
7
7
  "Select Type",
@@ -14,44 +14,44 @@ module NewRelic
14
14
  "Rows",
15
15
  "Extra"
16
16
  ].freeze
17
-
17
+
18
18
  class TransactionSample
19
-
19
+
20
20
  attr_accessor :params, :root_segment
21
21
  EMPTY_ARRAY = [].freeze
22
-
22
+
23
23
  @@start_time = Time.now
24
24
 
25
25
  include TransactionAnalysis
26
26
  class Segment
27
27
  attr_reader :entry_timestamp
28
- # The exit timestamp will be relative except for the outermost sample which will
28
+ # The exit timestamp will be relative except for the outermost sample which will
29
29
  # have a timestamp.
30
30
  attr_reader :exit_timestamp
31
31
  attr_reader :parent_segment
32
32
  attr_reader :metric_name
33
33
  attr_reader :segment_id
34
-
34
+
35
35
  def initialize(timestamp, metric_name, segment_id)
36
36
  @entry_timestamp = timestamp
37
37
  @metric_name = metric_name || '<unknown>'
38
38
  @segment_id = segment_id || object_id
39
39
  end
40
-
40
+
41
41
  def end_trace(timestamp)
42
42
  @exit_timestamp = timestamp
43
43
  end
44
-
44
+
45
45
  def add_called_segment(s)
46
46
  @called_segments ||= []
47
47
  @called_segments << s
48
48
  s.parent_segment = self
49
49
  end
50
-
50
+
51
51
  def to_s
52
52
  to_debug_str(0)
53
53
  end
54
-
54
+
55
55
  def to_json
56
56
  map = {:entry_timestamp => @entry_timestamp,
57
57
  :exit_timestamp => @exit_timestamp,
@@ -65,7 +65,7 @@ module NewRelic
65
65
  end
66
66
  map.to_json
67
67
  end
68
-
68
+
69
69
  def path_string
70
70
  "#{metric_name}[#{called_segments.collect {|segment| segment.path_string }.join('')}]"
71
71
  end
@@ -78,7 +78,7 @@ module NewRelic
78
78
  str
79
79
  end
80
80
  def to_debug_str(depth)
81
- tab = " " * depth
81
+ tab = " " * depth
82
82
  s = tab.clone
83
83
  s << ">> #{'%3i ms' % (@entry_timestamp*1000)} [#{self.class.name.split("::").last}] #{metric_name} \n"
84
84
  unless params.empty?
@@ -97,21 +97,21 @@ module NewRelic
97
97
  end
98
98
  s << " #{metric_name}\n"
99
99
  end
100
-
100
+
101
101
  def called_segments
102
102
  @called_segments || EMPTY_ARRAY
103
103
  end
104
-
104
+
105
105
  # return the total duration of this segment
106
106
  def duration
107
107
  (@exit_timestamp - @entry_timestamp).to_f
108
108
  end
109
-
110
- # return the duration of this segment without
109
+
110
+ # return the duration of this segment without
111
111
  # including the time in the called segments
112
112
  def exclusive_duration
113
113
  d = duration
114
-
114
+
115
115
  if @called_segments
116
116
  @called_segments.each do |segment|
117
117
  d -= segment.duration
@@ -146,27 +146,27 @@ module NewRelic
146
146
  # bandwidth etc as most segments have no parameters
147
147
  params[key] = value
148
148
  end
149
-
149
+
150
150
  def [](key)
151
151
  params[key]
152
152
  end
153
-
153
+
154
154
  def params
155
155
  @params ||= {}
156
156
  end
157
-
158
- # call the provided block for this segment and each
157
+
158
+ # call the provided block for this segment and each
159
159
  # of the called segments
160
160
  def each_segment(&block)
161
161
  block.call self
162
-
162
+
163
163
  if @called_segments
164
164
  @called_segments.each do |segment|
165
165
  segment.each_segment(&block)
166
166
  end
167
167
  end
168
168
  end
169
-
169
+
170
170
  def find_segment(id)
171
171
  return self if @segment_id == id
172
172
  called_segments.each do |segment|
@@ -175,14 +175,14 @@ module NewRelic
175
175
  end
176
176
  nil
177
177
  end
178
-
178
+
179
179
  # perform this in the runtime environment of a managed application, to explain the sql
180
180
  # statement(s) executed within a segment of a transaction sample.
181
- # returns an array of explanations (which is an array rows consisting of
181
+ # returns an array of explanations (which is an array rows consisting of
182
182
  # an array of strings for each column returned by the the explain query)
183
183
  # Note this happens only for statements whose execution time exceeds a threshold (e.g. 500ms)
184
184
  # and only within the slowest transaction in a report period, selected for shipment to RPM
185
- def explain_sql
185
+ def explain_sql
186
186
  sql = params[:sql]
187
187
  return nil unless sql && params[:connection_config]
188
188
  statements = sql.split(";\n")
@@ -191,7 +191,7 @@ module NewRelic
191
191
  if statement.split($;, 2)[0].upcase == 'SELECT'
192
192
  explain_resultset = []
193
193
  begin
194
- connection = NewRelic::TransactionSample.get_connection(params[:connection_config])
194
+ connection = NewRelic::TransactionSample.get_connection(params[:connection_config])
195
195
  if connection
196
196
  # The resultset type varies for different drivers. Only thing you can count on is
197
197
  # that it implements each. Also: can't use select_rows because the native postgres
@@ -224,7 +224,7 @@ module NewRelic
224
224
  def params=(p)
225
225
  @params = p
226
226
  end
227
-
227
+
228
228
 
229
229
  def handle_exception_in_explain(e)
230
230
  x = 1 # this is here so that code coverage knows we've entered this block
@@ -235,11 +235,11 @@ module NewRelic
235
235
  def obfuscated_sql
236
236
  TransactionSample.obfuscate_sql(params[:sql])
237
237
  end
238
-
238
+
239
239
  def called_segments=(segments)
240
240
  @called_segments = segments
241
241
  end
242
-
242
+
243
243
  protected
244
244
  def parent_segment=(s)
245
245
  @parent_segment = s
@@ -251,57 +251,57 @@ module NewRelic
251
251
  end
252
252
 
253
253
  class SummarySegment < Segment
254
-
255
-
254
+
255
+
256
256
  def initialize(segment)
257
257
  super segment.entry_timestamp, segment.metric_name, nil
258
-
258
+
259
259
  add_segments segment.called_segments
260
-
260
+
261
261
  end_trace segment.exit_timestamp
262
262
  end
263
-
263
+
264
264
  def add_segments(segments)
265
265
  segments.collect do |segment|
266
266
  SummarySegment.new(segment)
267
267
  end.each {|segment| add_called_segment(segment)}
268
268
  end
269
-
269
+
270
270
  end
271
-
271
+
272
272
  class CompositeSegment < Segment
273
273
  attr_reader :detail_segments
274
-
274
+
275
275
  def initialize(segments)
276
276
  summary = SummarySegment.new(segments.first)
277
277
  super summary.entry_timestamp, "Repeating pattern (#{segments.length} repeats)", nil
278
-
278
+
279
279
  summary.end_trace(segments.last.exit_timestamp)
280
-
280
+
281
281
  @detail_segments = segments.clone
282
-
282
+
283
283
  add_called_segment(summary)
284
284
  end_trace summary.exit_timestamp
285
285
  end
286
-
286
+
287
287
  def detail_segments=(segments)
288
288
  @detail_segments = segments
289
289
  end
290
-
290
+
291
291
  end
292
-
292
+
293
293
  class << self
294
294
  def obfuscate_sql(sql)
295
- NewRelic::Agent.instance.obfuscator.call(sql)
295
+ NewRelic::Agent.instance.obfuscator.call(sql)
296
296
  end
297
-
297
+
298
298
  def get_connection(config)
299
299
  @@connections ||= {}
300
-
300
+
301
301
  connection = @@connections[config]
302
-
302
+
303
303
  return connection if connection
304
-
304
+
305
305
  begin
306
306
  connection = ActiveRecord::Base.send("#{config[:adapter]}_connection", config)
307
307
  @@connections[config] = connection
@@ -311,7 +311,7 @@ module NewRelic
311
311
  nil
312
312
  end
313
313
  end
314
-
314
+
315
315
  def close_connections
316
316
  @@connections ||= {}
317
317
  @@connections.values.each do |connection|
@@ -320,17 +320,17 @@ module NewRelic
320
320
  rescue
321
321
  end
322
322
  end
323
-
323
+
324
324
  @@connections = {}
325
325
  end
326
-
326
+
327
327
  end
328
328
 
329
329
  attr_accessor :profile
330
330
  attr_reader :root_segment
331
331
  attr_reader :params
332
332
  attr_reader :sample_id
333
-
333
+
334
334
  def initialize(time = Time.now.to_f, sample_id = nil)
335
335
  @sample_id = sample_id || object_id
336
336
  @start_time = time
@@ -342,71 +342,71 @@ module NewRelic
342
342
  def count_segments
343
343
  @root_segment.count_segments - 1 # don't count the root segment
344
344
  end
345
-
345
+
346
346
  def truncate(max)
347
347
  original_count = count_segments
348
-
348
+
349
349
  return if original_count <= max
350
-
350
+
351
351
  @root_segment.truncate(max-1)
352
-
352
+
353
353
  if params[:segment_count].nil?
354
354
  params[:segment_count] = original_count
355
355
  end
356
356
  end
357
-
357
+
358
358
  # offset from start of app
359
359
  def timestamp
360
360
  @start_time - @@start_time.to_f
361
361
  end
362
-
362
+
363
363
  # Used in the server only
364
364
  def to_json(options = {}) #:nodoc:
365
365
  map = {:sample_id => @sample_id,
366
366
  :start_time => @start_time,
367
367
  :root_segment => @root_segment}
368
368
  if @params && !@params.empty?
369
- map[:params] = @params
369
+ map[:params] = @params
370
370
  end
371
371
  map.to_json
372
372
  end
373
-
374
-
373
+
374
+
375
375
 
376
376
  def start_time
377
377
  Time.at(@start_time)
378
378
  end
379
-
379
+
380
380
  def path_string
381
381
  @root_segment.path_string
382
382
  end
383
-
383
+
384
384
  def create_segment(relative_timestamp, metric_name, segment_id = nil)
385
385
  raise TypeError.new("Frozen Transaction Sample") if frozen?
386
- NewRelic::TransactionSample::Segment.new(relative_timestamp, metric_name, segment_id)
386
+ NewRelic::TransactionSample::Segment.new(relative_timestamp, metric_name, segment_id)
387
387
  end
388
-
388
+
389
389
  def duration
390
390
  root_segment.duration
391
391
  end
392
-
392
+
393
393
  def each_segment(&block)
394
394
  @root_segment.each_segment(&block)
395
395
  end
396
-
396
+
397
397
  def to_s_compact
398
398
  @root_segment.to_s_compact
399
399
  end
400
-
400
+
401
401
  def find_segment(id)
402
402
  @root_segment.find_segment(id)
403
403
  end
404
-
404
+
405
405
  def to_s
406
406
  s = "Transaction Sample collected at #{start_time}\n"
407
407
  s << " {\n"
408
408
  s << " Path: #{params[:path]} \n"
409
-
409
+
410
410
  params.each do |k,v|
411
411
  next if k == :path
412
412
  s << " #{k}: " <<
@@ -422,7 +422,7 @@ module NewRelic
422
422
  s << " }\n\n"
423
423
  s << @root_segment.to_debug_str(0)
424
424
  end
425
-
425
+
426
426
  # return a new transaction sample that treats segments
427
427
  # with the given regular expression in their name as if they
428
428
  # were never called at all. This allows us to strip out segments
@@ -430,39 +430,39 @@ module NewRelic
430
430
  # normally show up in production (like Rails/Application Code Loading)
431
431
  def omit_segments_with(regex)
432
432
  regex = Regexp.new(regex)
433
-
433
+
434
434
  sample = TransactionSample.new(@start_time, sample_id)
435
-
435
+
436
436
  params.each {|k,v| sample.params[k] = v}
437
-
437
+
438
438
  delta = build_segment_with_omissions(sample, 0.0, @root_segment, sample.root_segment, regex)
439
439
  sample.root_segment.end_trace(@root_segment.exit_timestamp - delta)
440
440
  sample.profile = self.profile
441
441
  sample
442
442
  end
443
-
443
+
444
444
  # return a new transaction sample that can be sent to the RPM service.
445
445
  # this involves potentially one or more of the following options
446
- #
446
+ #
447
447
  # :explain_sql : run EXPLAIN on all queries whose response times equal the value for this key
448
448
  # (for example :explain_sql => 2.0 would explain everything over 2 seconds. 0.0 would explain everything.)
449
449
  # :keep_backtraces : keep backtraces, significantly increasing size of trace (off by default)
450
450
  # :record_sql => [ :raw | :obfuscated] : copy over the sql, obfuscating if necessary
451
451
  def prepare_to_send(options={})
452
452
  sample = TransactionSample.new(@start_time, sample_id)
453
-
453
+
454
454
  sample.params.merge! self.params
455
-
455
+
456
456
  begin
457
457
  build_segment_for_transfer(sample, @root_segment, sample.root_segment, options)
458
458
  ensure
459
459
  self.class.close_connections
460
460
  end
461
-
462
- sample.root_segment.end_trace(@root_segment.exit_timestamp)
461
+
462
+ sample.root_segment.end_trace(@root_segment.exit_timestamp)
463
463
  sample
464
464
  end
465
-
465
+
466
466
  def analyze
467
467
  sample = self
468
468
  original_path_string = nil
@@ -474,27 +474,27 @@ module NewRelic
474
474
  sample = new_sample
475
475
  return sample if sample.path_string.to_s == original_path_string
476
476
  end
477
-
477
+
478
478
  end
479
-
479
+
480
480
  def params=(params)
481
481
  @params = params
482
482
  end
483
483
 
484
484
  private
485
-
485
+
486
486
  def analyze_called_segments(called_segments)
487
487
  path = nil
488
488
  like_segments = []
489
-
490
- segments = []
491
-
489
+
490
+ segments = []
491
+
492
492
  called_segments.each do |segment|
493
493
  segment = segment.dup
494
494
  segment.called_segments = analyze_called_segments(segment.called_segments)
495
-
495
+
496
496
  current_path = segment.path_string
497
- if path == current_path
497
+ if path == current_path
498
498
  like_segments << segment
499
499
  else
500
500
  segments += summarize_segments(like_segments)
@@ -505,10 +505,10 @@ module NewRelic
505
505
  end
506
506
  end
507
507
  segments += summarize_segments(like_segments)
508
-
508
+
509
509
  segments
510
510
  end
511
-
511
+
512
512
  def summarize_segments(like_segments)
513
513
  if like_segments.length > COLLAPSE_SEGMENTS_THRESHOLD
514
514
  [CompositeSegment.new(like_segments)]
@@ -516,33 +516,33 @@ module NewRelic
516
516
  like_segments
517
517
  end
518
518
  end
519
-
519
+
520
520
  def build_segment_with_omissions(new_sample, time_delta, source_segment, target_segment, regex)
521
521
  source_segment.called_segments.each do |source_called_segment|
522
522
  # if this segment's metric name matches the given regular expression, bail
523
523
  # here and increase the amount of time that we reduce the target sample with
524
524
  # by this omitted segment's duration.
525
525
  do_omit = regex =~ source_called_segment.metric_name
526
-
526
+
527
527
  if do_omit
528
528
  time_delta += source_called_segment.duration
529
529
  else
530
530
  target_called_segment = new_sample.create_segment(
531
- source_called_segment.entry_timestamp - time_delta,
531
+ source_called_segment.entry_timestamp - time_delta,
532
532
  source_called_segment.metric_name,
533
533
  source_called_segment.segment_id)
534
-
534
+
535
535
  target_segment.add_called_segment target_called_segment
536
536
  source_called_segment.params.each do |k,v|
537
537
  target_called_segment[k]=v
538
538
  end
539
-
539
+
540
540
  time_delta = build_segment_with_omissions(
541
541
  new_sample, time_delta, source_called_segment, target_called_segment, regex)
542
542
  target_called_segment.end_trace(source_called_segment.exit_timestamp - time_delta)
543
543
  end
544
544
  end
545
-
545
+
546
546
  return time_delta
547
547
  end
548
548
 
@@ -564,7 +564,7 @@ module NewRelic
564
564
  if options[:record_sql] && options[:record_sql] && options[:explain_sql] && source_called_segment.duration > options[:explain_sql].to_f
565
565
  target_called_segment[:explanation] = source_called_segment.explain_sql
566
566
  end
567
-
567
+
568
568
  target_called_segment[:sql] = case options[:record_sql]
569
569
  when :raw then v
570
570
  when :obfuscated then TransactionSample.obfuscate_sql(v)
@@ -573,7 +573,7 @@ module NewRelic
573
573
  when :connection_config
574
574
  # don't copy it
575
575
  else
576
- target_called_segment[k]=v
576
+ target_called_segment[k]=v
577
577
  end
578
578
  end
579
579
 
@@ -581,6 +581,6 @@ module NewRelic
581
581
  target_called_segment.end_trace(source_called_segment.exit_timestamp)
582
582
  end
583
583
  end
584
-
584
+
585
585
  end
586
586
  end