newrelic_rpm 3.12.1.298 → 3.13.0.299

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +37 -0
  3. data/GUIDELINES_FOR_CONTRIBUTING.md +1 -1
  4. data/LICENSE +4 -4
  5. data/README.md +3 -3
  6. data/lib/new_relic/agent/agent.rb +27 -0
  7. data/lib/new_relic/agent/commands/thread_profiler_session.rb +2 -0
  8. data/lib/new_relic/agent/configuration/default_source.rb +51 -1
  9. data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
  10. data/lib/new_relic/agent/database.rb +12 -2
  11. data/lib/new_relic/agent/database/obfuscator.rb +4 -3
  12. data/lib/new_relic/agent/datastores.rb +1 -1
  13. data/lib/new_relic/agent/datastores/redis.rb +131 -0
  14. data/lib/new_relic/agent/error_collector.rb +2 -2
  15. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +1 -0
  16. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -0
  17. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +2 -0
  18. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +2 -0
  19. data/lib/new_relic/agent/instrumentation/rake.rb +170 -0
  20. data/lib/new_relic/agent/instrumentation/redis.rb +71 -0
  21. data/lib/new_relic/agent/instrumentation/sinatra.rb +1 -0
  22. data/lib/new_relic/agent/new_relic_service.rb +4 -0
  23. data/lib/new_relic/agent/sql_sampler.rb +14 -13
  24. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +1 -0
  25. data/lib/new_relic/agent/transaction.rb +2 -0
  26. data/lib/new_relic/agent/transaction/attributes.rb +1 -1
  27. data/lib/new_relic/agent/transaction/trace.rb +2 -1
  28. data/lib/new_relic/agent/transaction/trace_node.rb +3 -2
  29. data/lib/new_relic/agent/transaction_sampler.rb +4 -15
  30. data/lib/new_relic/agent/transaction_state.rb +1 -0
  31. data/lib/new_relic/agent/vm/rubinius_vm.rb +27 -19
  32. data/lib/new_relic/language_support.rb +7 -0
  33. data/lib/new_relic/version.rb +2 -2
  34. data/lib/tasks/newrelic.rb +9 -0
  35. data/newrelic_rpm.gemspec +1 -1
  36. data/test/multiverse/README.md +1 -1
  37. data/test/multiverse/lib/multiverse/runner.rb +2 -2
  38. data/test/multiverse/suites/active_record/active_record_test.rb +6 -6
  39. data/test/multiverse/suites/agent_only/agent_attributes_test.rb +11 -0
  40. data/test/multiverse/suites/agent_only/script/warnings.rb +15 -0
  41. data/test/multiverse/suites/agent_only/start_up_test.rb +12 -4
  42. data/test/multiverse/suites/rake/Envfile +37 -0
  43. data/test/multiverse/suites/rake/Rakefile +54 -0
  44. data/test/multiverse/suites/rake/config/newrelic.yml +18 -0
  45. data/test/multiverse/suites/rake/multitask_test.rb +40 -0
  46. data/test/multiverse/suites/rake/rake_test.rb +209 -0
  47. data/test/multiverse/suites/rake/rake_test_helper.rb +66 -0
  48. data/test/multiverse/suites/rake/unsupported_rake_test.rb +19 -0
  49. data/test/multiverse/suites/redis/Envfile +14 -0
  50. data/test/multiverse/suites/redis/config/newrelic.yml +19 -0
  51. data/test/multiverse/suites/redis/redis_instrumentation_test.rb +212 -0
  52. data/test/multiverse/suites/redis/redis_unsupported_version_test.rb +20 -0
  53. data/test/multiverse/suites/resque/resque_marshalling_test.rb +9 -1
  54. data/test/new_relic/agent/agent_test.rb +78 -1
  55. data/test/new_relic/agent/configuration/high_security_source_test.rb +9 -0
  56. data/test/new_relic/agent/database/sql_obfuscation_test.rb +1 -3
  57. data/test/new_relic/agent/datastores/redis_test.rb +128 -0
  58. data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +1 -1
  59. data/test/new_relic/agent/sql_sampler_test.rb +64 -52
  60. data/test/new_relic/agent/transaction/trace_node_test.rb +1 -1
  61. data/test/new_relic/agent/transaction/trace_test.rb +1 -1
  62. data/test/new_relic/agent/transaction_sampler_test.rb +9 -11
  63. data/test/new_relic/agent/vm/rubinius_vm_test.rb +1 -1
  64. data/test/new_relic/fake_collector.rb +18 -1
  65. data/test/new_relic/multiverse_helpers.rb +6 -0
  66. data/test/performance/suites/redis.rb +45 -0
  67. data/ui/views/newrelic/_sql_row.rhtml +1 -1
  68. data/ui/views/newrelic/explain_sql.rhtml +1 -1
  69. metadata +21 -5
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ # Because some envs have Rails, we might not have loaded in the absence of
6
+ # initializers running, so kick-start agent to get instrumentation loaded.
7
+ NewRelic::Agent.manual_start(:sync_startup => false)
8
+
9
+ module RakeTestHelper
10
+ def after_setup
11
+ ENV['NEWRELIC_DISABLE_HARVEST_THREAD'] = 'false'
12
+ ENV['NEW_RELIC_PORT'] = $collector.port.to_s
13
+ end
14
+
15
+ def after_teardown
16
+ unless passed?
17
+ puts @output
18
+ end
19
+ end
20
+
21
+ def run_rake(commands = "", allow_failure = false)
22
+ full_command = "bundle exec rake #{commands} 2>&1"
23
+ @output = `#{full_command}`
24
+
25
+ if !allow_failure
26
+ assert $?.success?, "Failed during '#{full_command}'"
27
+ end
28
+ end
29
+
30
+ def with_tasks_traced(*tasks)
31
+ with_environment("NEW_RELIC_RAKE_TASKS" => tasks.join(",")) do
32
+ yield
33
+ end
34
+ end
35
+
36
+ def without_attributes(*tasks)
37
+ with_environment("NEW_RELIC_ATTRIBUTES_EXCLUDE" => "*") do
38
+ yield
39
+ end
40
+ end
41
+
42
+ def assert_metric_names_posted(*expected_names)
43
+ expected_names.each do |expected_name|
44
+ assert_includes all_metric_names_posted, expected_name
45
+ end
46
+ end
47
+
48
+ def refute_metric_names_posted(*expected_names)
49
+ expected_names.each do |expected_name|
50
+ refute_includes all_metric_names_posted, expected_name
51
+ end
52
+ end
53
+
54
+ def refute_any_rake_metrics
55
+ all_metric_names_posted.each do |metric_name|
56
+ refute_match /^OtherTransaction.*/, metric_name
57
+ refute_match /^Rake.*/, metric_name
58
+ end
59
+ end
60
+
61
+ def all_metric_names_posted
62
+ $collector.calls_for("metric_data").map do |metric_post|
63
+ metric_post.metric_names
64
+ end.flatten
65
+ end
66
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require File.expand_path(File.join(__FILE__, '..', 'rake_test_helper'))
6
+
7
+ if !::NewRelic::Agent::Instrumentation::RakeInstrumentation.should_install?
8
+ class UnsupportedRakeTest < Minitest::Test
9
+ include MultiverseHelpers
10
+ include RakeTestHelper
11
+
12
+ setup_and_teardown_agent
13
+
14
+ def test_we_hear_nothing
15
+ run_rake
16
+ refute_any_rake_metrics
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ gemfile <<-RB
2
+ gem 'rack'
3
+ gem 'redis', '~>3.2.1'
4
+ RB
5
+
6
+ gemfile <<-RB
7
+ gem 'rack'
8
+ gem 'redis', '3.0.0' # oldest supported version
9
+ RB
10
+
11
+ gemfile <<-RB
12
+ gem 'rack'
13
+ gem 'redis', '2.2.2' # newest unsupported version
14
+ RB
@@ -0,0 +1,19 @@
1
+ ---
2
+ development:
3
+ error_collector:
4
+ enabled: true
5
+ apdex_t: 0.5
6
+ ssl: false
7
+ monitor_mode: true
8
+ license_key: bootstrap_newrelic_admin_license_key_000
9
+ developer_mode: false
10
+ app_name: test
11
+ host: 127.0.0.1
12
+ port: <%= $collector && $collector.port %>
13
+ api_host: 127.0.0.1
14
+ transaction_tracer:
15
+ record_sql: obfuscated
16
+ enabled: true
17
+ stack_trace_threshold: 0.5
18
+ transaction_threshold: 1.0
19
+ capture_params: false
@@ -0,0 +1,212 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require 'redis'
6
+
7
+ if NewRelic::Agent::Datastores::Redis.is_supported_version?
8
+ class NewRelic::Agent::Instrumentation::RedisInstrumentationTest < Minitest::Test
9
+ include MultiverseHelpers
10
+ setup_and_teardown_agent
11
+
12
+ def after_setup
13
+ super
14
+ @redis = Redis.new
15
+
16
+ # Creating a new client doesn't actually establish a connection, so make
17
+ # sure we do that by issuing a dummy get command, and then drop metrics
18
+ # generated by the connect
19
+ @redis.get('bogus')
20
+ NewRelic::Agent.drop_buffered_data
21
+ end
22
+
23
+ def after_teardown
24
+ @redis.flushall
25
+ end
26
+
27
+ def test_records_metrics_for_connect
28
+ redis = Redis.new
29
+ redis.get("foo")
30
+
31
+ expected = {
32
+ "Datastore/operation/Redis/connect" => { :call_count => 1 },
33
+ "Datastore/operation/Redis/get" => { :call_count => 1 },
34
+ "Datastore/Redis/allOther" => { :call_count => 2 },
35
+ "Datastore/Redis/all" => { :call_count => 2 },
36
+ "Datastore/allOther" => { :call_count => 2 },
37
+ "Datastore/all" => { :call_count => 2 }
38
+ }
39
+
40
+ assert_metrics_recorded_exclusive(expected, :ignore_filter => /Supportability/)
41
+ end
42
+
43
+ def test_records_connect_tt_node_within_call_that_triggered_it
44
+ in_transaction do
45
+ redis = Redis.new
46
+ redis.get("foo")
47
+ end
48
+
49
+ tt = last_transaction_trace
50
+
51
+ get_node = tt.root_node.called_nodes[0].called_nodes[0]
52
+ assert_equal('Datastore/operation/Redis/get', get_node.metric_name)
53
+
54
+ connect_node = get_node.called_nodes[0]
55
+ assert_equal('Datastore/operation/Redis/connect', connect_node.metric_name)
56
+ end
57
+
58
+ def test_records_metrics_for_set
59
+ @redis.set 'time', 'walk'
60
+
61
+ expected = {
62
+ "Datastore/operation/Redis/set" => { :call_count => 1 },
63
+ "Datastore/Redis/allOther" => { :call_count => 1 },
64
+ "Datastore/Redis/all"=> { :call_count => 1 },
65
+ "Datastore/allOther"=> { :call_count => 1 },
66
+ "Datastore/all"=> { :call_count => 1 }
67
+ }
68
+ assert_metrics_recorded(expected)
69
+ end
70
+
71
+ def test_records_metrics_for_get_in_web_transaction
72
+ in_web_transaction do
73
+ @redis.set 'prodigal', 'sorcerer'
74
+ end
75
+
76
+ expected = {
77
+ "Datastore/operation/Redis/set" => { :call_count => 1 },
78
+ "Datastore/Redis/allWeb" => { :call_count => 1 },
79
+ "Datastore/Redis/all"=> { :call_count => 1 },
80
+ "Datastore/allWeb"=> { :call_count => 1 },
81
+ "Datastore/all"=> { :call_count => 1 }
82
+ }
83
+ assert_metrics_recorded(expected)
84
+ end
85
+
86
+ def test_records_metrics_for_get
87
+ @redis.get 'mox sapphire'
88
+
89
+ expected = {
90
+ "Datastore/operation/Redis/get" => { :call_count => 1 },
91
+ "Datastore/Redis/allOther" => { :call_count => 1 },
92
+ "Datastore/Redis/all"=> { :call_count => 1 },
93
+ "Datastore/allOther"=> { :call_count => 1 },
94
+ "Datastore/all"=> { :call_count => 1 }
95
+ }
96
+ assert_metrics_recorded(expected)
97
+ end
98
+
99
+ def test_records_tt_node_for_get
100
+ in_transaction do
101
+ @redis.get 'mox sapphire'
102
+ end
103
+
104
+ tt = last_transaction_trace
105
+ get_node = tt.root_node.called_nodes[0].called_nodes[0]
106
+ assert_equal('Datastore/operation/Redis/get', get_node.metric_name)
107
+ end
108
+
109
+ def test_does_not_record_statement_on_individual_command_node_by_default
110
+ in_transaction do
111
+ @redis.get 'mox sapphire'
112
+ end
113
+
114
+ tt = last_transaction_trace
115
+ get_node = tt.root_node.called_nodes[0].called_nodes[0]
116
+
117
+ assert_equal('Datastore/operation/Redis/get', get_node.metric_name)
118
+ refute get_node[:statement]
119
+ end
120
+
121
+ def test_records_metrics_for_set_in_web_transaction
122
+ in_web_transaction do
123
+ @redis.get 'timetwister'
124
+ end
125
+
126
+ expected = {
127
+ "Datastore/operation/Redis/get" => { :call_count => 1 },
128
+ "Datastore/Redis/allWeb" => { :call_count => 1 },
129
+ "Datastore/Redis/all"=> { :call_count => 1 },
130
+ "Datastore/allWeb"=> { :call_count => 1 },
131
+ "Datastore/all"=> { :call_count => 1 }
132
+ }
133
+ assert_metrics_recorded(expected)
134
+ end
135
+
136
+ def test_records_metrics_for_pipelined_commands
137
+ @redis.pipelined do
138
+ @redis.get 'great log'
139
+ @redis.get 'late log'
140
+ end
141
+
142
+ expected = {
143
+ "Datastore/operation/Redis/pipeline" => { :call_count => 1 },
144
+ "Datastore/Redis/allOther" => { :call_count => 1 },
145
+ "Datastore/Redis/all" => { :call_count => 1 },
146
+ "Datastore/allOther" => { :call_count => 1 },
147
+ "Datastore/all" => { :call_count => 1 }
148
+ }
149
+ assert_metrics_recorded_exclusive(expected, :ignore_filter => /Supportability/)
150
+ end
151
+
152
+ def test_records_commands_without_args_in_pipelined_block_by_default
153
+ in_transaction do
154
+ @redis.pipelined do
155
+ @redis.set 'late log', 'goof'
156
+ @redis.get 'great log'
157
+ end
158
+ end
159
+
160
+ tt = last_transaction_trace
161
+ pipeline_node = tt.root_node.called_nodes[0].called_nodes[0]
162
+
163
+ assert_equal "set ?\nget ?", pipeline_node[:statement]
164
+ end
165
+
166
+ def test_records_metrics_for_multi_blocks
167
+ @redis.multi do
168
+ @redis.get 'darkpact'
169
+ @redis.get 'chaos orb'
170
+ end
171
+
172
+ expected = {
173
+ "Datastore/operation/Redis/multi" => { :call_count => 1 },
174
+ "Datastore/Redis/allOther" => { :call_count => 1 },
175
+ "Datastore/Redis/all" => { :call_count => 1 },
176
+ "Datastore/allOther" => { :call_count => 1 },
177
+ "Datastore/all" => { :call_count => 1 }
178
+ }
179
+ assert_metrics_recorded_exclusive(expected, :ignore_filter => /Supportability/)
180
+ end
181
+
182
+ def test_records_commands_without_args_in_tt_node_for_multi_blocks
183
+ in_transaction do
184
+ @redis.multi do
185
+ @redis.set 'darkpact', 'sorcery'
186
+ @redis.get 'chaos orb'
187
+ end
188
+ end
189
+
190
+ tt = last_transaction_trace
191
+ pipeline_node = tt.root_node.called_nodes[0].called_nodes[0]
192
+
193
+ assert_equal("multi\nset ?\nget ?\nexec", pipeline_node[:statement])
194
+ end
195
+
196
+ def test_records_commands_with_args_in_tt_node_for_multi_blocks
197
+ with_config(:'transaction_tracer.record_redis_arguments' => true) do
198
+ in_transaction do
199
+ @redis.multi do
200
+ @redis.set 'darkpact', 'sorcery'
201
+ @redis.get 'chaos orb'
202
+ end
203
+ end
204
+ end
205
+
206
+ tt = last_transaction_trace
207
+ pipeline_node = tt.root_node.called_nodes[0].called_nodes[0]
208
+
209
+ assert_equal("multi\nset \"darkpact\" \"sorcery\"\nget \"chaos orb\"\nexec", pipeline_node[:statement])
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require 'redis'
6
+ require 'newrelic_rpm'
7
+
8
+ if !NewRelic::Agent::Datastores::Redis.is_supported_version?
9
+ class NewRelic::Agent::Instrumentation::RedisUnsupportedVersionTest < Minitest::Test
10
+ def setup
11
+ @redis = Redis.new
12
+ end
13
+
14
+ def test_no_metrics_recorded_for_get
15
+ @redis.get('hello')
16
+
17
+ assert_no_metrics_match(/redis/i)
18
+ end
19
+ end
20
+ end
@@ -13,6 +13,12 @@ class ResqueMarshallingTest < Minitest::Test
13
13
 
14
14
  setup_and_teardown_agent
15
15
 
16
+ def before_teardown
17
+ puts
18
+ p $collector.agent_data.map { |post| [post.class, post.action] }
19
+ super
20
+ end
21
+
16
22
  class DummyJob
17
23
  extend Resque::Plugins::NewRelicInstrumentation
18
24
  end
@@ -41,6 +47,8 @@ class ResqueMarshallingTest < Minitest::Test
41
47
  DummyJob.around_perform_with_monitoring do
42
48
  yield
43
49
  end
50
+
51
+ run_harvest
44
52
  exit
45
53
  end
46
54
  end
@@ -50,4 +58,4 @@ class ResqueMarshallingTest < Minitest::Test
50
58
  end
51
59
  end
52
60
 
53
- end
61
+ end
@@ -30,7 +30,11 @@ module NewRelic
30
30
 
31
31
  def test_after_fork_reporting_to_channel
32
32
  @agent.stubs(:connected?).returns(true)
33
- @agent.after_fork(:report_to_channel => 123)
33
+
34
+ with_config(:monitor_mode => true) do
35
+ @agent.after_fork(:report_to_channel => 123)
36
+ end
37
+
34
38
  assert(@agent.service.kind_of?(NewRelic::Agent::PipeService),
35
39
  'Agent should use PipeService when directed to report to pipe channel')
36
40
  NewRelic::Agent::PipeService.any_instance.expects(:shutdown).never
@@ -411,6 +415,79 @@ module NewRelic
411
415
  end
412
416
  end
413
417
 
418
+ def test_wait_on_connect
419
+ error = nil
420
+ connected = false
421
+ thread = Thread.new do
422
+ begin
423
+ @agent.wait_on_connect(2)
424
+ connected = true
425
+ rescue => e
426
+ error = e
427
+ end
428
+ end
429
+
430
+ until @agent.waited_on_connect? do
431
+ # hold on there....
432
+ end
433
+
434
+ @agent.stubs(:connected?).returns(true)
435
+ @agent.signal_connected
436
+ thread.join
437
+
438
+ refute error, error
439
+ assert connected
440
+ end
441
+
442
+ def test_wait_raises_if_not_connected_once_signaled
443
+ error = nil
444
+ thread = Thread.new do
445
+ begin
446
+ @agent.wait_on_connect(2)
447
+ rescue => e
448
+ error = e
449
+ end
450
+ end
451
+
452
+ until @agent.waited_on_connect? do
453
+ # hold on there....
454
+ end
455
+
456
+ @agent.stubs(:connected?).returns(false)
457
+ @agent.signal_connected
458
+ thread.join
459
+
460
+ assert error, error
461
+ assert_kind_of NewRelic::Agent::Agent::Connect::WaitOnConnectTimeout, error
462
+ end
463
+
464
+ def test_wait_raises_if_not_signaled
465
+ error = nil
466
+ thread = Thread.new do
467
+ begin
468
+ @agent.wait_on_connect(0.01)
469
+ rescue => e
470
+ error = e
471
+ end
472
+ end
473
+
474
+ until @agent.waited_on_connect? do
475
+ # hold on there....
476
+ end
477
+
478
+ @agent.stubs(:connected?).returns(false)
479
+ thread.join
480
+
481
+ assert error, error
482
+ assert_kind_of NewRelic::Agent::Agent::Connect::WaitOnConnectTimeout, error
483
+ end
484
+
485
+ def test_wait_when_already_connected
486
+ @agent.stubs(:connected?).returns(true)
487
+ @agent.wait_on_connect(2)
488
+ refute @agent.waited_on_connect?
489
+ end
490
+
414
491
  def test_defer_start_if_resque_dispatcher_and_channel_manager_isnt_started_and_forkable
415
492
  NewRelic::LanguageSupport.stubs(:can_fork?).returns(true)
416
493
  NewRelic::Agent::PipeChannelManager.listener.stubs(:started?).returns(false)