newrelic_rpm 3.6.7.159 → 3.6.8.164

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/CHANGELOG +14 -0
  2. data/lib/new_relic/agent/agent.rb +38 -35
  3. data/lib/new_relic/agent/agent_logger.rb +6 -47
  4. data/lib/new_relic/agent/beacon_configuration.rb +10 -4
  5. data/lib/new_relic/agent/browser_monitoring.rb +39 -33
  6. data/lib/new_relic/agent/commands/agent_command.rb +4 -4
  7. data/lib/new_relic/agent/commands/agent_command_router.rb +72 -10
  8. data/lib/new_relic/agent/commands/thread_profiler_session.rb +110 -0
  9. data/lib/new_relic/agent/commands/xray_session.rb +55 -0
  10. data/lib/new_relic/agent/commands/xray_session_collection.rb +158 -0
  11. data/lib/new_relic/agent/configuration/default_source.rb +61 -24
  12. data/lib/new_relic/agent/configuration/mask_defaults.rb +2 -2
  13. data/lib/new_relic/agent/configuration/server_source.rb +1 -1
  14. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +2 -0
  15. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +4 -10
  16. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +10 -11
  17. data/lib/new_relic/agent/memory_logger.rb +52 -0
  18. data/lib/new_relic/agent/new_relic_service.rb +4 -0
  19. data/lib/new_relic/agent/request_sampler.rb +32 -13
  20. data/lib/new_relic/agent/samplers/cpu_sampler.rb +6 -3
  21. data/lib/new_relic/agent/threading/agent_thread.rb +2 -1
  22. data/lib/new_relic/agent/threading/backtrace_node.rb +80 -27
  23. data/lib/new_relic/agent/threading/backtrace_service.rb +264 -0
  24. data/lib/new_relic/agent/threading/thread_profile.rb +79 -118
  25. data/lib/new_relic/agent/transaction/developer_mode_sample_buffer.rb +56 -0
  26. data/lib/new_relic/agent/transaction/force_persist_sample_buffer.rb +25 -0
  27. data/lib/new_relic/agent/transaction/slowest_sample_buffer.rb +25 -0
  28. data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +86 -0
  29. data/lib/new_relic/agent/transaction/xray_sample_buffer.rb +64 -0
  30. data/lib/new_relic/agent/transaction.rb +25 -4
  31. data/lib/new_relic/agent/transaction_sample_builder.rb +6 -10
  32. data/lib/new_relic/agent/transaction_sampler.rb +47 -202
  33. data/lib/new_relic/agent/worker_loop.rb +47 -39
  34. data/lib/new_relic/agent.rb +1 -1
  35. data/lib/new_relic/build.rb +2 -2
  36. data/lib/new_relic/coerce.rb +8 -0
  37. data/lib/new_relic/control/instance_methods.rb +1 -0
  38. data/lib/new_relic/rack/browser_monitoring.rb +15 -1
  39. data/lib/new_relic/rack/developer_mode.rb +1 -1
  40. data/lib/new_relic/transaction_sample.rb +20 -5
  41. data/lib/new_relic/version.rb +1 -1
  42. data/newrelic.yml +4 -6
  43. data/newrelic_rpm.gemspec +1 -1
  44. data/test/agent_helper.rb +11 -0
  45. data/test/environments/lib/environments/runner.rb +5 -1
  46. data/test/environments/rails21/Gemfile +2 -2
  47. data/test/environments/rails22/Gemfile +2 -2
  48. data/test/environments/rails23/Gemfile +2 -2
  49. data/test/environments/rails31/Gemfile +2 -2
  50. data/test/environments/rails32/Gemfile +2 -2
  51. data/test/multiverse/suites/agent_only/marshaling_test.rb +1 -1
  52. data/test/multiverse/suites/agent_only/testing_app.rb +6 -0
  53. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +5 -5
  54. data/test/multiverse/suites/agent_only/xray_sessions_test.rb +163 -0
  55. data/test/multiverse/suites/rails/request_statistics_test.rb +2 -2
  56. data/test/multiverse/suites/rails/view_instrumentation_test.rb +20 -21
  57. data/test/new_relic/agent/agent/connect_test.rb +0 -10
  58. data/test/new_relic/agent/agent_test.rb +27 -44
  59. data/test/new_relic/agent/browser_monitoring_test.rb +0 -52
  60. data/test/new_relic/agent/commands/agent_command_router_test.rb +150 -12
  61. data/test/new_relic/agent/commands/{thread_profiler_test.rb → thread_profiler_session_test.rb} +58 -19
  62. data/test/new_relic/agent/commands/xray_session_collection_test.rb +332 -0
  63. data/test/new_relic/agent/commands/xray_session_test.rb +42 -0
  64. data/test/new_relic/agent/configuration/manager_test.rb +2 -1
  65. data/test/new_relic/agent/configuration/server_source_test.rb +10 -10
  66. data/test/new_relic/agent/cpu_sampler_test.rb +50 -0
  67. data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +31 -0
  68. data/test/new_relic/agent/instrumentation/queue_time_test.rb +0 -1
  69. data/test/new_relic/agent/instrumentation/sequel_test.rb +1 -1
  70. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +0 -1
  71. data/test/new_relic/agent/memory_logger_test.rb +53 -0
  72. data/test/new_relic/agent/new_relic_service_test.rb +1 -1
  73. data/test/new_relic/agent/pipe_channel_manager_test.rb +4 -5
  74. data/test/new_relic/agent/request_sampler_test.rb +70 -20
  75. data/test/new_relic/agent/rules_engine_test.rb +6 -0
  76. data/test/new_relic/agent/threading/agent_thread_test.rb +2 -2
  77. data/test/new_relic/agent/threading/backtrace_node_test.rb +110 -17
  78. data/test/new_relic/agent/threading/backtrace_service_test.rb +567 -0
  79. data/test/new_relic/agent/threading/fake_thread.rb +4 -0
  80. data/test/new_relic/agent/threading/thread_profile_test.rb +141 -217
  81. data/test/new_relic/agent/threading/threaded_test_case.rb +3 -8
  82. data/test/new_relic/agent/transaction/developer_mode_sample_buffer_test.rb +69 -0
  83. data/test/new_relic/agent/transaction/force_persist_sample_buffer_test.rb +52 -0
  84. data/test/new_relic/agent/transaction/slowest_sample_buffer_test.rb +67 -0
  85. data/test/new_relic/agent/transaction/xray_sample_buffer_test.rb +71 -0
  86. data/test/new_relic/agent/transaction_sampler_test.rb +171 -307
  87. data/test/new_relic/agent/transaction_test.rb +33 -5
  88. data/test/new_relic/agent/worker_loop_test.rb +33 -11
  89. data/test/new_relic/coerce_test.rb +13 -0
  90. data/test/new_relic/fake_collector.rb +26 -3
  91. data/test/new_relic/multiverse_helpers.rb +2 -0
  92. data/test/new_relic/rack/browser_monitoring_test.rb +12 -0
  93. data/test/new_relic/rack/developer_mode_test.rb +2 -2
  94. data/test/new_relic/transaction_sample_test.rb +19 -2
  95. data/test/performance/lib/performance/console_reporter.rb +1 -1
  96. data/test/performance/lib/performance/test_case.rb +7 -3
  97. data/test/performance/script/runner +3 -0
  98. data/test/performance/suites/thread_profiling.rb +83 -0
  99. data/test/test_helper.rb +2 -2
  100. data.tar.gz.sig +0 -0
  101. metadata +32 -32
  102. metadata.gz.sig +1 -1
  103. data/lib/new_relic/agent/commands/thread_profiler.rb +0 -80
@@ -89,7 +89,7 @@ module NewRelic
89
89
  require 'new_relic/agent/stats_engine'
90
90
  require 'new_relic/agent/transaction_sampler'
91
91
  require 'new_relic/agent/sql_sampler'
92
- require 'new_relic/agent/commands/thread_profiler'
92
+ require 'new_relic/agent/commands/thread_profiler_session'
93
93
  require 'new_relic/agent/error_collector'
94
94
  require 'new_relic/agent/busy_calculator'
95
95
  require 'new_relic/agent/sampler'
@@ -1,2 +1,2 @@
1
- # GITSHA: ac5ce2fccf1bb387f330b48102db9954822f6b53
2
- module NewRelic; module VERSION; BUILD='159'; end; end
1
+ # GITSHA: 2af3914786d2a12b3cda44aa4f5f453ea1f845f8
2
+ module NewRelic; module VERSION; BUILD='164'; end; end
@@ -17,6 +17,14 @@ module NewRelic
17
17
  0
18
18
  end
19
19
 
20
+ def int_or_nil(value, context=nil)
21
+ return nil if value.nil?
22
+ Integer(value)
23
+ rescue => error
24
+ log_failure(value, Integer, context, error)
25
+ nil
26
+ end
27
+
20
28
  def float(value, context=nil)
21
29
  result = Float(value)
22
30
  raise "Value #{result.inspect} is not finite." unless result.finite?
@@ -4,6 +4,7 @@
4
4
 
5
5
  require 'new_relic/language_support'
6
6
  require 'new_relic/agent/null_logger'
7
+ require 'new_relic/agent/memory_logger'
7
8
  require 'new_relic/agent/agent_logger'
8
9
 
9
10
  module NewRelic
@@ -89,9 +89,23 @@ module NewRelic::Rack
89
89
  end
90
90
  end
91
91
  end
92
- headers['Content-Length'] = source.length.to_s if headers['Content-Length']
92
+
93
+ if headers['Content-Length']
94
+ headers['Content-Length'] = calculate_content_length(source).to_s
95
+ end
96
+
93
97
  source
94
98
  end
99
+
100
+ # String does not respond to 'bytesize' in 1.8.6. Fortunately String#length
101
+ # returns bytes rather than characters in 1.8.6 so we can use that instead.
102
+ def calculate_content_length(source)
103
+ if source.respond_to?(:bytesize)
104
+ source.bytesize
105
+ else
106
+ source.length
107
+ end
108
+ end
95
109
  end
96
110
 
97
111
  end
@@ -241,7 +241,7 @@ module NewRelic
241
241
  end
242
242
 
243
243
  def get_samples
244
- @samples = NewRelic::Agent.instance.transaction_sampler.samples.select do |sample|
244
+ @samples = NewRelic::Agent.instance.transaction_sampler.dev_mode_sample_buffer.samples.select do |sample|
245
245
  sample.params[:path] != nil
246
246
  end
247
247
 
@@ -15,8 +15,8 @@ module NewRelic
15
15
 
16
16
  class TransactionSample
17
17
 
18
- attr_accessor(:params, :root_segment, :profile, :force_persist, :guid,
19
- :threshold)
18
+ attr_accessor :params, :root_segment, :profile, :force_persist, :guid,
19
+ :threshold, :finished, :xray_session_id
20
20
  attr_reader :root_segment, :params, :sample_id
21
21
 
22
22
  @@start_time = Time.now
@@ -71,12 +71,14 @@ module NewRelic
71
71
  trace_tree = encoder.encode(self.to_array)
72
72
  [ Helper.time_to_millis(@start_time),
73
73
  Helper.time_to_millis(duration),
74
- string(@params[:path]),
74
+ string(transaction_name),
75
75
  string(@params[:uri]),
76
76
  trace_tree,
77
77
  string(@guid),
78
78
  nil,
79
- !!@force_persist ]
79
+ forced?,
80
+ int_or_nil(xray_session_id)
81
+ ]
80
82
  end
81
83
 
82
84
  def start_time
@@ -87,9 +89,21 @@ module NewRelic
87
89
  @root_segment.path_string
88
90
  end
89
91
 
92
+ def transaction_name
93
+ @params[:path]
94
+ end
95
+
96
+ def transaction_name=(new_name)
97
+ @params[:path] = new_name
98
+ end
99
+
100
+ def forced?
101
+ !!@force_persist || !int_or_nil(xray_session_id).nil?
102
+ end
103
+
90
104
  # relative_timestamp is seconds since the start of the transaction
91
105
  def create_segment(relative_timestamp, metric_name=nil, segment_id = nil)
92
- raise TypeError.new("Frozen Transaction Sample") if frozen?
106
+ raise TypeError.new("Frozen Transaction Sample") if finished
93
107
  @params[:segment_count] += 1
94
108
  @segment_count += 1
95
109
  NewRelic::TransactionSample::Segment.new(relative_timestamp, metric_name, segment_id)
@@ -176,6 +190,7 @@ module NewRelic
176
190
  sample.params.merge! self.params
177
191
  sample.guid = self.guid
178
192
  sample.force_persist = self.force_persist if self.force_persist
193
+ sample.xray_session_id = self.xray_session_id
179
194
 
180
195
  build_segment_for_transfer(sample, @root_segment, sample.root_segment, options)
181
196
 
@@ -12,7 +12,7 @@ module NewRelic
12
12
 
13
13
  MAJOR = 3
14
14
  MINOR = 6
15
- TINY = 7
15
+ TINY = 8
16
16
 
17
17
  begin
18
18
  require File.join(File.dirname(__FILE__), 'build')
data/newrelic.yml CHANGED
@@ -188,18 +188,16 @@ common: &default_settings
188
188
 
189
189
  development:
190
190
  <<: *default_settings
191
- # Turn off communication to New Relic service in development mode (also
192
- # 'enabled').
193
- # NOTE: for initial evaluation purposes, you may want to temporarily
194
- # turn the agent on in development mode.
195
- monitor_mode: false
191
+ # Turn on communication to New Relic service in development mode
192
+ monitor_mode: true
193
+ app_name: <%= @app_name %> (Development)
196
194
 
197
195
  # Rails Only - when running in Developer Mode, the New Relic Agent will
198
196
  # present performance information on the last 100 transactions you have
199
197
  # executed since starting the mongrel.
200
198
  # NOTE: There is substantial overhead when running in developer mode.
201
199
  # Do not use for production or load testing.
202
- developer_mode: true
200
+ developer_mode: false
203
201
 
204
202
  # Enable textmate links
205
203
  # textmate: true
data/newrelic_rpm.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.name = "newrelic_rpm"
10
10
  s.version = NewRelic::VERSION::STRING
11
11
  s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
12
- s.authors = [ "Jason Clark", "Sam Goldstein", "Michael Granger", "Jonan Scheffler", "Ben Weintraub" ]
12
+ s.authors = [ "Jason Clark", "Sam Goldstein", "Jonan Scheffler", "Ben Weintraub" ]
13
13
  s.date = Time.now.strftime('%Y-%m-%d')
14
14
  s.description = <<-EOS
15
15
  New Relic is a performance management system, developed by New Relic,
data/test/agent_helper.rb CHANGED
@@ -97,6 +97,11 @@ unless defined?( assert_not_includes )
97
97
  end
98
98
  end
99
99
 
100
+ def assert_equal_unordered(left, right)
101
+ assert_equal(left.length, right.length, "Lengths don't match. #{left.length} != #{right.length}")
102
+ left.each { |element| assert_includes(right, element) }
103
+ end
104
+
100
105
  def compare_metrics(expected, actual)
101
106
  actual.delete_if {|a| a.include?('GC/cumulative') } # in case we are in REE
102
107
  assert_equal(expected.to_a.sort, actual.to_a.sort, "extra: #{(actual - expected).to_a.inspect}; missing: #{(expected - actual).to_a.inspect}")
@@ -184,6 +189,12 @@ def assert_falsy(expected, msg = nil)
184
189
  assert_block( msg ) { !expected }
185
190
  end
186
191
 
192
+ unless defined?( assert_false )
193
+ def assert_false(expected)
194
+ assert_equal false, expected
195
+ end
196
+ end
197
+
187
198
  # Mock up a transaction for testing purposes, optionally specifying a name and
188
199
  # transaction type. The given block will be executed within the context of the
189
200
  # dummy transaction.
@@ -87,7 +87,11 @@ module Environments
87
87
 
88
88
  def bundle(dir)
89
89
  puts "Bundling..."
90
- bundling = `cd #{dir} && bundle install`
90
+ bundling = `cd #{dir} && bundle install --local`
91
+ unless $?.success?
92
+ puts "Failed local bundle, trying again with full bundle..."
93
+ bundling = `cd #{dir} && bundle install`
94
+ end
91
95
  puts red(bundling) unless $?.success?
92
96
  end
93
97
 
@@ -13,8 +13,8 @@ gem 'rack-test'
13
13
  gem 'newrelic_rpm', :path => "../../.."
14
14
 
15
15
  if (RUBY_PLATFORM == 'java')
16
- gem "activerecord-jdbcmysql-adapter"
17
- gem "activerecord-jdbcsqlite3-adapter"
16
+ gem "activerecord-jdbcmysql-adapter", "~>1.2.9"
17
+ gem "activerecord-jdbcsqlite3-adapter", "~>1.2.9"
18
18
  gem "jruby-openssl"
19
19
  else
20
20
  gem "mysql", RUBY_VERSION == '1.8.6' ? '2.7' : '2.8.1'
@@ -12,8 +12,8 @@ gem 'rack-test'
12
12
  gem 'newrelic_rpm', :path => '../../..'
13
13
 
14
14
  if (RUBY_PLATFORM == 'java')
15
- gem "activerecord-jdbcmysql-adapter"
16
- gem "activerecord-jdbcsqlite3-adapter"
15
+ gem "activerecord-jdbcmysql-adapter", "~>1.2.9"
16
+ gem "activerecord-jdbcsqlite3-adapter", "~>1.2.9"
17
17
  gem "jruby-openssl"
18
18
  else
19
19
  gem "sqlite3-ruby", "1.2.5"
@@ -11,8 +11,8 @@ gem 'rack-test'
11
11
  gem "newrelic_rpm", :path => '../../..'
12
12
 
13
13
  if(RUBY_PLATFORM == 'java')
14
- gem "activerecord-jdbcmysql-adapter"
15
- gem "activerecord-jdbcsqlite3-adapter"
14
+ gem "activerecord-jdbcmysql-adapter", "~>1.2.9"
15
+ gem "activerecord-jdbcsqlite3-adapter", "~>1.2.9"
16
16
  gem "jruby-openssl"
17
17
  else
18
18
  gem "mysql", RUBY_VERSION == '1.8.6' ? '2.7' : '2.8.1'
@@ -8,8 +8,8 @@ gem 'rack'
8
8
  gem 'rack-test'
9
9
 
10
10
  if (RUBY_PLATFORM == 'java')
11
- gem "activerecord-jdbcmysql-adapter"
12
- gem "activerecord-jdbcsqlite3-adapter"
11
+ gem "activerecord-jdbcmysql-adapter", "~>1.2.9"
12
+ gem "activerecord-jdbcsqlite3-adapter", "~>1.2.9"
13
13
  gem "jruby-openssl"
14
14
  else
15
15
  gem "mysql"
@@ -9,8 +9,8 @@ gem 'rack'
9
9
  gem 'rack-test'
10
10
 
11
11
  platforms :jruby do
12
- gem "activerecord-jdbcmysql-adapter"
13
- gem "activerecord-jdbcsqlite3-adapter"
12
+ gem "activerecord-jdbcmysql-adapter", "~>1.2.9"
13
+ gem "activerecord-jdbcsqlite3-adapter", "~>1.2.9"
14
14
  gem "jruby-openssl"
15
15
  end
16
16
 
@@ -28,7 +28,7 @@ class MarshalingTest < MiniTest::Unit::TestCase
28
28
  sampler.notice_scope_empty(OpenStruct.new(:name => 'path',
29
29
  :custom_parameters => {}))
30
30
 
31
- expected_sample = sampler.instance_variable_get(:@slowest_sample)
31
+ expected_sample = sampler.last_sample
32
32
 
33
33
  agent.service.connect
34
34
  agent.send(:harvest_and_send_slowest_sample)
@@ -17,6 +17,12 @@ class TestingApp
17
17
  end
18
18
 
19
19
  def call(env)
20
+ request = Rack::Request.new(env)
21
+ params = request.params
22
+ if params['transaction_name']
23
+ NewRelic::Agent.set_transaction_name(params['transaction_name'])
24
+ end
25
+ sleep(params['sleep'].to_f) if params['sleep']
20
26
  [200, headers, [response]]
21
27
  end
22
28
 
@@ -23,7 +23,7 @@ class ThreadProfilingTest < MiniTest::Unit::TestCase
23
23
  agent.service.request_timeout = 0.5
24
24
  agent.service.agent_id = 666
25
25
 
26
- @thread_profiler = agent.thread_profiler
26
+ @thread_profiler_session = agent.agent_command_router.thread_profiler_session
27
27
  @threads = []
28
28
  end
29
29
 
@@ -69,7 +69,7 @@ class ThreadProfilingTest < MiniTest::Unit::TestCase
69
69
 
70
70
  profile_data = $collector.calls_for('profile_data')[0]
71
71
  assert_equal('666', profile_data.run_id, "Missing run_id, profile_data was #{profile_data.inspect}")
72
- assert(profile_data.poll_count > 10, "Expected poll_count > 10, but was #{profile_data.poll_count}")
72
+ assert(profile_data.sample_count > 10, "Expected sample_count > 10, but was #{profile_data.sample_count}")
73
73
 
74
74
  assert_saw_traces(profile_data, "OTHER")
75
75
  assert_saw_traces(profile_data, "AGENT")
@@ -85,12 +85,12 @@ class ThreadProfilingTest < MiniTest::Unit::TestCase
85
85
 
86
86
  profile_data = $collector.calls_for('profile_data')[0]
87
87
  assert_equal('666', profile_data.run_id, "Missing run_id, profile_data was #{profile_data.inspect}")
88
- assert(profile_data.poll_count < 50, "Expected poll_count < 50, but was #{profile_data.poll_count}")
88
+ assert(profile_data.sample_count < 50, "Expected sample_count < 50, but was #{profile_data.sample_count}")
89
89
  end
90
90
 
91
91
  def issue_command(cmd)
92
92
  $collector.stub('get_agent_commands', cmd)
93
- agent.send(:handle_agent_commands)
93
+ agent.send(:check_for_and_handle_agent_commands)
94
94
  end
95
95
 
96
96
  # Runs a thread we expect to span entire test and be killed at the end
@@ -103,7 +103,7 @@ class ThreadProfilingTest < MiniTest::Unit::TestCase
103
103
 
104
104
  def let_it_finish
105
105
  Timeout.timeout(5) do
106
- until @thread_profiler.finished?
106
+ until @thread_profiler_session.ready_to_harvest?
107
107
  sleep(0.1)
108
108
  end
109
109
  end
@@ -0,0 +1,163 @@
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
+ # https://newrelic.atlassian.net/wiki/display/eng/Agent+Thread+Profiling
6
+ # https://newrelic.atlassian.net/browse/RUBY-917
7
+
8
+ if RUBY_VERSION >= '1.9'
9
+
10
+ require 'rack/test'
11
+ require 'multiverse_helpers'
12
+ require './testing_app'
13
+
14
+ class XraySessionsTest < MiniTest::Unit::TestCase
15
+
16
+ AGENT_RUN_ID = 123
17
+
18
+ include MultiverseHelpers
19
+ include Rack::Test::Methods
20
+
21
+ setup_and_teardown_agent() do |collector|
22
+ collector.stub('connect', {"agent_run_id" => AGENT_RUN_ID })
23
+ end
24
+
25
+ def after_setup
26
+ agent.service.request_timeout = 0.5
27
+ agent.service.agent_id = AGENT_RUN_ID
28
+ end
29
+
30
+ def app
31
+ @app ||= TestingApp.new
32
+ end
33
+
34
+ def test_tags_transaction_traces_with_xray_id
35
+ session = build_xray_session('key_transaction_name' => 'Controller/Rack/A')
36
+ with_xray_sessions(session) do
37
+ 5.times { get '/?transaction_name=A' }
38
+ trigger_harvest
39
+ end
40
+
41
+ posts = $collector.calls_for('transaction_sample_data')
42
+ assert_equal(1, posts.size, "Expected exactly one transaction_sample_data post")
43
+
44
+ traces = posts.first.samples
45
+ assert_equal(5, traces.size)
46
+ assert traces.all? { |t| t.metric_name == 'Controller/Rack/A' }
47
+ assert traces.all? { |t| t.xray_id == session['x_ray_id'] }
48
+ end
49
+
50
+ def test_does_not_collect_traces_for_non_xrayed_transactions
51
+ session = build_xray_session('key_transaction_name' => 'Controller/Rack/A')
52
+ with_xray_sessions(session) do
53
+ get '/?transaction_name=OtherThing'
54
+ get '/?transaction_name=A'
55
+ trigger_harvest
56
+ end
57
+
58
+ posts = $collector.calls_for('transaction_sample_data')
59
+ assert_equal(1, posts.size, "Expected exactly one transaction_sample_data post")
60
+
61
+ # We expect exactly one transaction trace, for A only
62
+ assert_equal(1, posts.first.samples.size)
63
+ end
64
+
65
+ def test_gathers_transaction_traces_from_multiple_concurrent_xray_sessions
66
+ sessionA = build_xray_session('x_ray_id' => 12, 'key_transaction_name' => 'Controller/Rack/A')
67
+ sessionB = build_xray_session('x_ray_id' => 13, 'key_transaction_name' => 'Controller/Rack/B')
68
+
69
+ with_xray_sessions(sessionA, sessionB) do
70
+ 2.times do
71
+ get '/?transaction_name=A'
72
+ get '/?transaction_name=B'
73
+ end
74
+ trigger_harvest
75
+ end
76
+
77
+ posts = $collector.calls_for('transaction_sample_data')
78
+ assert_equal(1, posts.size, "Expected exactly one transaction_sample_data post")
79
+
80
+ traces = posts.first.samples
81
+ assert_equal(4, traces.size)
82
+
83
+ tracesA = traces.select { |t| t.metric_name == 'Controller/Rack/A' }
84
+ tracesB = traces.select { |t| t.metric_name == 'Controller/Rack/B' }
85
+ assert_equal(2, tracesA.size, "Expected 2 traces for transaction A")
86
+ assert_equal(2, tracesB.size, "Expected 2 traces for transaction B")
87
+ end
88
+
89
+ def test_gathers_thread_profiles
90
+ session = build_xray_session('key_transaction_name' => 'Controller/Rack/A')
91
+ with_xray_sessions(session) do
92
+ get '/?transaction_name=A&sleep=1'
93
+ trigger_harvest
94
+ end
95
+
96
+ # assert that a thread profile was submitted
97
+ posts = $collector.calls_for('profile_data')
98
+ assert_equal(1, posts.size, "Expected exactly one profile_data post")
99
+
100
+ profile_data_post = posts.first
101
+ assert(profile_data_post.sample_count > 1, "Expected at least one sample")
102
+ assert_saw_traces(profile_data_post, 'REQUEST')
103
+ end
104
+
105
+ ## Helpers
106
+
107
+ def next_xray_session_id
108
+ @xray_session_id ||= 0
109
+ @xray_session_id += 1
110
+ @xray_session_id
111
+ end
112
+
113
+ def build_xray_session(overrides={})
114
+ defaults = {
115
+ "x_ray_id" => next_xray_session_id,
116
+ "xray_session_name" => "Test XRay Session",
117
+ "key_transaction_name" => "Controller/Rack/Transaction",
118
+ "requested_trace_count" => 10,
119
+ "duration" => 100,
120
+ "sample_period" => 0.1,
121
+ "run_profiler" => true
122
+ }
123
+ defaults.merge(overrides)
124
+ end
125
+
126
+ def build_active_xrays_command(active_xray_ids)
127
+ [[
128
+ AGENT_RUN_ID,
129
+ {
130
+ 'name' => 'active_xray_sessions',
131
+ 'arguments' => { 'xray_ids' => active_xray_ids }
132
+ }
133
+ ]]
134
+ end
135
+
136
+ def with_xray_sessions(*xray_metadatas)
137
+ xray_session_ids = xray_metadatas.map { |m| m['x_ray_id'] }
138
+ activate_cmd = build_active_xrays_command(xray_session_ids)
139
+
140
+ $collector.stub('get_xray_metadata', xray_metadatas)
141
+ issue_command(activate_cmd)
142
+
143
+ yield
144
+
145
+ deactivate_cmd = build_active_xrays_command([])
146
+ issue_command(deactivate_cmd)
147
+ end
148
+
149
+ def issue_command(cmd)
150
+ $collector.stub('get_agent_commands', cmd)
151
+ agent.send(:check_for_and_handle_agent_commands)
152
+ end
153
+
154
+ def trigger_harvest
155
+ agent.send(:transmit_data)
156
+ end
157
+
158
+ def assert_saw_traces(profile_data, type)
159
+ assert !profile_data.traces[type].empty?, "Missing #{type} traces"
160
+ end
161
+
162
+ end
163
+ end