newrelic_rpm 3.9.4.245 → 3.9.5.251

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +57 -0
  3. data/Guardfile +1 -0
  4. data/lib/new_relic/agent/agent.rb +3 -3
  5. data/lib/new_relic/agent/audit_logger.rb +5 -2
  6. data/lib/new_relic/agent/configuration/default_source.rb +11 -5
  7. data/lib/new_relic/agent/error_collector.rb +14 -1
  8. data/lib/new_relic/agent/hostname.rb +22 -1
  9. data/lib/new_relic/agent/instrumentation/middleware_tracing.rb +8 -2
  10. data/lib/new_relic/agent/instrumentation/queue_time.rb +9 -6
  11. data/lib/new_relic/agent/method_tracer.rb +51 -172
  12. data/lib/new_relic/agent/method_tracer_helpers.rb +90 -0
  13. data/lib/new_relic/agent/new_relic_service.rb +33 -11
  14. data/lib/new_relic/agent/new_relic_service/encoders.rb +9 -5
  15. data/lib/new_relic/agent/request_sampler.rb +20 -12
  16. data/lib/new_relic/agent/rules_engine.rb +31 -78
  17. data/lib/new_relic/agent/rules_engine/replacement_rule.rb +76 -0
  18. data/lib/new_relic/agent/rules_engine/segment_terms_rule.rb +48 -0
  19. data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
  20. data/lib/new_relic/agent/sql_sampler.rb +39 -10
  21. data/lib/new_relic/agent/stats_engine/metric_stats.rb +1 -0
  22. data/lib/new_relic/agent/stats_engine/stats_hash.rb +7 -13
  23. data/lib/new_relic/agent/system_info.rb +96 -10
  24. data/lib/new_relic/agent/threading/agent_thread.rb +4 -1
  25. data/lib/new_relic/agent/threading/backtrace_node.rb +67 -57
  26. data/lib/new_relic/agent/threading/thread_profile.rb +30 -15
  27. data/lib/new_relic/agent/transaction.rb +11 -4
  28. data/lib/new_relic/environment_report.rb +21 -20
  29. data/lib/new_relic/version.rb +1 -1
  30. data/test/agent_helper.rb +12 -0
  31. data/test/fixtures/cross_agent_tests/README.md +1 -0
  32. data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_1core_1logical.txt +3 -0
  33. data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_1core_2logical.txt +14 -0
  34. data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_2core_2logical.txt +14 -0
  35. data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_4core_4logical.txt +28 -0
  36. data/test/fixtures/{proc_cpuinfo.txt → cross_agent_tests/proc_cpuinfo/2pack_12core_24logical.txt} +0 -0
  37. data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_20core_40logical.txt +999 -0
  38. data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_2core_2logical.txt +51 -0
  39. data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_2core_4logical.txt +28 -0
  40. data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_4core_4logical.txt +28 -0
  41. data/test/fixtures/cross_agent_tests/proc_cpuinfo/4pack_4core_4logical.txt +103 -0
  42. data/test/fixtures/cross_agent_tests/proc_cpuinfo/8pack_8core_8logical.txt +199 -0
  43. data/test/fixtures/cross_agent_tests/proc_cpuinfo/README.md +24 -0
  44. data/test/fixtures/cross_agent_tests/proc_cpuinfo/Xpack_Xcore_2logical.txt +43 -0
  45. data/test/fixtures/cross_agent_tests/transaction_segment_terms.json +101 -0
  46. data/test/multiverse/lib/multiverse/suite.rb +1 -1
  47. data/test/multiverse/suites/agent_only/agent_run_id_handling_test.rb +40 -0
  48. data/test/multiverse/suites/agent_only/labels_test.rb +9 -14
  49. data/test/multiverse/suites/agent_only/marshaling_test.rb +4 -6
  50. data/test/multiverse/suites/agent_only/rename_rule_test.rb +41 -4
  51. data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +11 -3
  52. data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +8 -8
  53. data/test/multiverse/suites/rack/example_app.rb +20 -0
  54. data/test/multiverse/suites/rack/http_response_code_test.rb +51 -0
  55. data/test/multiverse/suites/sidekiq/Envfile +13 -6
  56. data/test/multiverse/suites/sidekiq/sidekiq_server.rb +4 -3
  57. data/test/new_relic/agent/audit_logger_test.rb +27 -0
  58. data/test/new_relic/agent/error_collector_test.rb +26 -5
  59. data/test/new_relic/agent/hostname_test.rb +66 -14
  60. data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +8 -12
  61. data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +7 -45
  62. data/test/new_relic/agent/method_tracer_test.rb +52 -1
  63. data/test/new_relic/agent/new_relic_service_test.rb +76 -0
  64. data/test/new_relic/agent/request_sampler_test.rb +7 -0
  65. data/test/new_relic/agent/rules_engine_test.rb +87 -56
  66. data/test/new_relic/agent/sql_sampler_test.rb +50 -14
  67. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +2 -2
  68. data/test/new_relic/agent/stats_engine/samplers_test.rb +1 -1
  69. data/test/new_relic/agent/{stats_hash_test.rb → stats_engine/stats_hash_test.rb} +1 -38
  70. data/test/new_relic/agent/system_info_test.rb +45 -0
  71. data/test/new_relic/agent/threading/agent_thread_test.rb +30 -0
  72. data/test/new_relic/agent/threading/backtrace_node_test.rb +27 -44
  73. data/test/new_relic/agent/threading/thread_profile_test.rb +35 -14
  74. data/test/new_relic/agent/transaction_test.rb +13 -10
  75. data/test/new_relic/environment_report_test.rb +7 -6
  76. data/test/new_relic/fake_collector.rb +10 -6
  77. data/test/new_relic/multiverse_helpers.rb +4 -11
  78. data/test/new_relic/rack/agent_hooks_test.rb +1 -1
  79. data/test/performance/lib/performance/baseline_compare_reporter.rb +24 -7
  80. data/test/performance/lib/performance/result.rb +3 -1
  81. data/test/performance/lib/performance/runner.rb +10 -0
  82. data/test/performance/lib/performance/timer.rb +6 -10
  83. data/test/performance/script/runner +18 -1
  84. data/test/performance/suites/queue_time.rb +21 -0
  85. data/test/performance/suites/stats_hash.rb +34 -0
  86. data/test/performance/suites/thread_profiling.rb +26 -0
  87. metadata +25 -4
  88. metadata.gz.sig +0 -0
@@ -2,12 +2,19 @@ suite_condition("SideKiq requires MRI 1.9.3 or JRuby 1.6 in 1.9 mode") do
2
2
  RUBY_VERSION >= '1.9.3' || (RUBY_PLATFORM == 'java' && RUBY_VERSION >= '1.9')
3
3
  end
4
4
 
5
- gemfile <<-RB
6
- gem 'json'
7
- gem 'sidekiq', '~> 3.0.0'
8
- gem 'rack'
9
- gem 'newrelic_rpm', :require => false, :path => File.expand_path('../../../../')
10
- RB
5
+ # Sidekiq 3.x does not support MRI 1.9.x
6
+ if RUBY_VERSION >= '2.0.0' || (RUBY_PLATFORM == 'java')
7
+ gemfile <<-RB
8
+ gem 'json'
9
+ gem 'sidekiq', '~> 3.0.0'
10
+ gem 'rack'
11
+
12
+ # Work around for https://github.com/celluloid/celluloid/issues/457
13
+ gem 'celluloid', '0.15.2'
14
+
15
+ gem 'newrelic_rpm', :require => false, :path => File.expand_path('../../../../')
16
+ RB
17
+ end
11
18
 
12
19
  gemfile <<-RB
13
20
  gem 'json'
@@ -18,13 +18,14 @@ class SidekiqServer
18
18
  def run(file="test_worker.rb")
19
19
  @sidekiq.parse(["--require", File.join(File.dirname(__FILE__), file),
20
20
  "--queue", "#{queue_name},1"])
21
- Thread.new { @sidekiq.run }
21
+ @cli_thread = Thread.new { @sidekiq.run }
22
22
  end
23
23
 
24
24
  # If we just let the process go away, occasional timing issues cause the
25
25
  # Launcher actor in Sidekiq to throw a fuss and exit with a failed code.
26
26
  def stop
27
- puts "Trying to stop Sidekiq gracefully"
28
- @sidekiq.launcher.stop
27
+ puts "Trying to stop Sidekiq gracefully from #{$$}"
28
+ Process.kill("INT", $$)
29
+ @cli_thread.join
29
30
  end
30
31
  end
@@ -31,6 +31,11 @@ class AuditLoggerTest < Minitest::Test
31
31
  @logger.stubs(:ensure_log_path).returns(@fakelog)
32
32
  end
33
33
 
34
+ def setup_fake_logger_with_failure(error)
35
+ setup_fake_logger
36
+ @logger.stubs(:enabled?).raises(error)
37
+ end
38
+
34
39
  def assert_log_contains_string(str)
35
40
  log_body = read_log_body
36
41
  assert(log_body.include?(str), "Expected log to contain string '#{str}'\nLog body was: #{log_body}")
@@ -133,4 +138,26 @@ class AuditLoggerTest < Minitest::Test
133
138
  end
134
139
  assert_log_contains_string('cachey-mccaherson')
135
140
  end
141
+
142
+ TRAPPABLE_ERRORS = [
143
+ StandardError.new,
144
+ SystemStackError.new,
145
+ SystemCallError.new("Syscalls FTW")
146
+ ]
147
+
148
+ TRAPPABLE_ERRORS.each do |error|
149
+ define_method("test_traps_#{error.class}") do
150
+ setup_fake_logger_with_failure(error)
151
+ @logger.log_request(@uri, @dummy_data, @marshaller)
152
+ assert_empty read_log_body
153
+ end
154
+ end
155
+
156
+ def test_allows_other_exceptions_through
157
+ setup_fake_logger_with_failure(Exception.new)
158
+ assert_raises(Exception) do
159
+ @logger.log_request(@uri, @dummy_data, @marshaller)
160
+ end
161
+ end
162
+
136
163
  end
@@ -237,10 +237,30 @@ class NewRelic::Agent::ErrorCollectorTest < Minitest::Test
237
237
  end
238
238
 
239
239
  def test_increment_error_count_record_summary_and_txn_metric
240
- @error_collector.increment_error_count!(StandardError.new('Boo'),
241
- :metric => 'Controller/class/method')
240
+ in_web_transaction('Controller/class/method') do
241
+ @error_collector.increment_error_count!(StandardError.new('Boo'))
242
+ end
243
+
244
+ assert_metrics_recorded(['Errors/all',
245
+ 'Errors/allWeb',
246
+ 'Errors/Controller/class/method'])
247
+ end
248
+
249
+ def test_increment_error_count_record_summary_and_txn_metric
250
+ in_background_transaction('OtherTransaction/AnotherFramework/Job/perform') do
251
+ @error_collector.increment_error_count!(StandardError.new('Boo'))
252
+ end
253
+
254
+ assert_metrics_recorded(['Errors/all',
255
+ 'Errors/allOther',
256
+ 'Errors/OtherTransaction/AnotherFramework/Job/perform'])
257
+ end
258
+
259
+ def test_icrement_error_count_summary_outside_transaction
260
+ @error_collector.increment_error_count!(StandardError.new('Boo'))
242
261
 
243
- assert_metrics_recorded(['Errors/all', 'Errors/Controller/class/method'])
262
+ assert_metrics_recorded(['Errors/all'])
263
+ assert_metrics_not_recorded(['Errors/allWeb', 'Errors/allOther'])
244
264
  end
245
265
 
246
266
  def test_doesnt_increment_error_count_on_transaction_if_nameless
@@ -353,8 +373,9 @@ class NewRelic::Agent::ErrorCollectorTest < Minitest::Test
353
373
  end
354
374
  assert_metrics_recorded_exclusive(
355
375
  {
356
- 'Errors/all' => { :call_count => 1 },
357
- 'Errors/boo' => { :call_count => 1 }
376
+ 'Errors/all' => { :call_count => 1 },
377
+ 'Errors/boo' => { :call_count => 1 },
378
+ 'Errors/allOther' => { :call_count => 1 }
358
379
  },
359
380
  :filter => /^Errors\//
360
381
  )
@@ -8,30 +8,82 @@ require 'new_relic/agent/hostname'
8
8
  module NewRelic
9
9
  module Agent
10
10
  class HostnameTest < Minitest::Test
11
- def test_get_returns_socket_hostname
11
+ def setup
12
12
  Socket.stubs(:gethostname).returns('Rivendell')
13
+ end
14
+
15
+ def test_get_returns_socket_hostname
13
16
  assert_equal 'Rivendell', NewRelic::Agent::Hostname.get
14
17
  end
15
18
 
16
19
  def test_get_uses_dyno_name_if_dyno_env_set_and_dyno_names_enabled
17
- with_config(:use_heroku_dyno_names => true) do
18
- Socket.stubs(:gethostname).returns('Rivendell')
19
- ENV['DYNO'] = 'Imladris'
20
-
21
- expected = 'Imladris'
22
- assert_equal expected, NewRelic::Agent::Hostname.get
20
+ with_dyno_name('Imladris', :'heroku.use_dyno_names' => true) do
21
+ assert_equal 'Imladris', NewRelic::Agent::Hostname.get
23
22
  end
24
- ensure
25
- ENV.delete('DYNO')
26
23
  end
27
24
 
28
25
  def test_get_uses_socket_gethostname_if_dyno_env_set_and_dyno_names_disabled
29
- with_config(:use_heroku_dyno_names => false) do
30
- Socket.stubs(:gethostname).returns('Rivendell')
31
- ENV['DYNO'] = 'Imladris'
26
+ with_dyno_name('Imladris', :'heroku.use_dyno_names' => false) do
27
+ assert_equal 'Rivendell', NewRelic::Agent::Hostname.get
28
+ end
29
+ end
30
+
31
+ def test_shortens_to_prefix_if_using_dyno_names_and_matches
32
+ with_dyno_name('Imladris.1', :'heroku.use_dyno_names' => true,
33
+ :'heroku.dyno_name_prefixes_to_shorten' => ['Imladris']) do
34
+ assert_equal 'Imladris.*', NewRelic::Agent::Hostname.get
35
+ end
36
+ end
37
+
38
+ def test_does_not_shorten_if_not_using_dyno_names
39
+ with_dyno_name('Imladris', :'heroku.use_dyno_names' => false,
40
+ :'heroku.dyno_name_prefixes_to_shorten' => ['Rivendell']) do
41
+ Socket.stubs(:gethostname).returns('Rivendell.1')
42
+ assert_equal 'Rivendell.1', NewRelic::Agent::Hostname.get
43
+ end
44
+ end
45
+
46
+ def test_only_shortens_if_matches_prefix_and_dot
47
+ with_dyno_name('ImladrisImladrisFakeout.1',
48
+ :'heroku.use_dyno_names' => true,
49
+ :'heroku.dyno_name_prefixes_to_shorten' => ['Imladris']) do
50
+ assert_equal 'ImladrisImladrisFakeout.1', NewRelic::Agent::Hostname.get
51
+ end
52
+ end
53
+
54
+ def test_shortens_to_prefixes_from_string
55
+ with_dyno_name('Imladris.1', :'heroku.use_dyno_names' => true,
56
+ :'heroku.dyno_name_prefixes_to_shorten' => 'Imladris') do
57
+ assert_equal 'Imladris.*', NewRelic::Agent::Hostname.get
58
+ end
59
+ end
60
+
61
+ def test_shortens_to_prefixes_from_string_allows_csv
62
+ with_dyno_name('Imladris.1', :'heroku.use_dyno_names' => true,
63
+ :'heroku.dyno_name_prefixes_to_shorten' => 'Rivendell,Imladris') do
64
+ assert_equal 'Imladris.*', NewRelic::Agent::Hostname.get
65
+ end
66
+ end
67
+
68
+ def test_shortens_to_prefixes_with_empty_string
69
+ with_dyno_name('Imladris.1', :'heroku.use_dyno_names' => true,
70
+ :'heroku.dyno_name_prefixes_to_shorten' => '') do
71
+ assert_equal 'Imladris.1', NewRelic::Agent::Hostname.get
72
+ end
73
+ end
74
+
75
+ def test_shortens_to_prefixes_with_unsupported_object
76
+ with_dyno_name('Imladris.1', :'heroku.use_dyno_names' => true,
77
+ :'heroku.dyno_name_prefixes_to_shorten' => Object.new) do
78
+ expects_logging(:warn, includes('Object'))
79
+ assert_equal 'Imladris.1', NewRelic::Agent::Hostname.get
80
+ end
81
+ end
32
82
 
33
- expected = 'Rivendell'
34
- assert_equal expected, NewRelic::Agent::Hostname.get
83
+ def with_dyno_name(dyno_name, config_options)
84
+ with_config(config_options) do
85
+ ENV['DYNO'] = dyno_name
86
+ yield
35
87
  end
36
88
  ensure
37
89
  ENV.delete('DYNO')
@@ -206,19 +206,15 @@ class NewRelic::Agent::Instrumentation::ActionControllerSubscriberTest < Minites
206
206
  end
207
207
 
208
208
  def test_applies_txn_name_rules
209
- rule = NewRelic::Agent::RulesEngine::Rule.new('match_expression' => 'test',
210
- 'replacement' => 'taste')
211
- NewRelic::Agent.instance.transaction_rules << rule
212
- @subscriber.start('process_action.action_controller', :id, @entry_payload)
213
- @subscriber.finish('process_action.action_controller', :id, @exit_payload)
209
+ rule_specs = [{'match_expression' => 'test', 'replacement' => 'taste'}]
214
210
 
215
- assert NewRelic::Agent.instance.stats_engine \
216
- .lookup_stats('Controller/taste/index')
217
- assert_nil NewRelic::Agent.instance.stats_engine \
218
- .lookup_stats('Controller/test/index')
219
- ensure
220
- NewRelic::Agent.instance.instance_variable_set(:@transaction_rules,
221
- NewRelic::Agent::RulesEngine.new)
211
+ with_transaction_renaming_rules(rule_specs) do
212
+ @subscriber.start('process_action.action_controller', :id, @entry_payload)
213
+ @subscriber.finish('process_action.action_controller', :id, @exit_payload)
214
+ end
215
+
216
+ assert_metrics_recorded(['Controller/taste/index'])
217
+ assert_metrics_not_recorded(['Controller/test/index'])
222
218
  end
223
219
 
224
220
  def test_record_queue_time_metrics
@@ -11,32 +11,6 @@ class NewRelic::Agent::MethodTracer::TraceExecutionScopedTest < Minitest::Test
11
11
  NewRelic::Agent.agent.stats_engine.clear_stats
12
12
  end
13
13
 
14
- def test_get_stats_unscoped
15
- fake_engine = mocked_object('stat_engine')
16
- fake_engine.expects(:get_stats_no_scope).with('foob').returns('fakestats')
17
- assert_equal 'fakestats', get_stats_unscoped('foob')
18
- end
19
-
20
- def test_get_stats_scoped_scoped_only
21
- fake_engine = mocked_object('stat_engine')
22
- fake_engine.expects(:get_stats).with('foob', true, true).returns('fakestats')
23
- assert_equal 'fakestats', get_stats_scoped('foob', true)
24
- end
25
-
26
- def test_get_stats_scoped_no_scoped_only
27
- fake_engine = mocked_object('stat_engine')
28
- fake_engine.expects(:get_stats).with('foob', true, false).returns('fakestats')
29
- assert_equal 'fakestats', get_stats_scoped('foob', false)
30
- end
31
-
32
- def test_stat_engine
33
- assert_equal agent_instance.stats_engine, stat_engine
34
- end
35
-
36
- def test_agent_instance
37
- assert_equal NewRelic::Agent.instance, agent_instance
38
- end
39
-
40
14
  def test_metric_recording_outside_transaction
41
15
  trace_execution_scoped(['foo']) do
42
16
  # meh
@@ -120,7 +94,7 @@ class NewRelic::Agent::MethodTracer::TraceExecutionScopedTest < Minitest::Test
120
94
  )
121
95
  end
122
96
 
123
- def test_metric_recording_without_metric_option
97
+ def test_metric_recording_with_metric_option_false
124
98
  options = { :metric => false, :scoped_metric => false }
125
99
 
126
100
  in_transaction('outer') do
@@ -130,24 +104,12 @@ class NewRelic::Agent::MethodTracer::TraceExecutionScopedTest < Minitest::Test
130
104
  end
131
105
 
132
106
  expected_values = { :call_count => 1 }
133
- assert_metrics_recorded_exclusive(
134
- 'outer' => expected_values,
135
- 'bar' => expected_values
136
- )
137
- end
138
-
139
- def test_set_if_nil
140
- h = {}
141
- set_if_nil(h, :foo)
142
- assert h[:foo]
143
- h[:bar] = false
144
- set_if_nil(h, :bar)
145
- assert !h[:bar]
107
+ assert_metrics_recorded_exclusive('outer' => expected_values)
146
108
  end
147
109
 
148
110
  def test_log_errors_base
149
111
  ran = false
150
- log_errors("name") do
112
+ NewRelic::Agent::MethodTracerHelpers.log_errors("name") do
151
113
  ran = true
152
114
  end
153
115
  assert ran, "should run the contents of the block"
@@ -155,7 +117,7 @@ class NewRelic::Agent::MethodTracer::TraceExecutionScopedTest < Minitest::Test
155
117
 
156
118
  def test_log_errors_with_return
157
119
  ran = false
158
- return_val = log_errors('name') do
120
+ return_val = NewRelic::Agent::MethodTracerHelpers.log_errors('name') do
159
121
  ran = true
160
122
  'happy trees'
161
123
  end
@@ -169,7 +131,7 @@ class NewRelic::Agent::MethodTracer::TraceExecutionScopedTest < Minitest::Test
169
131
  includes("Caught exception in name."),
170
132
  instance_of(RuntimeError))
171
133
 
172
- log_errors("name") do
134
+ NewRelic::Agent::MethodTracerHelpers.log_errors("name") do
173
135
  raise "should not propagate out of block"
174
136
  end
175
137
  end
@@ -177,9 +139,9 @@ class NewRelic::Agent::MethodTracer::TraceExecutionScopedTest < Minitest::Test
177
139
  def test_trace_execution_scoped_header
178
140
  state = NewRelic::Agent::TransactionState.tl_get
179
141
  stack = state.traced_method_stack
180
- self.expects(:log_errors).with(:trace_execution_scoped_header).yields
142
+ NewRelic::Agent::MethodTracerHelpers.expects(:log_errors).with(:trace_execution_scoped_header).yields
181
143
  stack.expects(:push_frame).with(state, :method_tracer, 1.0)
182
- trace_execution_scoped_header(state, 1.0)
144
+ NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped_header(state, 1.0)
183
145
  end
184
146
 
185
147
  def test_trace_execution_scoped_calculates_exclusive_time
@@ -93,7 +93,7 @@ class NewRelic::Agent::MethodTracerTest < Minitest::Test
93
93
 
94
94
  def test_record_metrics_does_not_raise_outside_transaction
95
95
  state = NewRelic::Agent::TransactionState.tl_get
96
- NewRelic::Agent::MethodTracer::TraceExecutionScoped.record_metrics(state, 'a', ['b'], 12, 10, :metric => true)
96
+ NewRelic::Agent::MethodTracerHelpers.record_metrics(state, 'a', ['b'], 12, 10, :metric => true)
97
97
 
98
98
  expected = { :call_count => 1, :total_call_time => 12, :total_exclusive_time => 10 }
99
99
  assert_metrics_recorded('a' => expected, 'b' => expected)
@@ -378,6 +378,57 @@ class NewRelic::Agent::MethodTracerTest < Minitest::Test
378
378
  assert_equal ['YY'], @scope_listener.scopes
379
379
  end
380
380
 
381
+ def test_add_method_tracer_module_double_inclusion
382
+ mod = Module.new { def traced_method; end }
383
+ cls = Class.new { include mod }
384
+
385
+ mod.module_eval do
386
+ include NewRelic::Agent::MethodTracer
387
+ add_method_tracer :traced_method
388
+ end
389
+
390
+ cls.new.traced_method
391
+ end
392
+
393
+ # This test validates that including the MethodTracer module does not pollute
394
+ # the host class with any additional helper methods that are not part of the
395
+ # official public API.
396
+ def test_only_adds_methods_to_host_that_are_part_of_public_api
397
+ host_class = Class.new { include ::NewRelic::Agent::MethodTracer }
398
+ plain_class = Class.new
399
+
400
+ host_instance_methods = host_class.new.methods
401
+ plain_instance_methods = plain_class.new.methods
402
+
403
+ added_methods = host_instance_methods - plain_instance_methods
404
+
405
+ public_api_methods = [
406
+ 'trace_execution_unscoped',
407
+ 'trace_execution_scoped',
408
+ 'trace_method_execution', # deprecated
409
+ 'trace_method_execution_with_scope', # deprecated
410
+ 'trace_method_execution_no_scope', # deprecated
411
+ 'get_stats_scoped', # deprecated
412
+ 'get_stats_unscoped' # deprecated
413
+ ]
414
+
415
+ assert_equal(public_api_methods.sort, added_methods.map(&:to_s).sort)
416
+ end
417
+
418
+ def test_get_stats_unscoped
419
+ host_class = Class.new { include ::NewRelic::Agent::MethodTracer }
420
+ expected_stats = NewRelic::Agent.get_stats('foobar')
421
+ stats = host_class.new.get_stats_unscoped('foobar')
422
+ assert_same(expected_stats, stats)
423
+ end
424
+
425
+ def test_get_stats_scoped
426
+ host_class = Class.new { include ::NewRelic::Agent::MethodTracer }
427
+ expected_stats = NewRelic::Agent.get_stats('foobar', true)
428
+ stats = host_class.new.get_stats_scoped('foobar', false)
429
+ assert_same(expected_stats, stats)
430
+ end
431
+
381
432
  def trace_no_push_scope
382
433
  self.class.add_method_tracer :method_to_be_traced, 'X', :push_scope => false
383
434
  method_to_be_traced 1,2,3,true,nil
@@ -653,6 +653,82 @@ class NewRelicServiceTest < Minitest::Test
653
653
  refute @service.valid_to_marshal?({})
654
654
  end
655
655
 
656
+ def test_supportability_metrics_with_item_count
657
+ NewRelic::Agent.drop_buffered_data
658
+
659
+ payload = ['eggs', 'spam']
660
+ @http_handle.respond_to(:foobar, 'foobar')
661
+ @service.send(:invoke_remote, :foobar, payload, :item_count => 12)
662
+
663
+ expected_size_bytes = @service.marshaller.dump(payload).size
664
+ expected_values = {
665
+ :call_count => 1,
666
+ :total_call_time => expected_size_bytes,
667
+ :total_exclusive_time => 12
668
+ }
669
+
670
+ assert_metrics_recorded(
671
+ 'Supportability/invoke_remote' => { :call_count => 1 },
672
+ 'Supportability/invoke_remote/foobar' => { :call_count => 1 },
673
+ 'Supportability/invoke_remote_serialize' => { :call_count => 1 },
674
+ 'Supportability/invoke_remote_serialize/foobar' => { :call_count => 1},
675
+ 'Supportability/invoke_remote_size' => expected_values,
676
+ 'Supportability/invoke_remote_size/foobar' => expected_values
677
+ )
678
+ end
679
+
680
+ def test_supportability_metrics_without_item_count
681
+ NewRelic::Agent.drop_buffered_data
682
+
683
+ payload = ['eggs', 'spam']
684
+ @http_handle.respond_to(:foobar, 'foobar')
685
+ @service.send(:invoke_remote, :foobar, payload)
686
+
687
+ expected_size_bytes = @service.marshaller.dump(payload).size
688
+ expected_values = {
689
+ :call_count => 1,
690
+ :total_call_time => expected_size_bytes,
691
+ :total_exclusive_time => 0
692
+ }
693
+
694
+ assert_metrics_recorded(
695
+ 'Supportability/invoke_remote' => { :call_count => 1 },
696
+ 'Supportability/invoke_remote/foobar' => { :call_count => 1 },
697
+ 'Supportability/invoke_remote_serialize' => { :call_count => 1 },
698
+ 'Supportability/invoke_remote_serialize/foobar' => { :call_count => 1},
699
+ 'Supportability/invoke_remote_size' => expected_values,
700
+ 'Supportability/invoke_remote_size/foobar' => expected_values
701
+ )
702
+ end
703
+
704
+ def test_supportability_metrics_with_serialization_failure
705
+ NewRelic::Agent.drop_buffered_data
706
+
707
+ payload = ['eggs', 'spam']
708
+ @http_handle.respond_to(:foobar, 'foobar')
709
+ @service.marshaller.stubs(:dump).raises(StandardError.new)
710
+
711
+ assert_raises(NewRelic::Agent::SerializationError) do
712
+ @service.send(:invoke_remote, :foobar, payload)
713
+ end
714
+
715
+ expected_values = { :call_count => 1 }
716
+
717
+ assert_metrics_recorded(
718
+ 'Supportability/invoke_remote' => expected_values,
719
+ 'Supportability/invoke_remote/foobar' => expected_values,
720
+ 'Supportability/serialization_failure' => expected_values,
721
+ 'Supportability/serialization_failure/foobar' => expected_values
722
+ )
723
+
724
+ assert_metrics_not_recorded([
725
+ 'Supportability/invoke_remote_serialize',
726
+ 'Supportability/invoke_remote_serialize/foobar',
727
+ 'Supportability/invoke_remote_size',
728
+ 'Supportability/invoke_remote_size/foobar'
729
+ ])
730
+ end
731
+
656
732
  def build_stats_hash(items={})
657
733
  hash = NewRelic::Agent::StatsHash.new
658
734
  items.each do |key, value|