newrelic_rpm 3.3.5 → 3.4.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of newrelic_rpm might be problematic. Click here for more details.
- data/CHANGELOG +8 -5
- data/lib/new_relic/agent.rb +11 -3
- data/lib/new_relic/agent/agent.rb +68 -223
- data/lib/new_relic/agent/error_collector.rb +1 -1
- data/lib/new_relic/agent/instrumentation/resque.rb +80 -0
- data/lib/new_relic/agent/instrumentation/sinatra.rb +2 -0
- data/lib/new_relic/agent/new_relic_service.rb +221 -0
- data/lib/new_relic/agent/pipe_channel_manager.rb +151 -0
- data/lib/new_relic/agent/pipe_service.rb +57 -0
- data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +4 -34
- data/lib/new_relic/agent/sql_sampler.rb +1 -5
- data/lib/new_relic/agent/stats_engine/transactions.rb +2 -2
- data/lib/new_relic/agent/transaction_sampler.rb +0 -2
- data/lib/new_relic/control/configuration.rb +1 -1
- data/lib/new_relic/control/instance_methods.rb +2 -1
- data/lib/new_relic/language_support.rb +26 -0
- data/lib/new_relic/transaction_sample.rb +2 -6
- data/lib/new_relic/version.rb +3 -3
- data/newrelic_rpm.gemspec +16 -5
- data/test/new_relic/agent/agent/connect_test.rb +39 -23
- data/test/new_relic/agent/agent_test.rb +25 -4
- data/test/new_relic/agent/database_test.rb +12 -0
- data/test/new_relic/agent/new_relic_service_test.rb +151 -0
- data/test/new_relic/agent/pipe_channel_manager_test.rb +114 -0
- data/test/new_relic/agent/pipe_service_test.rb +113 -0
- data/test/new_relic/agent/rpm_agent_test.rb +3 -30
- data/test/new_relic/agent/transaction_sample_builder_test.rb +0 -1
- data/test/new_relic/agent/transaction_sampler_test.rb +6 -6
- data/test/new_relic/agent/worker_loop_test.rb +2 -2
- data/test/new_relic/agent_test.rb +73 -3
- data/test/new_relic/control/configuration_test.rb +0 -7
- data/test/new_relic/control_test.rb +3 -3
- data/test/new_relic/delayed_job_injection_test.rb +6 -1
- data/test/new_relic/fake_collector.rb +210 -0
- data/test/new_relic/fake_service.rb +44 -0
- data/test/script/ci.sh +6 -6
- data/test/script/ci_agent-tests_runner.sh +82 -0
- data/test/script/ci_multiverse_runner.sh +35 -0
- data/test/test_contexts.rb +1 -0
- data/test/test_helper.rb +3 -1
- metadata +359 -324
data/CHANGELOG
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
v3.4.0
|
2
|
+
* Major refactor of data transmission mechanism. This enabled child processes to send data to parent processes, which then send the data to the New Relic service. This should only affect Resque users, dramatically improving their experience.
|
3
|
+
* Moved Resque instrumentation from rpm_contrib to main agent. Resque users should discontinue use of rpm_contrib or upgrade to 2.1.11.
|
4
|
+
|
1
5
|
v3.3.5
|
2
|
-
* [FIX] Allow tracing of
|
6
|
+
* [FIX] Allow tracing of ! and ? methods
|
3
7
|
* [PERF] Give up after scanning first 50k of the response in RUM
|
4
8
|
auto-instrumentation.
|
5
|
-
* [FIX] Don't raise when extracting metrics from SQL queries with non UTF-8
|
6
|
-
* Replaced "Custom/DJ Locked Jobs" metric with new metrics for
|
9
|
+
* [FIX] Don't raise when extracting metrics from SQL queries with non UTF-8
|
10
|
+
* bytes. Replaced "Custom/DJ Locked Jobs" metric with three new metrics for
|
7
11
|
monitoring DelayedJob: queue_length, failed_jobs, and locked_jobs, all under
|
8
|
-
Workers/DelayedJob
|
9
|
-
depending on the version of DelayedJob deployed.
|
12
|
+
Workers/DelayedJob
|
10
13
|
|
11
14
|
v3.3.4.1
|
12
15
|
* Bug fix when rendering empty collection in Rails 3.1+
|
data/lib/new_relic/agent.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
require 'new_relic/control'
|
2
3
|
require 'new_relic/data_serialization'
|
4
|
+
|
3
5
|
# = New Relic Ruby Agent
|
4
6
|
#
|
5
7
|
# New Relic is a performance monitoring application for applications
|
@@ -58,7 +60,8 @@ module NewRelic
|
|
58
60
|
# support at New Relic for help.
|
59
61
|
module Agent
|
60
62
|
extend self
|
61
|
-
|
63
|
+
extend Forwardable
|
64
|
+
|
62
65
|
require 'new_relic/version'
|
63
66
|
require 'new_relic/local_environment'
|
64
67
|
require 'new_relic/stats'
|
@@ -86,6 +89,7 @@ module NewRelic
|
|
86
89
|
require 'new_relic/agent/busy_calculator'
|
87
90
|
require 'new_relic/agent/sampler'
|
88
91
|
require 'new_relic/agent/database'
|
92
|
+
require 'new_relic/agent/pipe_channel_manager'
|
89
93
|
require 'new_relic/agent/transaction_info'
|
90
94
|
|
91
95
|
require 'new_relic/agent/instrumentation/controller_instrumentation'
|
@@ -152,7 +156,7 @@ module NewRelic
|
|
152
156
|
# a standard output logger is returned.
|
153
157
|
def logger
|
154
158
|
control = NewRelic::Control.instance(false)
|
155
|
-
if control
|
159
|
+
if control && control.log
|
156
160
|
control.log
|
157
161
|
else
|
158
162
|
require 'logger'
|
@@ -177,6 +181,9 @@ module NewRelic
|
|
177
181
|
#
|
178
182
|
def manual_start(options={})
|
179
183
|
raise "Options must be a hash" unless Hash === options
|
184
|
+
if options[:start_channel_listener]
|
185
|
+
NewRelic::Agent::PipeChannelManager.listener.start
|
186
|
+
end
|
180
187
|
NewRelic::Control.instance.init_plugin({ :agent_enabled => true, :sync_startup => true }.merge(options))
|
181
188
|
end
|
182
189
|
|
@@ -462,6 +469,7 @@ module NewRelic
|
|
462
469
|
def browser_timing_footer
|
463
470
|
agent.browser_timing_footer
|
464
471
|
end
|
465
|
-
|
472
|
+
|
473
|
+
def_delegator :'NewRelic::Agent::PipeChannelManager', :register_report_channel
|
466
474
|
end
|
467
475
|
end
|
@@ -5,6 +5,8 @@ require 'logger'
|
|
5
5
|
require 'zlib'
|
6
6
|
require 'stringio'
|
7
7
|
require 'new_relic/data_serialization'
|
8
|
+
require 'new_relic/agent/new_relic_service'
|
9
|
+
require 'new_relic/agent/pipe_service'
|
8
10
|
|
9
11
|
module NewRelic
|
10
12
|
module Agent
|
@@ -14,22 +16,7 @@ module NewRelic
|
|
14
16
|
# in realtime as the application runs, and periodically sends that
|
15
17
|
# data to the NewRelic server.
|
16
18
|
class Agent
|
17
|
-
|
18
|
-
# Specifies the version of the agent's communication protocol with
|
19
|
-
# the NewRelic hosted site.
|
20
|
-
|
21
|
-
PROTOCOL_VERSION = 8
|
22
|
-
# 14105: v8 (tag 2.10.3)
|
23
|
-
# (no v7)
|
24
|
-
# 10379: v6 (not tagged)
|
25
|
-
# 4078: v5 (tag 2.5.4)
|
26
|
-
# 2292: v4 (tag 2.3.6)
|
27
|
-
# 1754: v3 (tag 2.3.0)
|
28
|
-
# 534: v2 (shows up in 2.1.0, our first tag)
|
29
|
-
|
30
|
-
|
31
19
|
def initialize
|
32
|
-
|
33
20
|
@launch_time = Time.now
|
34
21
|
|
35
22
|
@metric_ids = {}
|
@@ -40,12 +27,13 @@ module NewRelic
|
|
40
27
|
@error_collector = NewRelic::Agent::ErrorCollector.new
|
41
28
|
@connect_attempts = 0
|
42
29
|
|
43
|
-
@request_timeout = NewRelic::Control.instance.fetch('timeout', 2 * 60)
|
44
|
-
|
45
30
|
@last_harvest_time = Time.now
|
46
31
|
@obfuscator = lambda {|sql| NewRelic::Agent::Database.default_sql_obfuscator(sql) }
|
32
|
+
@forked = false
|
33
|
+
|
34
|
+
@service = NewRelic::Agent::NewRelicService.new(control.license_key, control.server)
|
47
35
|
end
|
48
|
-
|
36
|
+
|
49
37
|
# contains all the class-level methods for NewRelic::Agent::Agent
|
50
38
|
module ClassMethods
|
51
39
|
# Should only be called by NewRelic::Control - returns a
|
@@ -81,6 +69,7 @@ module NewRelic
|
|
81
69
|
# handles things like static setup of the header for inclusion
|
82
70
|
# into pages
|
83
71
|
attr_reader :beacon_configuration
|
72
|
+
attr_accessor :service
|
84
73
|
|
85
74
|
# Returns the length of the unsent errors array, if it exists,
|
86
75
|
# otherwise nil
|
@@ -158,11 +147,16 @@ module NewRelic
|
|
158
147
|
# connection, this tells me to only try it once so this method returns
|
159
148
|
# quickly if there is some kind of latency with the server.
|
160
149
|
def after_fork(options={})
|
161
|
-
|
150
|
+
@forked = true
|
162
151
|
# @connected gets false after we fail to connect or have an error
|
163
152
|
# connecting. @connected has nil if we haven't finished trying to connect.
|
164
153
|
# or we didn't attempt a connection because this is the master process
|
165
|
-
|
154
|
+
|
155
|
+
if channel_id = options[:report_to_channel]
|
156
|
+
@service = NewRelic::Agent::PipeService.new(channel_id)
|
157
|
+
@connected_pid = $$
|
158
|
+
end
|
159
|
+
|
166
160
|
# log.debug "Agent received after_fork notice in #$$: [#{control.agent_enabled?}; monitor=#{control.monitor_mode?}; connected: #{@connected.inspect}; thread=#{@worker_thread.inspect}]"
|
167
161
|
return if !control.agent_enabled? or
|
168
162
|
!control.monitor_mode? or
|
@@ -179,7 +173,11 @@ module NewRelic
|
|
179
173
|
start_worker_thread(options)
|
180
174
|
@stats_engine.start_sampler_thread
|
181
175
|
end
|
182
|
-
|
176
|
+
|
177
|
+
def forked?
|
178
|
+
@forked
|
179
|
+
end
|
180
|
+
|
183
181
|
# True if we have initialized and completed 'start'
|
184
182
|
def started?
|
185
183
|
@started
|
@@ -203,25 +201,25 @@ module NewRelic
|
|
203
201
|
if @worker_loop
|
204
202
|
@worker_loop.run_task if run_loop_before_exit
|
205
203
|
@worker_loop.stop
|
204
|
+
end
|
206
205
|
|
207
|
-
|
206
|
+
log.debug "Starting Agent shutdown"
|
208
207
|
|
209
|
-
|
210
|
-
|
208
|
+
# if litespeed, then ignore all future SIGUSR1 - it's
|
209
|
+
# litespeed trying to shut us down
|
211
210
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
211
|
+
if control.dispatcher == :litespeed
|
212
|
+
Signal.trap("SIGUSR1", "IGNORE")
|
213
|
+
Signal.trap("SIGTERM", "IGNORE")
|
214
|
+
end
|
216
215
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
end
|
221
|
-
rescue => e
|
222
|
-
log.error e
|
223
|
-
log.error e.backtrace.join("\n")
|
216
|
+
begin
|
217
|
+
NewRelic::Agent.disable_all_tracing do
|
218
|
+
graceful_disconnect
|
224
219
|
end
|
220
|
+
rescue => e
|
221
|
+
log.error e
|
222
|
+
log.error e.backtrace.join("\n")
|
225
223
|
end
|
226
224
|
@started = nil
|
227
225
|
end
|
@@ -446,9 +444,9 @@ module NewRelic
|
|
446
444
|
end
|
447
445
|
|
448
446
|
private
|
449
|
-
|
450
|
-
|
451
|
-
|
447
|
+
# def collector
|
448
|
+
# @collector ||= control.collector
|
449
|
+
# end
|
452
450
|
|
453
451
|
# All of this module used to be contained in the
|
454
452
|
# start_worker_thread method - this is an artifact of
|
@@ -717,7 +715,7 @@ module NewRelic
|
|
717
715
|
# connect data passed back from the server
|
718
716
|
def connect_to_server
|
719
717
|
log_seed_token
|
720
|
-
|
718
|
+
@service.connect(connect_settings)
|
721
719
|
end
|
722
720
|
|
723
721
|
# Configures the error collector if the server says that we
|
@@ -834,18 +832,16 @@ module NewRelic
|
|
834
832
|
# should be reporting to, and then does the name resolution
|
835
833
|
# on that host so we don't block on DNS during the normal
|
836
834
|
# course of agent processing
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
835
|
+
# def set_collector_host!
|
836
|
+
# host = invoke_remote(:get_redirect_host)
|
837
|
+
# if host
|
838
|
+
# @collector = control.server_from_host(host)
|
839
|
+
# end
|
840
|
+
# end
|
843
841
|
|
844
842
|
# Sets the collector host and connects to the server, then
|
845
843
|
# invokes the final configuration with the returned data
|
846
844
|
def query_server_for_configuration
|
847
|
-
set_collector_host!
|
848
|
-
|
849
845
|
finish_setup(connect_to_server)
|
850
846
|
end
|
851
847
|
|
@@ -857,7 +853,8 @@ module NewRelic
|
|
857
853
|
# Can accommodate most arbitrary data - anything extra is
|
858
854
|
# ignored unless we say to do something with it here.
|
859
855
|
def finish_setup(config_data)
|
860
|
-
|
856
|
+
return if config_data == nil
|
857
|
+
@service.agent_id = config_data['agent_run_id']
|
861
858
|
@report_period = config_data['data_report_period']
|
862
859
|
@url_rules = config_data['url_rules']
|
863
860
|
@beacon_configuration = BeaconConfiguration.new(config_data)
|
@@ -878,8 +875,8 @@ module NewRelic
|
|
878
875
|
# Logs when we connect to the server, for debugging purposes
|
879
876
|
# - makes sure we know if an agent has not connected
|
880
877
|
def log_connection!(config_data)
|
881
|
-
control.log! "Connected to NewRelic Service at #{@collector}"
|
882
|
-
log.debug "Agent Run = #{@agent_id}."
|
878
|
+
control.log! "Connected to NewRelic Service at #{@service.collector.name}"
|
879
|
+
log.debug "Agent Run = #{@service.agent_id}."
|
883
880
|
log.debug "Connection data = #{config_data.inspect}"
|
884
881
|
end
|
885
882
|
end
|
@@ -909,14 +906,15 @@ module NewRelic
|
|
909
906
|
def merge_data_from(data)
|
910
907
|
metrics, transaction_traces, errors = data
|
911
908
|
@stats_engine.merge_data(metrics) if metrics
|
912
|
-
if transaction_traces
|
909
|
+
if transaction_traces && transaction_traces.respond_to?(:any?) &&
|
910
|
+
transaction_traces.any?
|
913
911
|
if @traces
|
914
|
-
@traces
|
912
|
+
@traces += transaction_traces
|
915
913
|
else
|
916
914
|
@traces = transaction_traces
|
917
915
|
end
|
918
916
|
end
|
919
|
-
if errors
|
917
|
+
if errors && errors.respond_to?(:any?) && errors.any?
|
920
918
|
if @unsent_errors
|
921
919
|
@unsent_errors = @unsent_errors + errors
|
922
920
|
else
|
@@ -1014,22 +1012,14 @@ module NewRelic
|
|
1014
1012
|
NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote').record_data_point(0.0)
|
1015
1013
|
NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote/metric_data').record_data_point(0.0)
|
1016
1014
|
harvest_timeslice_data(now)
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
@unsent_timeslice_data.values)
|
1023
|
-
|
1024
|
-
rescue Timeout::Error
|
1025
|
-
# assume that the data was received. chances are that it
|
1026
|
-
# was. Also, lol.
|
1027
|
-
metric_specs_and_ids = []
|
1028
|
-
end
|
1029
|
-
|
1015
|
+
# In this version of the protocol, we get back an assoc array of spec to id.
|
1016
|
+
metric_specs_and_ids = @service.metric_data(@last_harvest_time.to_f,
|
1017
|
+
now.to_f,
|
1018
|
+
@unsent_timeslice_data.values)
|
1019
|
+
metric_specs_and_ids ||= []
|
1030
1020
|
fill_metric_id_cache(metric_specs_and_ids)
|
1031
1021
|
|
1032
|
-
log.debug "#{now}: sent #{@unsent_timeslice_data.length} timeslices (#{@agent_id}) in #{Time.now - now} seconds"
|
1022
|
+
log.debug "#{now}: sent #{@unsent_timeslice_data.length} timeslices (#{@service.agent_id}) in #{Time.now - now} seconds"
|
1033
1023
|
|
1034
1024
|
# if we successfully invoked this web service, then clear the unsent message cache.
|
1035
1025
|
@unsent_timeslice_data = {}
|
@@ -1050,8 +1040,7 @@ module NewRelic
|
|
1050
1040
|
unless sql_traces.empty?
|
1051
1041
|
log.debug "Sending (#{sql_traces.size}) sql traces"
|
1052
1042
|
begin
|
1053
|
-
|
1054
|
-
# log.debug "Sql trace response: #{response}"
|
1043
|
+
@service.sql_trace_data(sql_traces)
|
1055
1044
|
rescue
|
1056
1045
|
@sql_sampler.merge sql_traces
|
1057
1046
|
end
|
@@ -1077,14 +1066,14 @@ module NewRelic
|
|
1077
1066
|
options[:explain_sql] = @transaction_sampler.explain_threshold
|
1078
1067
|
end
|
1079
1068
|
traces = @traces.collect {|trace| trace.prepare_to_send(options)}
|
1080
|
-
|
1069
|
+
@service.transaction_sample_data(traces)
|
1081
1070
|
rescue PostTooBigException
|
1082
1071
|
# we tried to send too much data, drop the first trace and
|
1083
1072
|
# try again
|
1084
1073
|
retry if @traces.shift
|
1085
1074
|
end
|
1086
1075
|
|
1087
|
-
log.debug "Sent slowest sample (#{@agent_id}) in #{Time.now - now} seconds"
|
1076
|
+
log.debug "Sent slowest sample (#{@service.agent_id}) in #{Time.now - now} seconds"
|
1088
1077
|
end
|
1089
1078
|
|
1090
1079
|
# if we succeed sending this sample, then we don't need to keep
|
@@ -1110,7 +1099,7 @@ module NewRelic
|
|
1110
1099
|
if @unsent_errors && @unsent_errors.length > 0
|
1111
1100
|
log.debug "Sending #{@unsent_errors.length} errors"
|
1112
1101
|
begin
|
1113
|
-
|
1102
|
+
@service.error_data(@unsent_errors)
|
1114
1103
|
rescue PostTooBigException
|
1115
1104
|
@unsent_errors.shift
|
1116
1105
|
retry
|
@@ -1122,153 +1111,7 @@ module NewRelic
|
|
1122
1111
|
@unsent_errors = []
|
1123
1112
|
end
|
1124
1113
|
end
|
1125
|
-
|
1126
|
-
# This method handles the compression of the request body that
|
1127
|
-
# we are going to send to the server
|
1128
|
-
#
|
1129
|
-
# We currently optimize for CPU here since we get roughly a 10x
|
1130
|
-
# reduction in message size with this, and CPU overhead is at a
|
1131
|
-
# premium. For extra-large posts, we use the higher compression
|
1132
|
-
# since otherwise it actually errors out.
|
1133
|
-
#
|
1134
|
-
# We do not compress if content is smaller than 64kb. There are
|
1135
|
-
# problems with bugs in Ruby in some versions that expose us
|
1136
|
-
# to a risk of segfaults if we compress aggressively.
|
1137
|
-
#
|
1138
|
-
# medium payloads get fast compression, to save CPU
|
1139
|
-
# big payloads get all the compression possible, to stay under
|
1140
|
-
# the 2,000,000 byte post threshold
|
1141
|
-
def compress_data(object)
|
1142
|
-
dump = Marshal.dump(object)
|
1143
|
-
|
1144
|
-
dump_size = dump.size
|
1145
|
-
|
1146
|
-
return [dump, 'identity'] if dump_size < (64*1024)
|
1147
|
-
|
1148
|
-
compressed_dump = Zlib::Deflate.deflate(dump, Zlib::DEFAULT_COMPRESSION)
|
1149
|
-
|
1150
|
-
# this checks to make sure mongrel won't choke on big uploads
|
1151
|
-
check_post_size(compressed_dump)
|
1152
|
-
|
1153
|
-
[compressed_dump, 'deflate']
|
1154
|
-
end
|
1155
|
-
|
1156
|
-
# Raises a PostTooBigException if the post_string is longer
|
1157
|
-
# than the limit configured in the control object
|
1158
|
-
def check_post_size(post_string)
|
1159
|
-
# TODO: define this as a config option on the server side
|
1160
|
-
return if post_string.size < control.post_size_limit
|
1161
|
-
log.warn "Tried to send too much data: #{post_string.size} bytes"
|
1162
|
-
raise PostTooBigException
|
1163
|
-
end
|
1164
|
-
|
1165
|
-
# Posts to the specified server
|
1166
|
-
#
|
1167
|
-
# Options:
|
1168
|
-
# - :uri => the path to request on the server (a misnomer of
|
1169
|
-
# course)
|
1170
|
-
# - :encoding => the encoding to pass to the server
|
1171
|
-
# - :collector => a URI object that responds to the 'name' method
|
1172
|
-
# and returns the name of the collector to
|
1173
|
-
# contact
|
1174
|
-
# - :data => the data to send as the body of the request
|
1175
|
-
def send_request(opts)
|
1176
|
-
request = Net::HTTP::Post.new(opts[:uri], 'CONTENT-ENCODING' => opts[:encoding], 'HOST' => opts[:collector].name)
|
1177
|
-
request['user-agent'] = user_agent
|
1178
|
-
request.content_type = "application/octet-stream"
|
1179
|
-
request.body = opts[:data]
|
1180
|
-
|
1181
|
-
log.debug "Connect to #{opts[:collector]}#{opts[:uri]}"
|
1182
|
-
|
1183
|
-
response = nil
|
1184
|
-
http = control.http_connection(collector)
|
1185
|
-
http.read_timeout = nil
|
1186
|
-
begin
|
1187
|
-
NewRelic::TimerLib.timeout(@request_timeout) do
|
1188
|
-
response = http.request(request)
|
1189
|
-
end
|
1190
|
-
rescue Timeout::Error
|
1191
|
-
log.warn "Timed out trying to post data to New Relic (timeout = #{@request_timeout} seconds)" unless @request_timeout < 30
|
1192
|
-
raise
|
1193
|
-
end
|
1194
|
-
if response.is_a? Net::HTTPServiceUnavailable
|
1195
|
-
raise NewRelic::Agent::ServerConnectionException, "Service unavailable (#{response.code}): #{response.message}"
|
1196
|
-
elsif response.is_a? Net::HTTPGatewayTimeOut
|
1197
|
-
log.debug("Timed out getting response: #{response.message}")
|
1198
|
-
raise Timeout::Error, response.message
|
1199
|
-
elsif response.is_a? Net::HTTPRequestEntityTooLarge
|
1200
|
-
raise PostTooBigException
|
1201
|
-
elsif !(response.is_a? Net::HTTPSuccess)
|
1202
|
-
raise NewRelic::Agent::ServerConnectionException, "Unexpected response from server (#{response.code}): #{response.message}"
|
1203
|
-
end
|
1204
|
-
response
|
1205
|
-
end
|
1206
|
-
|
1207
|
-
# Decompresses the response from the server, if it is gzip
|
1208
|
-
# encoded, otherwise returns it verbatim
|
1209
|
-
def decompress_response(response)
|
1210
|
-
if response['content-encoding'] != 'gzip'
|
1211
|
-
log.debug "Uncompressed content returned"
|
1212
|
-
return response.body
|
1213
|
-
end
|
1214
|
-
log.debug "Decompressing return value"
|
1215
|
-
i = Zlib::GzipReader.new(StringIO.new(response.body))
|
1216
|
-
i.read
|
1217
|
-
end
|
1218
|
-
|
1219
|
-
# unmarshals the response and raises it if it is an exception,
|
1220
|
-
# so we can handle it in nonlocally
|
1221
|
-
def check_for_exception(response)
|
1222
|
-
dump = decompress_response(response)
|
1223
|
-
value = Marshal.load(dump)
|
1224
|
-
raise value if value.is_a? Exception
|
1225
|
-
value
|
1226
|
-
end
|
1227
|
-
|
1228
|
-
# The path on the server that we should post our data to
|
1229
|
-
def remote_method_uri(method)
|
1230
|
-
uri = "/agent_listener/#{PROTOCOL_VERSION}/#{control.license_key}/#{method}"
|
1231
|
-
uri << "?run_id=#{@agent_id}" if @agent_id
|
1232
|
-
uri
|
1233
|
-
end
|
1234
|
-
|
1235
|
-
# Sets the user agent for connections to the server, to
|
1236
|
-
# conform with the HTTP spec and allow for debugging. Includes
|
1237
|
-
# the ruby version and also zlib version if available since
|
1238
|
-
# that may cause corrupt compression if there is a problem.
|
1239
|
-
def user_agent
|
1240
|
-
ruby_description = ''
|
1241
|
-
# note the trailing space!
|
1242
|
-
ruby_description << "(ruby #{::RUBY_VERSION} #{::RUBY_PLATFORM}) " if defined?(::RUBY_VERSION) && defined?(::RUBY_PLATFORM)
|
1243
|
-
zlib_version = ''
|
1244
|
-
zlib_version << "zlib/#{Zlib.zlib_version}" if defined?(::Zlib) && Zlib.respond_to?(:zlib_version)
|
1245
|
-
"NewRelic-RubyAgent/#{NewRelic::VERSION::STRING} #{ruby_description}#{zlib_version}"
|
1246
|
-
end
|
1247
|
-
|
1248
|
-
# send a message via post to the actual server. This attempts
|
1249
|
-
# to automatically compress the data via zlib if it is large
|
1250
|
-
# enough to be worth compressing, and handles any errors the
|
1251
|
-
# server may return
|
1252
|
-
def invoke_remote(method, *args)
|
1253
|
-
now = Time.now
|
1254
|
-
#determines whether to zip the data or send plain
|
1255
|
-
post_data, encoding = compress_data(args)
|
1256
|
-
|
1257
|
-
response = send_request({:uri => remote_method_uri(method), :encoding => encoding, :collector => collector, :data => post_data})
|
1258
|
-
|
1259
|
-
# raises the right exception if the remote server tells it to die
|
1260
|
-
return check_for_exception(response)
|
1261
|
-
rescue NewRelic::Agent::ForceRestartException => e
|
1262
|
-
log.info e.message
|
1263
|
-
raise
|
1264
|
-
rescue SystemCallError, SocketError => e
|
1265
|
-
# These include Errno connection errors
|
1266
|
-
raise NewRelic::Agent::ServerConnectionException, "Recoverable error connecting to the server: #{e}"
|
1267
|
-
ensure
|
1268
|
-
NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote').record_data_point((Time.now - now).to_f)
|
1269
|
-
NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote/' + method.to_s).record_data_point((Time.now - now).to_f)
|
1270
|
-
end
|
1271
|
-
|
1114
|
+
|
1272
1115
|
def save_or_transmit_data
|
1273
1116
|
if NewRelic::DataSerialization.should_send_data?
|
1274
1117
|
log.debug "Sending data to New Relic Service"
|
@@ -1288,6 +1131,8 @@ module NewRelic
|
|
1288
1131
|
retry_count += 1
|
1289
1132
|
retry unless retry_count > 1
|
1290
1133
|
raise e
|
1134
|
+
ensure
|
1135
|
+
NewRelic::Agent::Database.close_connections unless forked?
|
1291
1136
|
end
|
1292
1137
|
|
1293
1138
|
# This method contacts the server to send remaining data and
|
@@ -1300,11 +1145,11 @@ module NewRelic
|
|
1300
1145
|
def graceful_disconnect
|
1301
1146
|
if @connected
|
1302
1147
|
begin
|
1303
|
-
@request_timeout = 10
|
1148
|
+
@service.request_timeout = 10
|
1304
1149
|
save_or_transmit_data
|
1305
|
-
if @connected_pid == $$
|
1150
|
+
if @connected_pid == $$ && !@service.kind_of?(NewRelic::Agent::NewRelicService)
|
1306
1151
|
log.debug "Sending New Relic service agent run shutdown message"
|
1307
|
-
|
1152
|
+
@service.shutdown(Time.now.to_f)
|
1308
1153
|
else
|
1309
1154
|
log.debug "This agent connected from parent process #{@connected_pid}--not sending shutdown"
|
1310
1155
|
end
|
@@ -1316,7 +1161,7 @@ module NewRelic
|
|
1316
1161
|
end
|
1317
1162
|
end
|
1318
1163
|
end
|
1319
|
-
|
1164
|
+
|
1320
1165
|
extend ClassMethods
|
1321
1166
|
include InstanceMethods
|
1322
1167
|
include BrowserMonitoring
|