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.
- data/CHANGELOG +14 -0
- data/lib/new_relic/agent/agent.rb +38 -35
- data/lib/new_relic/agent/agent_logger.rb +6 -47
- data/lib/new_relic/agent/beacon_configuration.rb +10 -4
- data/lib/new_relic/agent/browser_monitoring.rb +39 -33
- data/lib/new_relic/agent/commands/agent_command.rb +4 -4
- data/lib/new_relic/agent/commands/agent_command_router.rb +72 -10
- data/lib/new_relic/agent/commands/thread_profiler_session.rb +110 -0
- data/lib/new_relic/agent/commands/xray_session.rb +55 -0
- data/lib/new_relic/agent/commands/xray_session_collection.rb +158 -0
- data/lib/new_relic/agent/configuration/default_source.rb +61 -24
- data/lib/new_relic/agent/configuration/mask_defaults.rb +2 -2
- data/lib/new_relic/agent/configuration/server_source.rb +1 -1
- data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +2 -0
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +4 -10
- data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +10 -11
- data/lib/new_relic/agent/memory_logger.rb +52 -0
- data/lib/new_relic/agent/new_relic_service.rb +4 -0
- data/lib/new_relic/agent/request_sampler.rb +32 -13
- data/lib/new_relic/agent/samplers/cpu_sampler.rb +6 -3
- data/lib/new_relic/agent/threading/agent_thread.rb +2 -1
- data/lib/new_relic/agent/threading/backtrace_node.rb +80 -27
- data/lib/new_relic/agent/threading/backtrace_service.rb +264 -0
- data/lib/new_relic/agent/threading/thread_profile.rb +79 -118
- data/lib/new_relic/agent/transaction/developer_mode_sample_buffer.rb +56 -0
- data/lib/new_relic/agent/transaction/force_persist_sample_buffer.rb +25 -0
- data/lib/new_relic/agent/transaction/slowest_sample_buffer.rb +25 -0
- data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +86 -0
- data/lib/new_relic/agent/transaction/xray_sample_buffer.rb +64 -0
- data/lib/new_relic/agent/transaction.rb +25 -4
- data/lib/new_relic/agent/transaction_sample_builder.rb +6 -10
- data/lib/new_relic/agent/transaction_sampler.rb +47 -202
- data/lib/new_relic/agent/worker_loop.rb +47 -39
- data/lib/new_relic/agent.rb +1 -1
- data/lib/new_relic/build.rb +2 -2
- data/lib/new_relic/coerce.rb +8 -0
- data/lib/new_relic/control/instance_methods.rb +1 -0
- data/lib/new_relic/rack/browser_monitoring.rb +15 -1
- data/lib/new_relic/rack/developer_mode.rb +1 -1
- data/lib/new_relic/transaction_sample.rb +20 -5
- data/lib/new_relic/version.rb +1 -1
- data/newrelic.yml +4 -6
- data/newrelic_rpm.gemspec +1 -1
- data/test/agent_helper.rb +11 -0
- data/test/environments/lib/environments/runner.rb +5 -1
- data/test/environments/rails21/Gemfile +2 -2
- data/test/environments/rails22/Gemfile +2 -2
- data/test/environments/rails23/Gemfile +2 -2
- data/test/environments/rails31/Gemfile +2 -2
- data/test/environments/rails32/Gemfile +2 -2
- data/test/multiverse/suites/agent_only/marshaling_test.rb +1 -1
- data/test/multiverse/suites/agent_only/testing_app.rb +6 -0
- data/test/multiverse/suites/agent_only/thread_profiling_test.rb +5 -5
- data/test/multiverse/suites/agent_only/xray_sessions_test.rb +163 -0
- data/test/multiverse/suites/rails/request_statistics_test.rb +2 -2
- data/test/multiverse/suites/rails/view_instrumentation_test.rb +20 -21
- data/test/new_relic/agent/agent/connect_test.rb +0 -10
- data/test/new_relic/agent/agent_test.rb +27 -44
- data/test/new_relic/agent/browser_monitoring_test.rb +0 -52
- data/test/new_relic/agent/commands/agent_command_router_test.rb +150 -12
- data/test/new_relic/agent/commands/{thread_profiler_test.rb → thread_profiler_session_test.rb} +58 -19
- data/test/new_relic/agent/commands/xray_session_collection_test.rb +332 -0
- data/test/new_relic/agent/commands/xray_session_test.rb +42 -0
- data/test/new_relic/agent/configuration/manager_test.rb +2 -1
- data/test/new_relic/agent/configuration/server_source_test.rb +10 -10
- data/test/new_relic/agent/cpu_sampler_test.rb +50 -0
- data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +31 -0
- data/test/new_relic/agent/instrumentation/queue_time_test.rb +0 -1
- data/test/new_relic/agent/instrumentation/sequel_test.rb +1 -1
- data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +0 -1
- data/test/new_relic/agent/memory_logger_test.rb +53 -0
- data/test/new_relic/agent/new_relic_service_test.rb +1 -1
- data/test/new_relic/agent/pipe_channel_manager_test.rb +4 -5
- data/test/new_relic/agent/request_sampler_test.rb +70 -20
- data/test/new_relic/agent/rules_engine_test.rb +6 -0
- data/test/new_relic/agent/threading/agent_thread_test.rb +2 -2
- data/test/new_relic/agent/threading/backtrace_node_test.rb +110 -17
- data/test/new_relic/agent/threading/backtrace_service_test.rb +567 -0
- data/test/new_relic/agent/threading/fake_thread.rb +4 -0
- data/test/new_relic/agent/threading/thread_profile_test.rb +141 -217
- data/test/new_relic/agent/threading/threaded_test_case.rb +3 -8
- data/test/new_relic/agent/transaction/developer_mode_sample_buffer_test.rb +69 -0
- data/test/new_relic/agent/transaction/force_persist_sample_buffer_test.rb +52 -0
- data/test/new_relic/agent/transaction/slowest_sample_buffer_test.rb +67 -0
- data/test/new_relic/agent/transaction/xray_sample_buffer_test.rb +71 -0
- data/test/new_relic/agent/transaction_sampler_test.rb +171 -307
- data/test/new_relic/agent/transaction_test.rb +33 -5
- data/test/new_relic/agent/worker_loop_test.rb +33 -11
- data/test/new_relic/coerce_test.rb +13 -0
- data/test/new_relic/fake_collector.rb +26 -3
- data/test/new_relic/multiverse_helpers.rb +2 -0
- data/test/new_relic/rack/browser_monitoring_test.rb +12 -0
- data/test/new_relic/rack/developer_mode_test.rb +2 -2
- data/test/new_relic/transaction_sample_test.rb +19 -2
- data/test/performance/lib/performance/console_reporter.rb +1 -1
- data/test/performance/lib/performance/test_case.rb +7 -3
- data/test/performance/script/runner +3 -0
- data/test/performance/suites/thread_profiling.rb +83 -0
- data/test/test_helper.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +32 -32
- metadata.gz.sig +1 -1
- 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
|
-
@
|
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
|
-
#
|
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
|
-
|
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 "
|
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
|
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
|
1049
|
-
@
|
1050
|
-
|
1051
|
-
|
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.
|
1091
|
-
|
1092
|
-
|
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
|
1096
|
-
@agent_command_router.
|
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
|
-
|
1112
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
191
|
-
|
192
|
-
|
195
|
+
user = obfuscate(config, transaction_attribute(:user))
|
196
|
+
account = obfuscate(config, transaction_attribute(:account))
|
197
|
+
product = obfuscate(config, transaction_attribute(:product))
|
193
198
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
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(
|
12
|
-
@id =
|
13
|
-
@name =
|
14
|
-
@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
|
-
|
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
|
-
|
22
|
-
@
|
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
|
30
|
-
|
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(
|
102
|
+
def invoke_commands(agent_commands)
|
41
103
|
results = {}
|
42
104
|
|
43
|
-
|
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)
|