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
data/CHANGELOG CHANGED
@@ -1,5 +1,19 @@
1
1
  # New Relic Ruby Agent Release Notes #
2
2
 
3
+ ## v3.6.8 ##
4
+
5
+ * X-Ray Sessions support
6
+
7
+ X-Ray Sessions provide more targeted transaction trace samples and thread
8
+ profiling for web transactions. For full details see our X-Ray sessions
9
+ documentation at https://newrelic.com/docs/site/xray-sessions.
10
+
11
+ * CPU metrics re-enabled for JRuby >= 1.7.0
12
+
13
+ To work around a JRuby bug, the Ruby agent stopped gathering CPU metrics on
14
+ that platform. With the bug fixed, the agent can gather those metrics again.
15
+ Thanks Bram de Vries for the contribution!
16
+
3
17
  ## v3.6.7 ##
4
18
 
5
19
  * Resque-pool support
@@ -15,7 +15,6 @@ require 'new_relic/agent/pipe_service'
15
15
  require 'new_relic/agent/configuration/manager'
16
16
  require 'new_relic/agent/database'
17
17
  require 'new_relic/agent/commands/agent_command_router'
18
- require 'new_relic/agent/commands/thread_profiler'
19
18
  require 'new_relic/agent/event_listener'
20
19
  require 'new_relic/agent/cross_app_monitor'
21
20
  require 'new_relic/agent/request_sampler'
@@ -45,8 +44,7 @@ module NewRelic
45
44
  @stats_engine = NewRelic::Agent::StatsEngine.new
46
45
  @transaction_sampler = NewRelic::Agent::TransactionSampler.new
47
46
  @sql_sampler = NewRelic::Agent::SqlSampler.new
48
- @thread_profiler = NewRelic::Agent::Commands::ThreadProfiler.new
49
- @agent_command_router = NewRelic::Agent::Commands::AgentCommandRouter.new(@thread_profiler)
47
+ @agent_command_router = NewRelic::Agent::Commands::AgentCommandRouter.new(@events)
50
48
  @cross_app_monitor = NewRelic::Agent::CrossAppMonitor.new(@events)
51
49
  @error_collector = NewRelic::Agent::ErrorCollector.new
52
50
  @transaction_rules = NewRelic::Agent::RulesEngine.new
@@ -59,6 +57,7 @@ module NewRelic
59
57
  @environment_report = nil
60
58
 
61
59
  @last_harvest_time = Time.now
60
+ @harvest_lock = Mutex.new
62
61
  @obfuscator = lambda {|sql| NewRelic::Agent::Database.default_sql_obfuscator(sql) }
63
62
  end
64
63
 
@@ -82,8 +81,7 @@ module NewRelic
82
81
  # the transaction sampler that handles recording transactions
83
82
  attr_reader :transaction_sampler
84
83
  attr_reader :sql_sampler
85
- # begins a thread profile session when instructed by agent commands
86
- attr_reader :thread_profiler
84
+ # manages agent commands we receive from the collector, and the handlers
87
85
  attr_reader :agent_command_router
88
86
  # error collector is a simple collection of recorded errors
89
87
  attr_reader :error_collector
@@ -109,6 +107,7 @@ module NewRelic
109
107
  # the latter during harvest.
110
108
  attr_reader :transaction_rules
111
109
  attr_reader :metric_rules
110
+ attr_reader :harvest_lock
112
111
 
113
112
  # Returns the length of the unsent errors array, if it exists,
114
113
  # otherwise nil
@@ -557,22 +556,12 @@ module NewRelic
557
556
  ::NewRelic::Agent.logger.debug "Running worker loop"
558
557
  end
559
558
 
560
- # Accessor for the harvest lock
561
- def harvest_lock
562
- return nil if @worker_loop.nil?
563
- @worker_loop.lock
564
- end
565
-
566
559
  # Synchronize with the harvest loop. If the harvest thread has taken
567
560
  # a lock (DNS lookups, backticks, agent-owned locks, etc), and we
568
561
  # fork while locked, this can deadlock child processes. For more
569
562
  # details, see https://github.com/resque/resque/issues/1101
570
563
  def synchronize_with_harvest
571
- if harvest_lock
572
- harvest_lock.synchronize do
573
- yield
574
- end
575
- else
564
+ harvest_lock.synchronize do
576
565
  yield
577
566
  end
578
567
  end
@@ -622,9 +611,12 @@ module NewRelic
622
611
 
623
612
  # Handles an unknown error in the worker thread by logging
624
613
  # it and disconnecting the agent, since we are now in an
625
- # unknown state
614
+ # unknown state.
626
615
  def handle_other_error(error)
627
- ::NewRelic::Agent.logger.error "Terminating worker loop.", error
616
+ ::NewRelic::Agent.logger.error "Unhandled error in worker thread, disconnecting this agent process:"
617
+ # These errors are fatal (that is, they will prevent the agent from
618
+ # reporting entirely), so we really want backtraces when they happen
619
+ ::NewRelic::Agent.logger.log_exception(:error, error)
628
620
  disconnect
629
621
  end
630
622
 
@@ -921,7 +913,7 @@ module NewRelic
921
913
  handle_license_error(e)
922
914
  rescue NewRelic::Agent::UnrecoverableAgentException => e
923
915
  handle_unrecoverable_agent_error(e)
924
- rescue Timeout::Error, StandardError => e
916
+ rescue Timeout::Error => e
925
917
  log_error(e)
926
918
  if opts[:keep_retrying]
927
919
  note_connect_failure
@@ -931,6 +923,8 @@ module NewRelic
931
923
  else
932
924
  disconnect
933
925
  end
926
+ rescue StandardError => e
927
+ handle_other_error(e)
934
928
  end
935
929
 
936
930
  # Who am I? Well, this method can tell you your hostname.
@@ -984,7 +978,6 @@ module NewRelic
984
978
  # transaction threshold
985
979
  def harvest_transaction_traces
986
980
  @traces = @transaction_sampler.harvest(@traces)
987
- @traces
988
981
  end
989
982
 
990
983
  def harvest_and_send_slowest_sql
@@ -1045,14 +1038,10 @@ module NewRelic
1045
1038
  ::NewRelic::Agent.logger.debug "Sent slowest sample (#{@service.agent_id}) in #{Time.now - start_time} seconds"
1046
1039
  end
1047
1040
 
1048
- def harvest_and_send_thread_profile(disconnecting=false)
1049
- @thread_profiler.stop(true) if disconnecting
1050
-
1051
- if @thread_profiler.finished?
1052
- profile = @thread_profiler.harvest
1053
-
1054
- ::NewRelic::Agent.logger.debug "Sending thread profile #{profile.profile_id}"
1055
- @service.profile_data(profile)
1041
+ def harvest_and_send_for_agent_commands(disconnecting=false)
1042
+ data = @agent_command_router.harvest_data_to_send(disconnecting)
1043
+ data.each do |service_method, payload|
1044
+ @service.send(service_method, payload)
1056
1045
  end
1057
1046
  end
1058
1047
 
@@ -1087,16 +1076,28 @@ module NewRelic
1087
1076
 
1088
1077
  # Fetch samples from the RequestSampler and send them.
1089
1078
  def harvest_and_send_analytic_event_data
1090
- samples = @request_sampler.samples
1091
- @service.analytic_event_data(samples) unless samples.empty?
1092
- @request_sampler.reset
1079
+ samples = @request_sampler.harvest
1080
+ begin
1081
+ @service.analytic_event_data(samples) unless samples.empty?
1082
+ rescue
1083
+ @request_sampler.merge(samples)
1084
+ raise
1085
+ end
1093
1086
  end
1094
1087
 
1095
- def handle_agent_commands
1096
- @agent_command_router.handle_agent_commands
1088
+ def check_for_and_handle_agent_commands
1089
+ @agent_command_router.check_for_and_handle_agent_commands
1097
1090
  end
1098
1091
 
1099
1092
  def transmit_data(disconnecting=false)
1093
+ harvest_lock.synchronize do
1094
+ transmit_data_already_locked(disconnecting)
1095
+ end
1096
+ end
1097
+
1098
+ # This method is expected to only be called with the harvest_lock
1099
+ # already held
1100
+ def transmit_data_already_locked(disconnecting)
1100
1101
  now = Time.now
1101
1102
  ::NewRelic::Agent.logger.debug "Sending data to New Relic Service"
1102
1103
 
@@ -1108,8 +1109,8 @@ module NewRelic
1108
1109
  harvest_and_send_timeslice_data
1109
1110
  harvest_and_send_analytic_event_data
1110
1111
 
1111
- handle_agent_commands
1112
- harvest_and_send_thread_profile(disconnecting)
1112
+ check_for_and_handle_agent_commands
1113
+ harvest_and_send_for_agent_commands(disconnecting)
1113
1114
  end
1114
1115
  rescue EOFError => e
1115
1116
  ::NewRelic::Agent.logger.warn("EOFError after #{Time.now - now}s when transmitting data to New Relic Service.")
@@ -1128,6 +1129,8 @@ module NewRelic
1128
1129
  @stats_engine.record_metrics('Supportability/Harvest', duration)
1129
1130
  end
1130
1131
 
1132
+ private :transmit_data_already_locked
1133
+
1131
1134
  # This method contacts the server to send remaining data and
1132
1135
  # let the server know that the agent is shutting down - this
1133
1136
  # allows us to do things like accurately set the end of the
@@ -16,7 +16,6 @@ module NewRelic
16
16
  gather_startup_logs
17
17
  end
18
18
 
19
-
20
19
  def fatal(*msgs)
21
20
  format_and_send(:fatal, msgs)
22
21
  end
@@ -120,15 +119,15 @@ module NewRelic
120
119
  end
121
120
 
122
121
  LOG_LEVELS = {
123
- "debug" => Logger::DEBUG,
124
- "info" => Logger::INFO,
125
- "warn" => Logger::WARN,
126
- "error" => Logger::ERROR,
127
- "fatal" => Logger::FATAL,
122
+ "debug" => ::Logger::DEBUG,
123
+ "info" => ::Logger::INFO,
124
+ "warn" => ::Logger::WARN,
125
+ "error" => ::Logger::ERROR,
126
+ "fatal" => ::Logger::FATAL,
128
127
  }
129
128
 
130
129
  def self.log_level_for(level)
131
- LOG_LEVELS.fetch(level.to_s.downcase, Logger::INFO)
130
+ LOG_LEVELS.fetch(level.to_s.downcase, ::Logger::INFO)
132
131
  end
133
132
 
134
133
  def set_log_format!
@@ -143,46 +142,6 @@ module NewRelic
143
142
  end
144
143
  end
145
144
 
146
- # Base class for startup logging and testing in multiverse
147
- class MemoryLogger
148
- def initialize
149
- @messages = []
150
- end
151
-
152
- def is_startup_logger?
153
- true
154
- end
155
-
156
- attr_accessor :messages, :level
157
-
158
- def fatal(*msgs)
159
- messages << [:fatal, msgs]
160
- end
161
-
162
- def error(*msgs)
163
- messages << [:error, msgs]
164
- end
165
-
166
- def warn(*msgs)
167
- messages << [:warn, msgs]
168
- end
169
-
170
- def info(*msgs)
171
- messages << [:info, msgs]
172
- end
173
-
174
- def debug(*msgs)
175
- messages << [:debug, msgs]
176
- end
177
-
178
- def dump(logger)
179
- messages.each do |msg|
180
- logger.send(msg[0], msg[1])
181
- end
182
- messages.clear
183
- end
184
- end
185
-
186
145
  # In an effort to not lose messages during startup, we trap them in memory
187
146
  # The real logger will then dump its contents out when it arrives.
188
147
  class StartupLogger < MemoryLogger
@@ -28,10 +28,16 @@ module NewRelic
28
28
  # Creates a new browser configuration data. Argument is a hash
29
29
  # of configuration values from the server
30
30
  def initialize
31
- @browser_timing_header = build_browser_timing_header
32
- ::NewRelic::Agent.logger.debug("Browser timing header: #{@browser_timing_header.inspect}")
33
- @browser_timing_static_footer = build_load_file_js
34
- ::NewRelic::Agent.logger.debug("Browser timing static footer: #{@browser_timing_static_footer.inspect}")
31
+ if Agent.config[:js_errors_beta] && Agent.config[:js_agent_loader]
32
+ ::NewRelic::Agent.logger.debug("Beta JS errors functionality enabled")
33
+ ::NewRelic::Agent.logger.debug("JS agent loader version: #{Agent.config[:js_agent_loader_version]}")
34
+ else
35
+ @browser_timing_header = build_browser_timing_header
36
+ ::NewRelic::Agent.logger.debug("Browser timing header: #{@browser_timing_header.inspect}")
37
+ @browser_timing_static_footer = build_load_file_js
38
+ ::NewRelic::Agent.logger.debug("Browser timing static footer: #{@browser_timing_static_footer.inspect}")
39
+ end
40
+
35
41
  if Agent.config[:'rum.jsonp']
36
42
  ::NewRelic::Agent.logger.debug("Real User Monitoring is using JSONP protocol")
37
43
  @finish_command = 'nrfj'
@@ -97,29 +97,6 @@ module NewRelic
97
97
  NewRelic::Agent::TransactionState.get.timings
98
98
  end
99
99
 
100
- def insert_mobile_response_header(request, response)
101
- if mobile_header_found_in?(request) &&
102
- NewRelic::Agent.instance.beacon_configuration
103
-
104
- config = NewRelic::Agent.instance.beacon_configuration
105
-
106
- response['X-NewRelic-Beacon-Url'] = beacon_url(request)
107
-
108
- payload = %[ ["#{Agent.config[:application_id]}","#{obfuscate(config, browser_monitoring_transaction_name)}",#{current_timings.queue_time_in_millis},#{current_timings.app_time_in_millis}] ]
109
- response['X-NewRelic-App-Server-Metrics'] = payload
110
- end
111
- end
112
-
113
- def mobile_header_found_in?(request)
114
- headers = ['HTTP_X_NEWRELIC_MOBILE_TRACE', 'X_NEWRELIC_MOBILE_TRACE',
115
- 'X-NewRelic-Mobile-Trace']
116
- headers.inject(false){|i,m| i || (request.env[m] == 'true')}
117
- end
118
-
119
- def beacon_url(request)
120
- "#{request.scheme || 'http'}://#{Agent.config[:beacon]}/mobile/1/#{Agent.config[:browser_key]}"
121
- end
122
-
123
100
  private
124
101
 
125
102
  # Check whether RUM header and footer should be generated. Log the
@@ -176,26 +153,55 @@ module NewRelic
176
153
  return NewRelic::Agent::TransactionState.get.request_token
177
154
  end
178
155
 
156
+ def use_beta_js_agent?
157
+ return Agent.config[:js_errors_beta] && Agent.config[:js_agent_loader]
158
+ end
159
+
179
160
  # NOTE: This method may be overridden for internal prototyping, so should
180
161
  # remain stable.
181
162
  def header_js_string
182
- NewRelic::Agent.instance.beacon_configuration.browser_timing_header
163
+ if (use_beta_js_agent?)
164
+ html_safe_if_needed("\n<script type=\"text/javascript\">#{Agent.config[:js_agent_loader]}</script>")
165
+ else
166
+ NewRelic::Agent.instance.beacon_configuration.browser_timing_header
167
+ end
183
168
  end
184
169
 
185
170
  # NOTE: This method may be overridden for internal prototyping, so should
186
171
  # remain stable.
187
172
  def footer_js_string(config)
188
- obfuscated_transaction_name = obfuscate(config, browser_monitoring_transaction_name)
173
+ if (use_beta_js_agent?)
174
+ js_data = {
175
+ 'txnParam' => config.finish_command,
176
+ 'beacon' => NewRelic::Agent.config[:beacon],
177
+ 'errorBeacon' => NewRelic::Agent.config[:error_beacon],
178
+ 'licenseKey' => NewRelic::Agent.config[:browser_key],
179
+ 'applicationID' => NewRelic::Agent.config[:application_id],
180
+ 'transactionName' => obfuscate(config, browser_monitoring_transaction_name),
181
+ 'queueTime' => current_timings.queue_time_in_millis,
182
+ 'applicationTime' => current_timings.app_time_in_millis,
183
+ 'ttGuid' => tt_guid,
184
+ 'agentToken' => tt_token,
185
+ 'user' => obfuscate(config, transaction_attribute(:user)),
186
+ 'account' => obfuscate(config, transaction_attribute(:account)),
187
+ 'product' => obfuscate(config, transaction_attribute(:product)),
188
+ 'agent' => NewRelic::Agent.config[:js_agent_file]
189
+ }
190
+
191
+ html_safe_if_needed("\n<script type=\"text/javascript\">window.NREUM||(NREUM={});NREUM.info=#{NewRelic.json_dump(js_data)}</script>")
192
+ else
193
+ obfuscated_transaction_name = obfuscate(config, browser_monitoring_transaction_name)
189
194
 
190
- user = obfuscate(config, transaction_attribute(:user))
191
- account = obfuscate(config, transaction_attribute(:account))
192
- product = obfuscate(config, transaction_attribute(:product))
195
+ user = obfuscate(config, transaction_attribute(:user))
196
+ account = obfuscate(config, transaction_attribute(:account))
197
+ product = obfuscate(config, transaction_attribute(:product))
193
198
 
194
- # This is slightly varied from other agents' RUM footer to ensure that
195
- # NREUMQ is defined. Our experimental header placement has some holes
196
- # where it could end up in a comment and not define NREUMQ as the footer
197
- # assumes. We protect against that here.
198
- html_safe_if_needed(%'<script type="text/javascript">if (typeof NREUMQ !== "undefined") { #{config.browser_timing_static_footer}NREUMQ.push(["#{config.finish_command}","#{Agent.config[:beacon]}","#{Agent.config[:browser_key]}","#{Agent.config[:application_id]}","#{obfuscated_transaction_name}",#{current_timings.queue_time_in_millis},#{current_timings.app_time_in_millis},new Date().getTime(),"#{tt_guid}","#{tt_token}","#{user}","#{account}","#{product}"]);}</script>')
199
+ # This is slightly varied from other agents' RUM footer to ensure that
200
+ # NREUMQ is defined. Our experimental header placement has some holes
201
+ # where it could end up in a comment and not define NREUMQ as the footer
202
+ # assumes. We protect against that here.
203
+ html_safe_if_needed(%'<script type="text/javascript">if (typeof NREUMQ !== "undefined") { #{config.browser_timing_static_footer}NREUMQ.push(["#{config.finish_command}","#{Agent.config[:beacon]}","#{Agent.config[:browser_key]}","#{Agent.config[:application_id]}","#{obfuscated_transaction_name}",#{current_timings.queue_time_in_millis},#{current_timings.app_time_in_millis},new Date().getTime(),"#{tt_guid}","#{tt_token}","#{user}","#{account}","#{product}"]);}</script>')
204
+ end
199
205
  end
200
206
 
201
207
  def html_safe_if_needed(string)
@@ -8,10 +8,10 @@ module NewRelic
8
8
  class AgentCommand
9
9
  attr_reader :id, :name, :arguments
10
10
 
11
- def initialize(collector_command)
12
- @id = collector_command[0]
13
- @name = collector_command[1]["name"]
14
- @arguments = collector_command[1]["arguments"]
11
+ def initialize(raw_collector_command)
12
+ @id = raw_collector_command[0]
13
+ @name = raw_collector_command[1]["name"]
14
+ @arguments = raw_collector_command[1]["arguments"]
15
15
  end
16
16
  end
17
17
  end
@@ -9,6 +9,8 @@
9
9
  # like the ThreadProfiler, so it's simpler to just keep it together here.
10
10
 
11
11
  require 'new_relic/agent/commands/agent_command'
12
+ require 'new_relic/agent/commands/xray_session_collection'
13
+ require 'new_relic/agent/threading/backtrace_service'
12
14
 
13
15
  module NewRelic
14
16
  module Agent
@@ -16,32 +18,91 @@ module NewRelic
16
18
  class AgentCommandRouter
17
19
  attr_reader :handlers
18
20
 
19
- def initialize(thread_profiler)
21
+ attr_accessor :thread_profiler_session, :backtrace_service,
22
+ :xray_session_collection
23
+
24
+ def initialize(event_listener=nil)
20
25
  @handlers = Hash.new { |*| Proc.new { |cmd| self.unrecognized_agent_command(cmd) } }
21
- @handlers['start_profiler'] = Proc.new { |cmd| thread_profiler.handle_start_command(cmd) }
22
- @handlers['stop_profiler'] = Proc.new { |cmd| thread_profiler.handle_stop_command(cmd) }
26
+
27
+ @backtrace_service = Threading::BacktraceService.new(event_listener)
28
+
29
+ @thread_profiler_session = ThreadProfilerSession.new(@backtrace_service)
30
+ @xray_session_collection = XraySessionCollection.new(@backtrace_service, event_listener)
31
+
32
+ @handlers['start_profiler'] = Proc.new { |cmd| thread_profiler_session.handle_start_command(cmd) }
33
+ @handlers['stop_profiler'] = Proc.new { |cmd| thread_profiler_session.handle_stop_command(cmd) }
34
+ @handlers['active_xray_sessions'] = Proc.new { |cmd| xray_session_collection.handle_active_xray_sessions(cmd) }
23
35
  end
24
36
 
25
37
  def new_relic_service
26
38
  NewRelic::Agent.instance.service
27
39
  end
28
40
 
29
- def handle_agent_commands
30
- results = invoke_commands(get_agent_commands)
41
+ def check_for_and_handle_agent_commands
42
+ commands = get_agent_commands
43
+
44
+ stop_xray_sessions unless active_xray_command?(commands)
45
+
46
+ results = invoke_commands(commands)
31
47
  new_relic_service.agent_command_results(results) unless results.empty?
32
48
  end
33
49
 
50
+ def stop_xray_sessions
51
+ self.xray_session_collection.stop_all_sessions
52
+ end
53
+
54
+ def active_xray_command?(commands)
55
+ commands.any? {|command| command.name == 'active_xray_sessions'}
56
+ end
57
+
58
+ NO_PROFILES_TO_SEND = {}.freeze
59
+
60
+ def harvest_data_to_send(disconnecting)
61
+ profiles = []
62
+ profiles += harvest_from_xray_session_collection
63
+ profiles += harvest_from_thread_profiler_session(disconnecting)
64
+
65
+ format_harvest_data(profiles)
66
+ end
67
+
68
+ def harvest_from_xray_session_collection
69
+ self.xray_session_collection.harvest_thread_profiles
70
+ end
71
+
72
+ def harvest_from_thread_profiler_session(disconnecting)
73
+ if self.thread_profiler_session.ready_to_harvest?(disconnecting)
74
+ self.thread_profiler_session.stop(true)
75
+ [self.thread_profiler_session.harvest]
76
+ else
77
+ []
78
+ end
79
+ end
80
+
81
+ def format_harvest_data(profiles)
82
+ if profiles.empty?
83
+ NewRelic::Agent.logger.debug "No thread profiles with data found to send."
84
+ NO_PROFILES_TO_SEND
85
+ else
86
+ log_profiles(profiles)
87
+ {:profile_data => profiles}
88
+ end
89
+ end
90
+
91
+ def log_profiles(profiles)
92
+ profile_descriptions = profiles.map { |p| p.to_log_description }
93
+ ::NewRelic::Agent.logger.debug "Sending thread profiles [#{profile_descriptions.join(", ")}]"
94
+ end
95
+
34
96
  def get_agent_commands
35
97
  commands = new_relic_service.get_agent_commands
36
98
  NewRelic::Agent.logger.debug "Received get_agent_commands = #{commands.inspect}"
37
- commands
99
+ commands.map {|collector_command| AgentCommand.new(collector_command)}
38
100
  end
39
101
 
40
- def invoke_commands(collector_commands)
102
+ def invoke_commands(agent_commands)
41
103
  results = {}
42
104
 
43
- collector_commands.each do |collector_command|
44
- agent_command = NewRelic::Agent::Commands::AgentCommand.new(collector_command)
105
+ agent_commands.each do |agent_command|
45
106
  results[agent_command.id.to_s] = invoke_command(agent_command)
46
107
  end
47
108
 
@@ -56,6 +117,7 @@ module NewRelic
56
117
  call_handler_for(agent_command)
57
118
  return success
58
119
  rescue AgentCommandError => e
120
+ NewRelic::Agent.logger.debug(e)
59
121
  error(e)
60
122
  end
61
123
  end
@@ -68,7 +130,7 @@ module NewRelic
68
130
  end
69
131
 
70
132
  def error(err)
71
- { ERROR_KEY => err.message}
133
+ { ERROR_KEY => err.message }
72
134
  end
73
135
 
74
136
  def call_handler_for(agent_command)