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,10 +1,10 @@
1
1
  module NewRelic
2
2
  module Agent
3
3
  class StatsEngine
4
-
4
+
5
5
  # Defines methods that stub out the stats engine methods
6
6
  # when the agent is disabled
7
-
7
+
8
8
  class ScopeStackElement
9
9
  attr_reader :name, :deduct_call_time_from_parent
10
10
  attr_accessor :children_time
@@ -14,7 +14,7 @@ module Agent
14
14
  @children_time = 0
15
15
  end
16
16
  end
17
-
17
+
18
18
  module Transactions
19
19
  module Shim # :nodoc:
20
20
  def start_transaction(*args); end
@@ -25,18 +25,18 @@ module Agent
25
25
  def scope_name; end
26
26
  def pop_scope(*args); end
27
27
  end
28
-
28
+
29
29
  def transaction_sampler= sampler
30
30
  fail "Can't add a scope listener midflight in a transaction" if scope_stack.any?
31
31
  @transaction_sampler = sampler
32
32
  end
33
-
33
+
34
34
  def remove_transaction_sampler(l)
35
35
  @transaction_sampler = nil
36
36
  end
37
-
37
+
38
38
  def push_scope(metric, time = Time.now.to_f, deduct_call_time_from_parent = true)
39
-
39
+
40
40
  stack = scope_stack
41
41
  if collecting_gc?
42
42
  if stack.empty?
@@ -52,14 +52,14 @@ module Agent
52
52
  stack.push scope
53
53
  scope
54
54
  end
55
-
55
+
56
56
  def pop_scope(expected_scope, duration, time=Time.now.to_f)
57
57
  capture_gc_time if collecting_gc?
58
58
  stack = scope_stack
59
59
  scope = stack.pop
60
60
  fail "unbalanced pop from blame stack, got #{scope ? scope.name : 'nil'}, expected #{expected_scope ? expected_scope.name : 'nil'}" if scope != expected_scope
61
-
62
- if !stack.empty?
61
+
62
+ if !stack.empty?
63
63
  if scope.deduct_call_time_from_parent
64
64
  stack.last.children_time += duration
65
65
  else
@@ -69,53 +69,53 @@ module Agent
69
69
  @transaction_sampler.notice_pop_scope(scope.name, time) if @transaction_sampler
70
70
  scope
71
71
  end
72
-
72
+
73
73
  def peek_scope
74
74
  scope_stack.last
75
75
  end
76
-
76
+
77
77
  # set the name of the transaction for the current thread, which will be used
78
78
  # to define the scope of all traced methods called on this thread until the
79
- # scope stack is empty.
79
+ # scope stack is empty.
80
80
  #
81
- # currently the transaction name is the name of the controller action that
81
+ # currently the transaction name is the name of the controller action that
82
82
  # is invoked via the dispatcher, but conceivably we could use other transaction
83
83
  # names in the future if the traced application does more than service http request
84
84
  # via controller actions
85
85
  def scope_name=(transaction)
86
86
  Thread::current[:newrelic_scope_name] = transaction
87
87
  end
88
-
88
+
89
89
  def scope_name
90
90
  Thread::current[:newrelic_scope_name]
91
91
  end
92
-
92
+
93
93
  # Start a new transaction, unless one is already in progress
94
94
  def start_transaction(name = nil)
95
95
  Thread::current[:newrelic_scope_stack] ||= []
96
96
  self.scope_name = name if name
97
97
  end
98
-
98
+
99
99
  # Try to clean up gracefully, otherwise we leave things hanging around on thread locals.
100
100
  # If it looks like a transaction is still in progress, then maybe this is an inner transaction
101
101
  # and is ignored.
102
102
  #
103
103
  def end_transaction
104
104
  stack = scope_stack
105
-
105
+
106
106
  if stack && stack.empty?
107
107
  Thread::current[:newrelic_scope_stack] = nil
108
108
  Thread::current[:newrelic_scope_name] = nil
109
109
  end
110
110
  end
111
-
111
+
112
112
  private
113
-
113
+
114
114
  # Make sure we don't do this in a multi-threaded environment
115
115
  def collecting_gc?
116
- @@collecting_gc ||= GC.respond_to?(:time) && GC.respond_to?(:collections) && !NewRelic::Control.instance.multi_threaded?
116
+ @@collecting_gc ||= GC.respond_to?(:time) && GC.respond_to?(:collections) && !NewRelic::Control.instance.multi_threaded?
117
117
  end
118
-
118
+
119
119
  # Assumes collecting_gc?
120
120
  def capture_gc_time
121
121
  # Skip this if we are already in this segment
@@ -133,16 +133,16 @@ module Agent
133
133
  gc_scope = push_scope("GC/cumulative", time - elapsed)
134
134
  # GC stats are collected into a blamed metric which allows
135
135
  # us to show the stats controller by controller
136
- gc_stats = NewRelic::Agent.get_stats(gc_scope.name, true)
136
+ gc_stats = NewRelic::Agent.get_stats(gc_scope.name, true)
137
137
  gc_stats.record_multiple_data_points(elapsed, num_calls)
138
138
  pop_scope(gc_scope, elapsed, time)
139
139
  end
140
140
  end
141
-
141
+
142
142
  def scope_stack
143
143
  Thread::current[:newrelic_scope_stack] ||= []
144
144
  end
145
-
145
+
146
146
  end
147
147
  end
148
148
  end
@@ -1,8 +1,8 @@
1
1
  module NewRelic
2
2
  module Agent
3
-
3
+
4
4
  class TransactionSampler
5
-
5
+
6
6
  # Module defining methods stubbed out when the agent is disabled
7
7
  module Shim #:nodoc:
8
8
  def notice_first_scope_push(*args); end
@@ -10,12 +10,12 @@ module Agent
10
10
  def notice_pop_scope(*args); end
11
11
  def notice_scope_empty(*args); end
12
12
  end
13
-
13
+
14
14
  BUILDER_KEY = :transaction_sample_builder
15
15
 
16
16
  attr_accessor :stack_trace_threshold, :random_sampling, :sampling_rate
17
17
  attr_reader :samples, :last_sample, :disabled
18
-
18
+
19
19
  def initialize
20
20
  @samples = []
21
21
  @harvest_count = 0
@@ -27,7 +27,7 @@ module Agent
27
27
  @stack_trace_threshold = sampler_config.fetch('stack_trace_threshold', 0.500).to_f
28
28
  @samples_lock = Mutex.new
29
29
  end
30
-
30
+
31
31
  def current_sample_id
32
32
  b=builder
33
33
  b and b.sample_id
@@ -42,22 +42,22 @@ module Agent
42
42
  @disabled = true
43
43
  NewRelic::Agent.instance.stats_engine.remove_transaction_sampler self
44
44
  end
45
-
45
+
46
46
  def sampling_rate=(val)
47
47
  @sampling_rate = val
48
48
  @harvest_count = rand(val)
49
49
  end
50
-
50
+
51
51
  def notice_first_scope_push(time)
52
52
  start_builder(time.to_f) unless disabled
53
53
  end
54
-
55
- def notice_push_scope(scope, time=Time.now.to_f)
56
-
54
+
55
+ def notice_push_scope(scope, time=Time.now)
56
+
57
57
  return unless builder
58
-
59
- builder.trace_entry(scope, time)
60
-
58
+
59
+ builder.trace_entry(scope, time.to_f)
60
+
61
61
  # in developer mode, capture the stack trace with the segment.
62
62
  # this is cpu and memory expensive and therefore should not be
63
63
  # turned on in production mode
@@ -69,66 +69,66 @@ module Agent
69
69
  while trace.first =~/\/lib\/new_relic\/agent\//
70
70
  trace.shift
71
71
  end
72
-
72
+
73
73
  trace = trace[0..39] if trace.length > 40
74
74
  segment[:backtrace] = trace
75
75
  end
76
76
  end
77
77
  end
78
-
78
+
79
79
  def scope_depth
80
80
  return 0 unless builder
81
81
 
82
82
  builder.scope_depth
83
83
  end
84
-
85
- def notice_pop_scope(scope, time = Time.now.to_f)
84
+
85
+ def notice_pop_scope(scope, time = Time.now)
86
86
  return unless builder
87
87
  raise "frozen already???" if builder.sample.frozen?
88
- builder.trace_exit(scope, time)
88
+ builder.trace_exit(scope, time.to_f)
89
89
  end
90
-
90
+
91
91
  # This is called when we are done with the transaction. We've
92
92
  # unwound the stack to the top level.
93
- def notice_scope_empty(time=Time.now.to_f)
94
-
93
+ def notice_scope_empty(time=Time.now)
94
+
95
95
  last_builder = builder
96
96
  return unless last_builder
97
97
 
98
- last_builder.finish_trace(time)
98
+ last_builder.finish_trace(time.to_f)
99
99
  clear_builder
100
100
  return if last_builder.ignored?
101
-
101
+
102
102
  @samples_lock.synchronize do
103
103
  @last_sample = last_builder.sample
104
-
104
+
105
105
  @random_sample = @last_sample if @random_sampling
106
-
106
+
107
107
  # ensure we don't collect more than a specified number of samples in memory
108
108
  @samples << @last_sample if NewRelic::Control.instance.developer_mode?
109
109
  @samples.shift while @samples.length > @max_samples
110
-
110
+
111
111
  if @slowest_sample.nil? || @slowest_sample.duration < @last_sample.duration
112
112
  @slowest_sample = @last_sample
113
113
  end
114
114
  end
115
115
  end
116
-
116
+
117
117
  def notice_transaction(path, uri=nil, params={})
118
118
  builder.set_transaction_info(path, uri, params) if !disabled && builder
119
119
  end
120
-
120
+
121
121
  def ignore_transaction
122
122
  builder.ignore_transaction if builder
123
123
  end
124
124
  def notice_profile(profile)
125
125
  builder.set_profile(profile) if builder
126
126
  end
127
-
127
+
128
128
  def notice_transaction_cpu_time(cpu_time)
129
129
  builder.set_transaction_cpu_time(cpu_time) if builder
130
130
  end
131
-
131
+
132
132
  MAX_DATA_LENGTH = 16384
133
133
  # duration is seconds, float value.
134
134
  def notice_extra_data(message, duration, key, config=nil, config_key=nil)
@@ -148,7 +148,7 @@ module Agent
148
148
  end
149
149
 
150
150
  private :notice_extra_data
151
-
151
+
152
152
  # some statements (particularly INSERTS with large BLOBS
153
153
  # may be very large; we should trim them to a maximum usable length
154
154
  # config is the driver configuration for the connection
@@ -164,34 +164,34 @@ module Agent
164
164
  def notice_nosql(key, duration)
165
165
  notice_extra_data(key, duration, :key)
166
166
  end
167
-
167
+
168
168
  # get the set of collected samples, merging into previous samples,
169
- # and clear the collected sample list.
170
-
169
+ # and clear the collected sample list.
170
+
171
171
  def harvest(previous = nil, slow_threshold = 2.0)
172
172
  return [] if disabled
173
173
  result = []
174
174
  previous ||= []
175
-
175
+
176
176
  previous = [previous] unless previous.is_a?(Array)
177
-
177
+
178
178
  previous_slowest = previous.inject(nil) {|a,ts| (a) ? ((a.duration > ts.duration) ? a : ts) : ts}
179
-
179
+
180
180
  @samples_lock.synchronize do
181
-
182
- if @random_sampling
181
+
182
+ if @random_sampling
183
183
  @harvest_count += 1
184
-
184
+
185
185
  if (@harvest_count % @sampling_rate) == 0
186
186
  result << @random_sample if @random_sample
187
187
  else
188
188
  @random_sample = nil # if we don't nil this out, then we won't send the slowest if slowest == @random_sample
189
189
  end
190
190
  end
191
-
191
+
192
192
  slowest = @slowest_sample
193
193
  @slowest_sample = nil
194
-
194
+
195
195
  if slowest && slowest != @random_sample && slowest.duration >= slow_threshold
196
196
  if previous_slowest.nil? || previous_slowest.duration < slowest.duration
197
197
  result << slowest
@@ -215,13 +215,13 @@ module Agent
215
215
  @last_sample = nil
216
216
  end
217
217
 
218
- private
219
-
218
+ private
219
+
220
220
  def start_builder(time=nil)
221
221
  if disabled || Thread::current[:record_tt] == false || !NewRelic::Agent.is_execution_traced?
222
222
  clear_builder
223
223
  else
224
- Thread::current[BUILDER_KEY] ||= TransactionSampleBuilder.new(time)
224
+ Thread::current[BUILDER_KEY] ||= TransactionSampleBuilder.new(time)
225
225
  end
226
226
  end
227
227
  def builder
@@ -230,7 +230,7 @@ module Agent
230
230
  def clear_builder
231
231
  Thread::current[BUILDER_KEY] = nil
232
232
  end
233
-
233
+
234
234
  end
235
235
 
236
236
  # a builder is created with every sampled transaction, to dynamically
@@ -238,13 +238,12 @@ module Agent
238
238
  # accessed by any other thread so no need for synchronization.
239
239
  class TransactionSampleBuilder
240
240
  attr_reader :current_segment, :sample
241
-
241
+
242
242
  include NewRelic::CollectionHelper
243
-
244
- def initialize(time=nil)
245
- time ||= Time.now.to_f
246
- @sample = NewRelic::TransactionSample.new(time)
247
- @sample_start = time
243
+
244
+ def initialize(time=Time.now)
245
+ @sample = NewRelic::TransactionSample.new(time.to_f)
246
+ @sample_start = time.to_f
248
247
  @current_segment = @sample.root_segment
249
248
  end
250
249
 
@@ -252,13 +251,13 @@ module Agent
252
251
  @sample.sample_id
253
252
  end
254
253
  def ignored?
255
- @ignore || @sample.params[:path].nil?
254
+ @ignore || @sample.params[:path].nil?
256
255
  end
257
256
  def ignore_transaction
258
257
  @ignore = true
259
258
  end
260
259
  def trace_entry(metric_name, time)
261
- segment = @sample.create_segment(time - @sample_start, metric_name)
260
+ segment = @sample.create_segment(time.to_f - @sample_start, metric_name)
262
261
  @current_segment.add_called_segment(segment)
263
262
  @current_segment = segment
264
263
  end
@@ -267,10 +266,10 @@ module Agent
267
266
  if metric_name != @current_segment.metric_name
268
267
  fail "unbalanced entry/exit: #{metric_name} != #{@current_segment.metric_name}"
269
268
  end
270
- @current_segment.end_trace(time - @sample_start)
269
+ @current_segment.end_trace(time.to_f - @sample_start)
271
270
  @current_segment = @current_segment.parent_segment
272
271
  end
273
-
272
+
274
273
  def finish_trace(time)
275
274
  # This should never get called twice, but in a rare case that we can't reproduce in house it does.
276
275
  # log forensics and return gracefully
@@ -279,53 +278,53 @@ module Agent
279
278
  log.error "Unexpected double-freeze of Transaction Trace Object: \n#{@sample.to_s}"
280
279
  return
281
280
  end
282
- @sample.root_segment.end_trace(time - @sample_start)
281
+ @sample.root_segment.end_trace(time.to_f - @sample_start)
283
282
  @sample.params[:custom_params] = normalize_params(NewRelic::Agent::Instrumentation::MetricFrame.custom_parameters)
284
283
  @sample.freeze
285
284
  @current_segment = nil
286
285
  end
287
-
286
+
288
287
  def scope_depth
289
288
  depth = -1 # have to account for the root
290
289
  current = @current_segment
291
-
290
+
292
291
  while(current)
293
292
  depth += 1
294
293
  current = current.parent_segment
295
294
  end
296
-
295
+
297
296
  depth
298
297
  end
299
-
298
+
300
299
  def freeze
301
300
  @sample.freeze unless sample.frozen?
302
301
  end
303
-
302
+
304
303
  def set_profile(profile)
305
304
  @sample.profile = profile
306
305
  end
307
-
306
+
308
307
  def set_transaction_info(path, uri, params)
309
308
  @sample.params[:path] = path
310
-
309
+
311
310
  if NewRelic::Control.instance.capture_params
312
311
  params = normalize_params params
313
-
312
+
314
313
  @sample.params[:request_params].merge!(params)
315
314
  @sample.params[:request_params].delete :controller
316
315
  @sample.params[:request_params].delete :action
317
316
  end
318
- @sample.params[:uri] ||= uri || params[:uri]
317
+ @sample.params[:uri] ||= uri || params[:uri]
319
318
  end
320
-
319
+
321
320
  def set_transaction_cpu_time(cpu_time)
322
321
  @sample.params[:cpu_time] = cpu_time
323
322
  end
324
-
323
+
325
324
  def sample
326
325
  @sample
327
326
  end
328
-
327
+
329
328
  end
330
329
  end
331
330
  end