newrelic_rpm 3.14.0.305 → 3.14.1.311

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +55 -3
  3. data/lib/new_relic/agent/agent.rb +1 -0
  4. data/lib/new_relic/agent/configuration/default_source.rb +25 -2
  5. data/lib/new_relic/agent/error_collector.rb +2 -1
  6. data/lib/new_relic/agent/error_event_aggregator.rb +10 -7
  7. data/lib/new_relic/agent/hostname.rb +1 -1
  8. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +82 -4
  9. data/lib/new_relic/agent/instrumentation/middleware_tracing.rb +5 -4
  10. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +24 -4
  11. data/lib/new_relic/agent/instrumentation/rack.rb +80 -29
  12. data/lib/new_relic/agent/pipe_service.rb +4 -0
  13. data/lib/new_relic/agent/transaction.rb +5 -0
  14. data/lib/new_relic/version.rb +1 -1
  15. data/test/multiverse/suites/agent_only/agent_attributes_test.rb +15 -0
  16. data/test/multiverse/suites/agent_only/error_events_test.rb +15 -1
  17. data/test/multiverse/suites/delayed_job/Envfile +10 -0
  18. data/test/multiverse/suites/delayed_job/before_suite.rb +10 -0
  19. data/test/multiverse/suites/delayed_job/delayed_job_instrumentation_test.rb +106 -0
  20. data/test/multiverse/suites/mongo/mongo2_instrumentation_test.rb +45 -0
  21. data/test/multiverse/suites/rack/Envfile +10 -0
  22. data/test/multiverse/suites/rack/before_suite.rb +12 -0
  23. data/test/multiverse/suites/rack/http_response_code_test.rb +2 -2
  24. data/test/multiverse/suites/rack/puma_rack_builder_test.rb +81 -0
  25. data/test/multiverse/suites/rack/rack_auto_instrumentation_test.rb +12 -3
  26. data/test/multiverse/suites/rack/rack_cascade_test.rb +31 -31
  27. data/test/multiverse/suites/rack/rack_env_mutation_test.rb +2 -2
  28. data/test/multiverse/suites/rack/rack_unsupported_version_test.rb +1 -1
  29. data/test/multiverse/suites/rack/response_content_type_test.rb +2 -2
  30. data/test/multiverse/suites/rack/url_map_test.rb +45 -11
  31. data/test/new_relic/agent/agent/connect_test.rb +1 -1
  32. data/test/new_relic/agent/agent_logger_test.rb +2 -0
  33. data/test/new_relic/agent/agent_test.rb +1 -0
  34. data/test/new_relic/agent/audit_logger_test.rb +4 -0
  35. data/test/new_relic/agent/error_collector_test.rb +34 -10
  36. data/test/new_relic/agent/error_event_aggregator_test.rb +12 -1
  37. data/test/new_relic/agent/hostname_test.rb +5 -0
  38. data/test/new_relic/agent/instrumentation/delayed_job_instrumentation_test.rb +23 -0
  39. data/test/new_relic/agent/pipe_service_test.rb +7 -0
  40. data/test/new_relic/marshalling_test_cases.rb +42 -0
  41. metadata +6 -2
@@ -49,6 +49,10 @@ module NewRelic
49
49
  write_to_pipe(:error_data, errors) if errors
50
50
  end
51
51
 
52
+ def error_event_data(events)
53
+ write_to_pipe(:error_event_data, events) if events
54
+ end
55
+
52
56
  def sql_trace_data(sql)
53
57
  write_to_pipe(:sql_trace_data, sql) if sql
54
58
  end
@@ -546,6 +546,11 @@ module NewRelic
546
546
  if @request_attributes
547
547
  @request_attributes.assign_agent_attributes self
548
548
  end
549
+
550
+ display_host = Agent.config[:'process_host.display_name']
551
+ unless display_host == NewRelic::Agent::Hostname.get
552
+ add_agent_attribute(:'host.displayName', display_host, default_destinations)
553
+ end
549
554
  end
550
555
 
551
556
  def assign_intrinsics(state)
@@ -12,7 +12,7 @@ module NewRelic
12
12
 
13
13
  MAJOR = 3
14
14
  MINOR = 14
15
- TINY = 0
15
+ TINY = 1
16
16
 
17
17
  begin
18
18
  require File.join(File.dirname(__FILE__), 'build')
@@ -208,6 +208,21 @@ class AgentAttributesTest < Minitest::Test
208
208
  refute_event_has_attribute('httpResponseCode')
209
209
  end
210
210
 
211
+ def test_host_display_name_included_when_enabled_and_set
212
+ config = {:'process_host.display_name' => 'Fancy Host Name',
213
+ :'transaction_events.attributes.include' => 'host.displayName',}
214
+ run_transaction(config)
215
+
216
+ assert_event_has_agent_attribute('host.displayName', 'Fancy Host Name')
217
+ end
218
+
219
+ def test_host_display_name_excluded_when_enabled_but_not_set
220
+ config = {:'transaction_events.attributes.include' => 'host.displayName',}
221
+ run_transaction(config)
222
+
223
+ refute_event_has_attribute('host.displayName')
224
+ end
225
+
211
226
  def run_transaction(config = {}, txn_options = {})
212
227
  default_config = {
213
228
  :'transaction_tracer.transaction_threshold' => -10,
@@ -5,7 +5,9 @@
5
5
  class ErrorEventsTest < Minitest::Test
6
6
  include MultiverseHelpers
7
7
 
8
- setup_and_teardown_agent
8
+ setup_and_teardown_agent do
9
+ freeze_time
10
+ end
9
11
 
10
12
  def test_error_events_are_submitted
11
13
  txn = generate_errors
@@ -64,6 +66,18 @@ class ErrorEventsTest < Minitest::Test
64
66
  assert_equal(0, $collector.calls_for(:error_event_data).size)
65
67
  end
66
68
 
69
+ def test_error_events_created_outside_of_transaction
70
+ NewRelic::Agent.notice_error RuntimeError.new "No Txn"
71
+ NewRelic::Agent.agent.send(:harvest_and_send_error_event_data)
72
+
73
+ intrinsics, _, _ = last_error_event
74
+
75
+ assert_equal "TransactionError", intrinsics["type"]
76
+ assert_in_delta Time.now.to_f, intrinsics["timestamp"], 0.001
77
+ assert_equal "RuntimeError", intrinsics["error.class"]
78
+ assert_equal "No Txn", intrinsics["error.message"]
79
+ end
80
+
67
81
  def generate_errors num_errors = 1
68
82
  in_transaction :transaction_name => "Controller/blogs/index" do |t|
69
83
  num_errors.times { t.notice_error RuntimeError.new "Big Controller" }
@@ -22,6 +22,16 @@ if RUBY_VERSION >= '1.9.3'
22
22
  RB
23
23
  end
24
24
 
25
+ if RUBY_VERSION >= '1.9.3'
26
+ gemfile <<-RB
27
+ gem 'delayed_job', '~> 4.1.0'
28
+ gem 'delayed_job_active_record', '~> 4.1.0'
29
+ gem 'activerecord', '~> 3.2.19'
30
+ gem 'i18n', '~> 0.6.11'
31
+ #{boilerplate_gems}
32
+ RB
33
+ end
34
+
25
35
  # delayed_job_active_record (and older baked into delayed_job) support
26
36
  if RUBY_VERSION >= '1.9.3'
27
37
  dj4_with_active_record = <<-DJ
@@ -29,5 +29,15 @@ if Delayed::Worker.backend.to_s == "Delayed::Backend::ActiveRecord::Job"
29
29
  @connection = $db_connection
30
30
  end
31
31
 
32
+ class CreatePelicans < ActiveRecord::Migration
33
+ @connection = $db_connection
34
+ def self.up
35
+ create_table :pelicans do |t|
36
+ t.string :name
37
+ end
38
+ end
39
+ end
40
+
32
41
  CreateDelayedJobs.up
42
+ CreatePelicans.up
33
43
  end
@@ -0,0 +1,106 @@
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
+ if defined?(Delayed::Backend::ActiveRecord) && Delayed::Worker.respond_to?(:delay_jobs)
6
+ class DelayedJobInstrumentationTest < Minitest::Test
7
+ include MultiverseHelpers
8
+
9
+ class QuackJob
10
+ def initialize(index)
11
+ @index = index
12
+ end
13
+
14
+ def display_name
15
+ "Quack Job: #{@index}"
16
+ end
17
+
18
+ def perform
19
+ "Performing Quack Job #{@index} .."
20
+ end
21
+ end
22
+
23
+ class Pelican < ActiveRecord::Base
24
+ self.table_name = :pelicans
25
+
26
+ def quack
27
+ "quack..."
28
+ end
29
+
30
+ def quack_later
31
+ "...quack"
32
+ end
33
+
34
+ handle_asynchronously :quack_later
35
+ end
36
+
37
+ setup_and_teardown_agent
38
+
39
+ def after_setup
40
+ Delayed::Worker.delay_jobs = false
41
+ # We set Delayed::Worker.delay_jobs = false to run jobs inline for testing purposes, but
42
+ # we unfortunately hook the initialize method on Delayed::Worker
43
+ # to install our instrumentation. Delayed::Workers are not initialized when running
44
+ # tests inline so we have to manually instantiate one to install our instrumentation.
45
+ # We also need to take care to only install the instrumentation once.
46
+ unless Delayed::Job.instance_methods.any? { |m| m == :invoke_job_without_new_relic || m == "invoke_job_without_new_relic" }
47
+ Delayed::Worker.new
48
+ end
49
+ end
50
+
51
+ def after_teardown
52
+ Delayed::Worker.delay_jobs = true
53
+ end
54
+
55
+ # Delayed Job doesn't expose a version number, so we have to resort to checking Gem.loaded_specs.
56
+ # Additionally, earlier versions of Delayed Job do not call invoke_job when running jobs inline.
57
+ # We can only test methods using delay and handle_asynchronously on versions that run jobs via
58
+ # the invoke_job method.
59
+ def self.dj_invokes_job_inline?
60
+ Gem.loaded_specs["delayed_job"].version >= Gem::Version.new("3.0.0")
61
+ end
62
+
63
+ if dj_invokes_job_inline?
64
+ def test_delay_method
65
+ p = Pelican.create(:name => "Charlie")
66
+ p.delay.quack
67
+
68
+ assert_metrics_recorded [
69
+ 'OtherTransaction/all',
70
+ 'OtherTransaction/DelayedJob/all',
71
+ 'OtherTransaction/DelayedJob/DelayedJobInstrumentationTest::Pelican#quack'
72
+ ]
73
+ end
74
+
75
+ def test_handle_asynchronously
76
+ p = Pelican.create(:name => "Charlieee")
77
+ p.quack_later
78
+
79
+ assert_metrics_recorded [
80
+ 'OtherTransaction/all',
81
+ 'OtherTransaction/DelayedJob/all',
82
+ 'OtherTransaction/DelayedJob/DelayedJobInstrumentationTest::Pelican#quack_later_without_delay'
83
+ ]
84
+ end
85
+ end
86
+
87
+ def test_enqueue_standalone_job
88
+ job = QuackJob.new rand(100)
89
+ invoke_job(job)
90
+
91
+ assert_metrics_recorded [
92
+ 'OtherTransaction/all',
93
+ 'OtherTransaction/DelayedJob/all',
94
+ 'OtherTransaction/DelayedJob/DelayedJobInstrumentationTest::QuackJob'
95
+ ]
96
+ end
97
+
98
+ # Note we use this method instead of Delayed::Job.enqueue because Delayed Job 2.1.4 does
99
+ # not call invoke_job when running jobs inline it instead calls perform directly. This
100
+ # allows us to test the stand alone job case on all supported versions of Delayed Job.
101
+ def invoke_job(job)
102
+ job = Delayed::Job.new(:payload_object => job)
103
+ job.invoke_job
104
+ end
105
+ end
106
+ end
@@ -179,6 +179,51 @@ if NewRelic::Agent::Datastores::Mongo.is_supported_version? &&
179
179
  assert_metrics_recorded(expected)
180
180
  end
181
181
 
182
+ def test_batched_queries
183
+ 25.times do |i|
184
+ @collection.insert_one :name => "test-#{i}", :active => true
185
+ end
186
+ NewRelic::Agent.drop_buffered_data
187
+
188
+ @collection.find(:active => true).batch_size(10).to_a
189
+
190
+ expected = {
191
+ "Datastore/statement/MongoDB/#{@collection_name}/find" => {:call_count=>1},
192
+ "Datastore/statement/MongoDB/#{@collection_name}/getMore" => {:call_count=>2},
193
+ "Datastore/operation/MongoDB/find" => {:call_count=>1},
194
+ "Datastore/operation/MongoDB/getMore" => {:call_count=>2},
195
+ "Datastore/MongoDB/allWeb" => {:call_count=>3},
196
+ "Datastore/MongoDB/all" => {:call_count=>3},
197
+ "Datastore/allWeb" => { :call_count=>3},
198
+ "Datastore/all" => {:call_count=>3}
199
+ }
200
+ assert_metrics_recorded_exclusive expected
201
+ end
202
+
203
+ def test_batched_queries_have_node_per_query
204
+ 25.times do |i|
205
+ @collection.insert_one :name => "test-#{i}", :active => true
206
+ end
207
+ NewRelic::Agent.drop_buffered_data
208
+ in_transaction "webby" do
209
+ @collection.find(:active => true).batch_size(10).to_a
210
+ end
211
+
212
+ expected = [
213
+ "Datastore/statement/MongoDB/#{@collection_name}/find",
214
+ "Datastore/statement/MongoDB/#{@collection_name}/getMore",
215
+ "Datastore/statement/MongoDB/#{@collection_name}/getMore"
216
+ ]
217
+
218
+ trace = last_transaction_trace
219
+ actual = []
220
+ trace.each_node do |n|
221
+ actual << n.metric_name if n.metric_name.start_with? "Datastore/statement/MongoDB"
222
+ end
223
+
224
+ assert_equal expected, actual
225
+ end
226
+
182
227
  def test_drop_collection
183
228
  @collection.drop
184
229
 
@@ -1,3 +1,13 @@
1
+ gemfile <<-RB
2
+ gem 'puma', '~>2.12.3'
3
+ RB
4
+
5
+ gemfile <<-RB
6
+ gem 'puma', '~>2.12.3'
7
+ gem 'rack', '~>1.6.0'
8
+ gem 'rack-test'
9
+ RB
10
+
1
11
  gemfile <<-RB
2
12
  gem 'rack', '~>1.6.0'
3
13
  gem 'rack-test'
@@ -0,0 +1,12 @@
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
+ # this is a bit ugly, but Puma::Rack::Bundler isn't required by puma unless it's
6
+ # running as a webserver. This terrible hack is to install our instrumentation
7
+ # for these tests since our requests aren't served by an actual Puma webserver.
8
+ if NewRelic::Agent::Instrumentation::RackHelpers.puma_rack_version_supported?
9
+ require 'puma/rack/builder' unless defined? Puma::Rack::Builder
10
+ require 'puma/rack/urlmap' unless defined? Puma::Rack::URLMap
11
+ DependencyDetection.detect!
12
+ end
@@ -2,13 +2,13 @@
2
2
  # This file is distributed under New Relic's license terms.
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
+ if NewRelic::Agent::Instrumentation::RackHelpers.rack_version_supported?
6
+
5
7
  require File.join(File.dirname(__FILE__), 'example_app')
6
8
  require 'new_relic/rack/browser_monitoring'
7
9
  require 'new_relic/rack/agent_hooks'
8
10
  require 'new_relic/rack/error_collector'
9
11
 
10
- if NewRelic::Agent::Instrumentation::RackHelpers.rack_version_supported?
11
-
12
12
  class HttpResponseCodeTest < Minitest::Test
13
13
  include MultiverseHelpers
14
14
 
@@ -0,0 +1,81 @@
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
+ if NewRelic::Agent::Instrumentation::RackHelpers.puma_rack_version_supported?
6
+
7
+ class PumaRackBuilderTest < Minitest::Test
8
+ include MultiverseHelpers
9
+
10
+ class ExampleApp
11
+ def call env
12
+ [200, {'Content-Type' => 'text/html'}, ['Hello!']]
13
+ end
14
+ end
15
+
16
+ class MiddlewareOne
17
+ def initialize app
18
+ @app = app
19
+ end
20
+
21
+ def call env
22
+ env['MiddlewareOne'] = true
23
+ @app.call env
24
+ end
25
+ end
26
+
27
+ class MiddlewareTwo
28
+ def initialize app
29
+ @app = app
30
+ end
31
+
32
+ def call env
33
+ env['MiddlewareTwo'] = true
34
+ @app.call env
35
+ end
36
+ end
37
+
38
+ def setup
39
+ @app = build_app
40
+ @env = {}
41
+ end
42
+
43
+ def teardown
44
+ NewRelic::Agent.drop_buffered_data
45
+ end
46
+
47
+ def build_app
48
+ Puma::Rack::Builder.app do
49
+ use MiddlewareOne
50
+ use MiddlewareTwo
51
+ run ExampleApp.new
52
+ end
53
+ end
54
+
55
+
56
+ def test_middlewares_are_visited_with_puma_rack
57
+ @app.call @env
58
+ assert @env['MiddlewareOne'], 'Expected MiddlewareOne to be present and true in env'
59
+ assert @env['MiddlewareTwo'], 'Expected MiddlewareTwo to be present and true in env'
60
+ end
61
+
62
+ def test_puma_rack_builder_is_auto_instrumented
63
+ @app.call @env
64
+
65
+ assert_metrics_recorded_exclusive [
66
+ "Apdex",
67
+ "ApdexAll",
68
+ "HttpDispatcher",
69
+ "Middleware/all",
70
+ "Apdex/Rack/PumaRackBuilderTest::ExampleApp/call",
71
+ "Controller/Rack/PumaRackBuilderTest::ExampleApp/call",
72
+ "Middleware/Rack/PumaRackBuilderTest::MiddlewareOne/call",
73
+ "Middleware/Rack/PumaRackBuilderTest::MiddlewareTwo/call",
74
+ "Nested/Controller/Rack/PumaRackBuilderTest::ExampleApp/call",
75
+ ["Middleware/Rack/PumaRackBuilderTest::MiddlewareOne/call", "Controller/Rack/PumaRackBuilderTest::ExampleApp/call"],
76
+ ["Middleware/Rack/PumaRackBuilderTest::MiddlewareTwo/call", "Controller/Rack/PumaRackBuilderTest::ExampleApp/call"],
77
+ ["Nested/Controller/Rack/PumaRackBuilderTest::ExampleApp/call", "Controller/Rack/PumaRackBuilderTest::ExampleApp/call"]
78
+ ]
79
+ end
80
+ end
81
+ end
@@ -2,13 +2,13 @@
2
2
  # This file is distributed under New Relic's license terms.
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
+ if NewRelic::Agent::Instrumentation::RackHelpers.version_supported? && defined? Rack
6
+
5
7
  require File.join(File.dirname(__FILE__), 'example_app')
6
8
  require 'new_relic/rack/browser_monitoring'
7
9
  require 'new_relic/rack/agent_hooks'
8
10
  require 'new_relic/rack/error_collector'
9
11
 
10
- if NewRelic::Agent::Instrumentation::RackHelpers.rack_version_supported?
11
-
12
12
  class RackAutoInstrumentationTest < Minitest::Test
13
13
  include MultiverseHelpers
14
14
 
@@ -16,8 +16,16 @@ class RackAutoInstrumentationTest < Minitest::Test
16
16
 
17
17
  include Rack::Test::Methods
18
18
 
19
+ def builder_class
20
+ if defined? Puma::Rack::Builder
21
+ Puma::Rack::Builder
22
+ else
23
+ Rack::Builder
24
+ end
25
+ end
26
+
19
27
  def app
20
- Rack::Builder.app do
28
+ builder_class.app do
21
29
  use MiddlewareOne
22
30
  use MiddlewareTwo, 'the correct tag' do |headers|
23
31
  headers['MiddlewareTwoBlockTag'] = 'the block tag'
@@ -113,6 +121,7 @@ class RackAutoInstrumentationTest < Minitest::Test
113
121
 
114
122
  def test_middleware_that_returns_early_records_middleware_rollup_metric
115
123
  get '/?return-early=true'
124
+
116
125
  assert_metrics_recorded_exclusive([
117
126
  "Apdex",
118
127
  "ApdexAll",