newrelic_rpm 3.13.0.299 → 3.13.1.300

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -0
  3. data/CHANGELOG +36 -1
  4. data/lib/new_relic/agent/agent.rb +0 -1
  5. data/lib/new_relic/agent/database.rb +1 -1
  6. data/lib/new_relic/agent/datastores/mongo.rb +8 -7
  7. data/lib/new_relic/agent/datastores/mongo/event_formatter.rb +49 -0
  8. data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +2 -2
  9. data/lib/new_relic/agent/error_collector.rb +12 -51
  10. data/lib/new_relic/agent/error_trace_aggregator.rb +89 -0
  11. data/lib/new_relic/agent/instrumentation/active_record.rb +1 -1
  12. data/lib/new_relic/agent/instrumentation/active_record_4.rb +1 -1
  13. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +26 -1
  14. data/lib/new_relic/agent/instrumentation/mongo.rb +16 -1
  15. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +74 -0
  16. data/lib/new_relic/agent/supported_versions.rb +15 -1
  17. data/lib/new_relic/agent/system_info.rb +5 -0
  18. data/lib/new_relic/recipes/capistrano3.rb +1 -1
  19. data/lib/new_relic/recipes/capistrano_legacy.rb +1 -1
  20. data/lib/new_relic/version.rb +1 -1
  21. data/newrelic_rpm.gemspec +1 -1
  22. data/test/environments/lib/environments/runner.rb +1 -0
  23. data/test/fixtures/cross_agent_tests/proc_cpuinfo/README.md +4 -0
  24. data/test/fixtures/cross_agent_tests/proc_cpuinfo/malformed_file.txt +3 -0
  25. data/test/multiverse/lib/multiverse/suite.rb +4 -4
  26. data/test/multiverse/suites/active_record/active_record_test.rb +67 -26
  27. data/test/multiverse/suites/agent_only/start_up_test.rb +17 -3
  28. data/test/multiverse/suites/config_file_loading/Envfile +1 -1
  29. data/test/multiverse/suites/mongo/Envfile +3 -1
  30. data/test/multiverse/suites/mongo/mongo2_instrumentation_test.rb +344 -0
  31. data/test/multiverse/suites/mongo/mongo_connection_test.rb +2 -1
  32. data/test/multiverse/suites/mongo/mongo_instrumentation_test.rb +2 -1
  33. data/test/multiverse/suites/mongo/mongo_unsupported_version_test.rb +1 -1
  34. data/test/multiverse/suites/rails/rails3_app/app_rails3_plus.rb +7 -0
  35. data/test/multiverse/suites/sidekiq/Envfile +1 -1
  36. data/test/new_relic/agent/agent/start_test.rb +0 -5
  37. data/test/new_relic/agent/database_test.rb +8 -1
  38. data/test/new_relic/agent/datastores/mongo/event_formatter_test.rb +154 -0
  39. data/test/new_relic/agent/error_collector_test.rb +0 -13
  40. data/test/new_relic/agent/error_trace_aggregator_test.rb +30 -0
  41. data/test/new_relic/agent/instrumentation/mongodb_command_subscriber_test.rb +72 -0
  42. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +24 -22
  43. data/test/new_relic/agent/system_info_test.rb +9 -1
  44. data/test/new_relic/rack/error_collector_test.rb +1 -2
  45. metadata +10 -2
@@ -7,7 +7,8 @@ require 'newrelic_rpm'
7
7
  require 'new_relic/agent/datastores/mongo'
8
8
  require 'securerandom'
9
9
 
10
- if NewRelic::Agent::Datastores::Mongo.is_supported_version?
10
+ if NewRelic::Agent::Datastores::Mongo.is_supported_version? &&
11
+ !NewRelic::Agent::Datastores::Mongo.is_monitoring_enabled?
11
12
  require File.join(File.dirname(__FILE__), '..', '..', '..', 'helpers', 'mongo_metric_builder')
12
13
  require File.join(File.dirname(__FILE__), 'helpers', 'mongo_server')
13
14
  require File.join(File.dirname(__FILE__), 'helpers', 'mongo_replica_set')
@@ -7,7 +7,8 @@ require 'newrelic_rpm'
7
7
  require 'new_relic/agent/datastores/mongo'
8
8
  require 'securerandom'
9
9
 
10
- if NewRelic::Agent::Datastores::Mongo.is_supported_version?
10
+ if NewRelic::Agent::Datastores::Mongo.is_supported_version? &&
11
+ !NewRelic::Agent::Datastores::Mongo.is_monitoring_enabled?
11
12
  require File.join(File.dirname(__FILE__), '..', '..', '..', 'helpers', 'mongo_metric_builder')
12
13
  require File.join(File.dirname(__FILE__), 'helpers', 'mongo_server')
13
14
  require File.join(File.dirname(__FILE__), 'helpers', 'mongo_replica_set')
@@ -63,7 +63,7 @@ if !NewRelic::Agent::Datastores::Mongo.is_supported_version?
63
63
  end
64
64
  end
65
65
 
66
- if NewRelic::Agent::Datastores::Mongo.is_version2?
66
+ if NewRelic::Agent::Datastores::Mongo.is_unsupported_2x?
67
67
  include Mongo2xUnsupported
68
68
  else
69
69
  include Mongo1xUnsupported
@@ -47,6 +47,13 @@ if !defined?(MyApp)
47
47
  end
48
48
 
49
49
  if defined?(Sinatra)
50
+ module Sinatra
51
+ class Application < Base
52
+ # Override to not accidentally start the app in at_exit handler
53
+ set :run, Proc.new { false }
54
+ end
55
+ end
56
+
50
57
  class SinatraTestApp < Sinatra::Base
51
58
  get '/' do
52
59
  raise "Intentional error" if params["raise"]
@@ -6,7 +6,7 @@ end
6
6
  if RUBY_VERSION >= '2.0.0' || (RUBY_PLATFORM == 'java')
7
7
  gemfile <<-RB
8
8
  gem 'json'
9
- gem 'sidekiq', '~> 3.3.4'
9
+ gem 'sidekiq', '~> 3.4.2'
10
10
  gem 'rack'
11
11
 
12
12
  gem 'newrelic_rpm', :require => false, :path => File.expand_path('../../../../')
@@ -89,7 +89,6 @@ class NewRelic::Agent::Agent::StartTest < Minitest::Test
89
89
  private :at_exit
90
90
 
91
91
  def test_install_exit_handler_positive
92
- NewRelic::LanguageSupport.expects(:using_engine?).with('rbx').returns(false)
93
92
  NewRelic::LanguageSupport.expects(:using_engine?).with('jruby').returns(false)
94
93
  self.expects(:sinatra_classic_app?).returns(false)
95
94
  # we are overriding at_exit above, to immediately return, so we can
@@ -110,15 +109,11 @@ class NewRelic::Agent::Agent::StartTest < Minitest::Test
110
109
 
111
110
  def test_install_exit_handler_weird_ruby
112
111
  with_config(:send_data_one_exit => true) do
113
- NewRelic::LanguageSupport.expects(:using_engine?).with('rbx').returns(false)
114
112
  NewRelic::LanguageSupport.expects(:using_engine?).with('jruby').returns(false)
115
113
  self.expects(:sinatra_classic_app?).returns(true)
116
114
  install_exit_handler
117
- NewRelic::LanguageSupport.expects(:using_engine?).with('rbx').returns(false)
118
115
  NewRelic::LanguageSupport.expects(:using_engine?).with('jruby').returns(true)
119
116
  install_exit_handler
120
- NewRelic::LanguageSupport.expects(:using_engine?).with('rbx').returns(true)
121
- install_exit_handler
122
117
  end
123
118
  end
124
119
 
@@ -370,7 +370,7 @@ class NewRelic::Agent::DatabaseTest < Minitest::Test
370
370
  assert_equal('a' * (NewRelic::Agent::Database::MAX_QUERY_LENGTH - 3) + '...', truncated_query)
371
371
  end
372
372
 
373
- INVALID_UTF8_STRING = (''.respond_to?(:force_encoding) ? "\x80".force_encoding('UTF-8') : "\x80")
373
+ INVALID_UTF8_STRING = (''.respond_to?(:force_encoding) ? "select \x80".force_encoding('UTF-8') : "select \x80")
374
374
 
375
375
  def test_capture_query_mis_encoded
376
376
  query = INVALID_UTF8_STRING
@@ -382,6 +382,13 @@ class NewRelic::Agent::DatabaseTest < Minitest::Test
382
382
  assert_equal(expected_query, captured)
383
383
  end
384
384
 
385
+ def test_parse_operation_from_query_mis_encoded
386
+ query = INVALID_UTF8_STRING
387
+ expected = "select"
388
+ parsed = NewRelic::Agent::Database.parse_operation_from_query(query)
389
+ assert_equal(expected, parsed)
390
+ end
391
+
385
392
  sql_parsing_tests = load_cross_agent_test('sql_parsing')
386
393
  sql_parsing_tests.each_with_index do |test_case, i|
387
394
  define_method("test_sql_parsing_#{i}") do
@@ -0,0 +1,154 @@
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.dirname(__FILE__),'..','..','..','..','test_helper'))
6
+ require 'new_relic/agent/datastores/mongo/event_formatter'
7
+
8
+ module NewRelic
9
+ module Agent
10
+ module Datastores
11
+ module Mongo
12
+ class EventFormatterTest < Minitest::Test
13
+
14
+ DATABASE = 'multiverse'.freeze
15
+
16
+ FIND_COMMAND = {
17
+ "find" => "tribbles",
18
+ "filter" => { "_id" => { "$gt" => 1 }, "name" => "joe" },
19
+ "sort" => { "_id" => 1 },
20
+ "limit" => 2,
21
+ "skip" => 2,
22
+ "comment" => "test",
23
+ "hint" => { "_id" => 1 },
24
+ "max" => { "_id" => 6 },
25
+ "maxScan" => 5000,
26
+ "maxTimeMS" => 6000,
27
+ "min" => { "_id" => 0 },
28
+ "readPreference" => { "mode" => "secondaryPreferred" },
29
+ "returnKey" => false,
30
+ "showRecordId" => false,
31
+ "snapshot" => false
32
+ }.freeze
33
+
34
+ INSERT_COMMAND = {
35
+ "insert" => "tribbles",
36
+ "ordered" => true,
37
+ "documents" => [{ :name => "test" }]
38
+ }.freeze
39
+
40
+ UPDATE_COMMAND = {
41
+ "update" => "tribbles",
42
+ "ordered" => true,
43
+ "updates" => [
44
+ {
45
+ :q => { :_id => { "$gt" => 1 }},
46
+ :u => { "$inc" => { :x => 1 }},
47
+ :multi => false,
48
+ :upsert => false
49
+ }
50
+ ]
51
+ }.freeze
52
+
53
+ DELETE_COMMAND = {
54
+ "delete" => "tribbles",
55
+ "ordered" => true,
56
+ "deletes" => [{ :q => { :_id => { "$gt" => 1 }}, :limit => 1 }]
57
+ }.freeze
58
+
59
+ if RUBY_VERSION > "1.9.3"
60
+
61
+ def test_doesnt_modify_incoming_statement
62
+ formatted = EventFormatter.format('find', DATABASE, FIND_COMMAND)
63
+ refute_same FIND_COMMAND, formatted
64
+ end
65
+
66
+ def test_can_disable_statement_capturing_queries
67
+ with_config(:'mongo.capture_queries' => false) do
68
+ formatted = EventFormatter.format('find', DATABASE, FIND_COMMAND)
69
+ assert_nil formatted
70
+ end
71
+ end
72
+
73
+ def test_event_formatter_obfuscates_by_default
74
+ expected = {
75
+ :operation => :find,
76
+ :database => DATABASE,
77
+ :collection => "tribbles",
78
+ "find" => "tribbles",
79
+ "filter" => { "_id" => { "$gt" => "?" }, "name" => "?" },
80
+ "sort" => { "_id" => 1 },
81
+ "limit" => 2,
82
+ "skip" => 2,
83
+ "comment" => "test",
84
+ "hint" => { "_id" => 1 },
85
+ "max" => { "_id" => 6 },
86
+ "maxScan" => 5000,
87
+ "maxTimeMS" => 6000,
88
+ "min" => { "_id" => 0 },
89
+ "readPreference" => { "mode" => "secondaryPreferred" },
90
+ "returnKey" => false,
91
+ "showRecordId" => false,
92
+ "snapshot" => false
93
+ }
94
+
95
+ formatted = EventFormatter.format(:find, DATABASE, FIND_COMMAND)
96
+ assert_equal expected, formatted
97
+ end
98
+
99
+ def test_event_formatter_raw_selectors
100
+ with_config(:'mongo.obfuscate_queries' => false) do
101
+ formatted = EventFormatter.format(:find, DATABASE, FIND_COMMAND)
102
+ expected = FIND_COMMAND.merge(
103
+ :operation => :find,
104
+ :database => DATABASE,
105
+ :collection => 'tribbles'
106
+ )
107
+ assert_equal expected, formatted
108
+ end
109
+ end
110
+
111
+ def test_event_formatter_blacklists_inserts
112
+ expected = {
113
+ :operation => :insert,
114
+ :database => DATABASE,
115
+ :collection => "tribbles",
116
+ "insert" => "tribbles",
117
+ "ordered" => true
118
+ }
119
+
120
+ formatted = EventFormatter.format(:insert, DATABASE, INSERT_COMMAND)
121
+ assert_equal expected, formatted
122
+ end
123
+
124
+ def test_event_formatter_blacklists_updates
125
+ expected = {
126
+ :operation => :update,
127
+ :database => DATABASE,
128
+ :collection => "tribbles",
129
+ "update" => "tribbles",
130
+ "ordered" => true
131
+ }
132
+
133
+ formatted = EventFormatter.format(:update, DATABASE, UPDATE_COMMAND)
134
+ assert_equal expected, formatted
135
+ end
136
+
137
+ def test_event_formatter_blacklists_deletes
138
+ expected = {
139
+ :operation => :delete,
140
+ :database => DATABASE,
141
+ :collection => "tribbles",
142
+ "delete" => "tribbles",
143
+ "ordered" => true
144
+ }
145
+
146
+ formatted = EventFormatter.format(:delete, DATABASE, DELETE_COMMAND)
147
+ assert_equal expected, formatted
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -471,19 +471,6 @@ class NewRelic::Agent::ErrorCollectorTest < Minitest::Test
471
471
  assert_equal('STACK STACK STACK', @error_collector.extract_stack_trace(exception))
472
472
  end
473
473
 
474
- def test_over_queue_limit_negative
475
- refute @error_collector.over_queue_limit?(nil)
476
- end
477
-
478
- def test_over_queue_limit_positive
479
- expects_logging(:warn, includes('The error reporting queue has reached 20'))
480
- 21.times do
481
- @error_collector.notice_error("", {})
482
- end
483
-
484
- assert @error_collector.over_queue_limit?('hooray')
485
- end
486
-
487
474
  def test_skip_notice_error_is_true_if_the_error_collector_is_disabled
488
475
  error = StandardError.new
489
476
  with_config(:'error_collector.enabled' => false) do
@@ -0,0 +1,30 @@
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.dirname(__FILE__),'..','..','test_helper'))
6
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','data_container_tests'))
7
+
8
+ module NewRelic
9
+ module Agent
10
+ class ErrorTraceAggregatorTest < Minitest::Test
11
+ def setup
12
+ @aggregator = ErrorTraceAggregator.new(20)
13
+ end
14
+
15
+ def test_over_queue_limit_negative
16
+ refute @aggregator.over_queue_limit?(nil)
17
+ end
18
+
19
+ def test_over_queue_limit_positive
20
+ expects_logging(:warn, includes('The error reporting queue has reached 20'))
21
+ 21.times do
22
+ error = stub(:message => "", :is_internal => false)
23
+ @aggregator.add_to_error_queue(error)
24
+ end
25
+
26
+ assert @aggregator.over_queue_limit?('hooray')
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,72 @@
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.dirname(__FILE__),'..','..','..','test_helper'))
6
+ require 'new_relic/agent/instrumentation/mongodb_command_subscriber'
7
+
8
+ class NewRelic::Agent::Instrumentation::MongodbCommandSubscriberTest < Minitest::Test
9
+
10
+ if RUBY_VERSION > "1.9.3"
11
+ def setup
12
+ @started_event = mock('started event')
13
+ @started_event.stubs(:operation_id).returns(1)
14
+ @started_event.stubs(:command_name).returns('find')
15
+ @started_event.stubs(:database_name).returns('mongodb-test')
16
+ @started_event.stubs(:command).returns({ 'find' => 'users', 'filter' => { 'name' => 'test' }})
17
+
18
+ @succeeded_event = mock('succeeded event')
19
+ @succeeded_event.stubs(:operation_id).returns(1)
20
+ @succeeded_event.stubs(:duration).returns(2)
21
+
22
+ @subscriber = NewRelic::Agent::Instrumentation::MongodbCommandSubscriber.new
23
+
24
+ @stats_engine = NewRelic::Agent.instance.stats_engine
25
+ @stats_engine.clear_stats
26
+ end
27
+
28
+ def test_records_metrics_for_simple_find
29
+ simulate_query
30
+
31
+ metric_name = 'Datastore/statement/MongoDB/users/find'
32
+ assert_metrics_recorded(
33
+ metric_name => { :call_count => 1, :total_call_time => 2.0 }
34
+ )
35
+ end
36
+
37
+ def test_records_scoped_metrics
38
+ in_transaction('test_txn') { simulate_query }
39
+
40
+ metric_name = 'Datastore/statement/MongoDB/users/find'
41
+ assert_metrics_recorded(
42
+ [ metric_name, 'test_txn' ] => { :call_count => 1, :total_call_time => 2 }
43
+ )
44
+ end
45
+
46
+ def test_records_nothing_if_tracing_disabled
47
+ NewRelic::Agent.disable_all_tracing { simulate_query }
48
+ metric_name = 'Datastore/statement/MongoDB/users/find'
49
+ assert_metrics_not_recorded([ metric_name ])
50
+ end
51
+
52
+ def test_records_rollup_metrics
53
+ in_web_transaction { simulate_query }
54
+
55
+ assert_metrics_recorded(
56
+ 'Datastore/operation/MongoDB/find' => { :call_count => 1, :total_call_time => 2 },
57
+ 'Datastore/allWeb' => { :call_count => 1, :total_call_time => 2 },
58
+ 'Datastore/all' => { :call_count => 1, :total_call_time => 2 }
59
+ )
60
+ end
61
+
62
+ def test_should_not_raise_due_to_an_exception_during_instrumentation_callback
63
+ @subscriber.stubs(:metrics).raises(StandardError)
64
+ simulate_query
65
+ end
66
+
67
+ def simulate_query
68
+ @subscriber.started(@started_event)
69
+ @subscriber.succeeded(@succeeded_event)
70
+ end
71
+ end
72
+ end
@@ -161,32 +161,34 @@ class NewRelic::Agent::MetricStatsTest < Minitest::Test
161
161
  ])
162
162
  end
163
163
 
164
- def test_record_scoped_and_unscoped_metrics_is_thread_safe
165
- threads = []
166
- nthreads = 25
167
- iterations = 100
168
-
169
- nthreads.times do |tid|
170
- threads << Thread.new do
171
- iterations.times do
172
- in_transaction('txn') do
173
- @engine.tl_record_scoped_and_unscoped_metrics('m1', ['m3'], 1)
174
- @engine.tl_record_scoped_and_unscoped_metrics('m2', ['m4'], 1)
164
+ unless NewRelic::LanguageSupport.rubinius? # Routine segfaults with rbx, see RUBY-1507
165
+ def test_record_scoped_and_unscoped_metrics_is_thread_safe
166
+ threads = []
167
+ nthreads = 25
168
+ iterations = 100
169
+
170
+ nthreads.times do |tid|
171
+ threads << Thread.new do
172
+ iterations.times do
173
+ in_transaction('txn') do
174
+ @engine.tl_record_scoped_and_unscoped_metrics('m1', ['m3'], 1)
175
+ @engine.tl_record_scoped_and_unscoped_metrics('m2', ['m4'], 1)
176
+ end
175
177
  end
176
178
  end
177
179
  end
180
+ threads.each { |t| t.join }
181
+
182
+ expected = { :call_count => nthreads * iterations }
183
+ assert_metrics_recorded(
184
+ 'm1' => expected,
185
+ 'm2' => expected,
186
+ ['m1', 'txn'] => expected,
187
+ ['m2', 'txn'] => expected,
188
+ 'm3' => expected,
189
+ 'm4' => expected
190
+ )
178
191
  end
179
- threads.each { |t| t.join }
180
-
181
- expected = { :call_count => nthreads * iterations }
182
- assert_metrics_recorded(
183
- 'm1' => expected,
184
- 'm2' => expected,
185
- ['m1', 'txn'] => expected,
186
- ['m2', 'txn'] => expected,
187
- 'm3' => expected,
188
- 'm4' => expected
189
- )
190
192
  end
191
193
 
192
194
  def test_record_scoped_and_unscoped_metrics_records_unscoped_if_not_in_txn
@@ -31,8 +31,16 @@ class NewRelic::Agent::SystemInfoTest < Minitest::Test
31
31
  assert_equal(num_physical_cores , info[:num_physical_cores ])
32
32
  assert_equal(num_logical_processors, info[:num_logical_processors])
33
33
  end
34
+ elsif File.basename(file) =~ /malformed/
35
+ define_method("test_#{File.basename(file)}") do
36
+ cpuinfo = File.read(file)
37
+ info = @sysinfo.parse_cpuinfo(cpuinfo)
38
+ assert_equal(nil, info[:num_physical_package])
39
+ assert_equal(nil, info[:num_physical_cores])
40
+ assert_equal(nil, info[:num_logical_processors])
41
+ end
34
42
  else
35
- fail "Bad filename: cross_agent_tests/proc_cpuinfo/#{file}"
43
+ fail "Bad filename: #{file}"
36
44
  end
37
45
  end
38
46