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
@@ -119,6 +119,10 @@ module NewRelic
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
+
def name_set?
|
123
|
+
@name && @name != NewRelic::Agent::UNKNOWN_METRIC
|
124
|
+
end
|
125
|
+
|
122
126
|
def freeze_name
|
123
127
|
return if name_frozen?
|
124
128
|
@name = NewRelic::Agent.instance.transaction_rules.rename(@name)
|
@@ -144,6 +148,8 @@ module NewRelic
|
|
144
148
|
# Indicate that we are entering a measured controller action or task.
|
145
149
|
# Make sure you unwind every push with a pop call.
|
146
150
|
def start(transaction_type)
|
151
|
+
@name = NewRelic::Agent::UNKNOWN_METRIC
|
152
|
+
|
147
153
|
transaction_sampler.notice_first_scope_push(start_time)
|
148
154
|
sql_sampler.notice_first_scope_push(start_time)
|
149
155
|
|
@@ -177,8 +183,8 @@ module NewRelic
|
|
177
183
|
|
178
184
|
# Unwind one stack level. It knows if it's back at the outermost caller and
|
179
185
|
# does the appropriate wrapup of the context.
|
180
|
-
def stop(
|
181
|
-
@name
|
186
|
+
def stop(fallback_name=::NewRelic::Agent::UNKNOWN_METRIC, end_time=Time.now)
|
187
|
+
@name = fallback_name unless name_set? || name_frozen?
|
182
188
|
freeze_name
|
183
189
|
log_underflow if @type.nil?
|
184
190
|
|
@@ -200,11 +206,22 @@ module NewRelic
|
|
200
206
|
|
201
207
|
# these tear everything down so need to be done after merging stats
|
202
208
|
if self.root?
|
203
|
-
|
209
|
+
send_transaction_finished_event(start_time, end_time, overview_metrics)
|
204
210
|
agent.stats_engine.end_transaction
|
205
211
|
end
|
206
212
|
end
|
207
213
|
|
214
|
+
def send_transaction_finished_event(start_time, end_time, overview_metrics)
|
215
|
+
payload = {
|
216
|
+
:name => @name,
|
217
|
+
:type => @type,
|
218
|
+
:start_timestamp => start_time.to_f,
|
219
|
+
:duration => end_time.to_f - start_time.to_f,
|
220
|
+
:overview_metrics => overview_metrics
|
221
|
+
}
|
222
|
+
agent.events.notify(:transaction_finished, payload)
|
223
|
+
end
|
224
|
+
|
208
225
|
def merge_stats_hash
|
209
226
|
stats_hash.resolve_scopes!(@name)
|
210
227
|
NewRelic::Agent.instance.stats_engine.merge!(stats_hash)
|
@@ -364,8 +381,12 @@ module NewRelic
|
|
364
381
|
self.current && self.current.recording_web_transaction?
|
365
382
|
end
|
366
383
|
|
384
|
+
def self.transaction_type_is_web?(type)
|
385
|
+
[:controller, :uri, :rack, :sinatra].include?(type)
|
386
|
+
end
|
387
|
+
|
367
388
|
def recording_web_transaction?
|
368
|
-
|
389
|
+
self.class.transaction_type_is_web?(@type)
|
369
390
|
end
|
370
391
|
|
371
392
|
# Make a safe attempt to get the referer from a request object, generally successful when
|
@@ -100,10 +100,10 @@ module NewRelic
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def finish_trace(time=Time.now.to_f, custom_params={})
|
103
|
-
#
|
104
|
-
# log forensics and return gracefully
|
105
|
-
if @sample.
|
106
|
-
::NewRelic::Agent.logger.error "Unexpected double-
|
103
|
+
# Should never get called twice, but in a rare case that we can't
|
104
|
+
# reproduce in house it does. log forensics and return gracefully
|
105
|
+
if @sample.finished
|
106
|
+
::NewRelic::Agent.logger.error "Unexpected double-finish_trace of Transaction Trace Object: \n#{@sample.to_s}"
|
107
107
|
return
|
108
108
|
end
|
109
109
|
@sample.root_segment.end_trace(time.to_f - @sample_start)
|
@@ -112,7 +112,7 @@ module NewRelic
|
|
112
112
|
|
113
113
|
@sample.force_persist = sample.force_persist_sample?
|
114
114
|
@sample.threshold = transaction_trace_threshold
|
115
|
-
@sample.
|
115
|
+
@sample.finished = true
|
116
116
|
@current_segment = nil
|
117
117
|
end
|
118
118
|
|
@@ -139,10 +139,6 @@ module NewRelic
|
|
139
139
|
depth
|
140
140
|
end
|
141
141
|
|
142
|
-
def freeze
|
143
|
-
@sample.freeze unless sample.frozen?
|
144
|
-
end
|
145
|
-
|
146
142
|
def set_profile(profile)
|
147
143
|
@sample.profile = profile
|
148
144
|
end
|
@@ -159,7 +155,7 @@ module NewRelic
|
|
159
155
|
end
|
160
156
|
|
161
157
|
def set_transaction_name(name)
|
162
|
-
@sample.
|
158
|
+
@sample.transaction_name = name
|
163
159
|
end
|
164
160
|
|
165
161
|
def set_transaction_cpu_time(cpu_time)
|
@@ -5,6 +5,10 @@
|
|
5
5
|
require 'new_relic/agent'
|
6
6
|
require 'new_relic/control'
|
7
7
|
require 'new_relic/agent/transaction_sample_builder'
|
8
|
+
require 'new_relic/agent/transaction/developer_mode_sample_buffer'
|
9
|
+
require 'new_relic/agent/transaction/force_persist_sample_buffer'
|
10
|
+
require 'new_relic/agent/transaction/slowest_sample_buffer'
|
11
|
+
require 'new_relic/agent/transaction/xray_sample_buffer'
|
8
12
|
|
9
13
|
module NewRelic
|
10
14
|
module Agent
|
@@ -22,23 +26,17 @@ module NewRelic
|
|
22
26
|
def notice_scope_empty(*args); end
|
23
27
|
end
|
24
28
|
|
25
|
-
|
26
|
-
attr_accessor :slow_capture_threshold
|
27
|
-
attr_reader :samples, :last_sample, :disabled
|
29
|
+
attr_reader :last_sample, :dev_mode_sample_buffer, :xray_sample_buffer
|
28
30
|
|
29
31
|
def initialize
|
32
|
+
@dev_mode_sample_buffer = NewRelic::Agent::Transaction::DeveloperModeSampleBuffer.new
|
33
|
+
@xray_sample_buffer = NewRelic::Agent::Transaction::XraySampleBuffer.new
|
30
34
|
|
31
|
-
|
32
|
-
|
33
|
-
@
|
34
|
-
@
|
35
|
-
@
|
36
|
-
|
37
|
-
# @harvest_count is a count of harvests used for random
|
38
|
-
# sampling - we pull 1 @random_sample in every @sampling_rate harvests
|
39
|
-
@harvest_count = 0
|
40
|
-
@random_sample = nil
|
41
|
-
@sampling_rate = Agent.config[:sample_rate]
|
35
|
+
@sample_buffers = []
|
36
|
+
@sample_buffers << @dev_mode_sample_buffer
|
37
|
+
@sample_buffers << @xray_sample_buffer
|
38
|
+
@sample_buffers << NewRelic::Agent::Transaction::SlowestSampleBuffer.new
|
39
|
+
@sample_buffers << NewRelic::Agent::Transaction::ForcePersistSampleBuffer.new
|
42
40
|
|
43
41
|
# This lock is used to synchronize access to the @last_sample
|
44
42
|
# and related variables. It can become necessary on JRuby or
|
@@ -61,25 +59,10 @@ module NewRelic
|
|
61
59
|
end
|
62
60
|
end
|
63
61
|
|
64
|
-
# Returns the current sample id, delegated from `builder`
|
65
|
-
def current_sample_id
|
66
|
-
b=builder
|
67
|
-
b and b.sample_id
|
68
|
-
end
|
69
|
-
|
70
62
|
def enabled?
|
71
63
|
Agent.config[:'transaction_tracer.enabled'] || Agent.config[:developer_mode]
|
72
64
|
end
|
73
65
|
|
74
|
-
# Set with an integer value n, this takes one in every n
|
75
|
-
# harvested samples. It also resets the harvest count to a
|
76
|
-
# random integer between 0 and (n-1)
|
77
|
-
def sampling_rate=(val)
|
78
|
-
@sampling_rate = val.to_i
|
79
|
-
@harvest_count = rand(val.to_i).to_i
|
80
|
-
end
|
81
|
-
|
82
|
-
|
83
66
|
# Creates a new transaction sample builder, unless the
|
84
67
|
# transaction sampler is disabled. Takes a time parameter for
|
85
68
|
# the start of the transaction sample
|
@@ -97,43 +80,15 @@ module NewRelic
|
|
97
80
|
return unless builder
|
98
81
|
|
99
82
|
segment = builder.trace_entry(time.to_f)
|
100
|
-
|
101
|
-
capture_segment_trace if Agent.config[:developer_mode]
|
102
|
-
|
83
|
+
@sample_buffers.each { |sample_buffer| sample_buffer.visit_segment(segment) }
|
103
84
|
return segment
|
104
85
|
end
|
105
86
|
|
106
|
-
# in developer mode, capture the stack trace with the segment.
|
107
|
-
# this is cpu and memory expensive and therefore should not be
|
108
|
-
# turned on in production mode
|
109
|
-
def capture_segment_trace
|
110
|
-
return unless Agent.config[:developer_mode]
|
111
|
-
segment = builder.current_segment
|
112
|
-
if segment
|
113
|
-
# Strip stack frames off the top that match /new_relic/agent/
|
114
|
-
trace = caller
|
115
|
-
while trace.first =~/\/lib\/new_relic\/agent\//
|
116
|
-
trace.shift
|
117
|
-
end
|
118
|
-
|
119
|
-
trace = trace[0..39] if trace.length > 40
|
120
|
-
segment[:backtrace] = trace
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
# Defaults to zero, otherwise delegated to the transaction
|
125
|
-
# sample builder
|
126
|
-
def scope_depth
|
127
|
-
return 0 unless builder
|
128
|
-
|
129
|
-
builder.scope_depth
|
130
|
-
end
|
131
|
-
|
132
87
|
# Informs the transaction sample builder about the end of a
|
133
88
|
# traced scope
|
134
89
|
def notice_pop_scope(scope, time = Time.now)
|
135
90
|
return unless builder
|
136
|
-
raise "
|
91
|
+
raise "finished already???" if builder.sample.finished
|
137
92
|
builder.trace_exit(scope, time.to_f)
|
138
93
|
end
|
139
94
|
|
@@ -161,72 +116,9 @@ module NewRelic
|
|
161
116
|
end
|
162
117
|
end
|
163
118
|
|
164
|
-
# Samples can be stored in three places: the random sample
|
165
|
-
# variable, when random sampling is active, the developer mode
|
166
|
-
# @samples array, and the @slowest_sample variable if it is
|
167
|
-
# slower than the current occupant of that slot
|
168
119
|
def store_sample(sample)
|
169
|
-
|
170
|
-
|
171
|
-
sampler_methods << :store_sample_for_developer_mode
|
172
|
-
end
|
173
|
-
if Agent.config[:'transaction_tracer.random_sample']
|
174
|
-
sampler_methods << :store_random_sample
|
175
|
-
end
|
176
|
-
|
177
|
-
sampler_methods.each{|sym| send(sym, sample) }
|
178
|
-
|
179
|
-
if sample.force_persist_sample?
|
180
|
-
store_force_persist(sample)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
# Only active when random sampling is true - this is very rarely
|
185
|
-
# used. Always store the most recent sample so that random
|
186
|
-
# sampling can pick a few of the samples to store, upon harvest
|
187
|
-
def store_random_sample(sample)
|
188
|
-
@random_sample = sample if Agent.config[:'transaction_tracer.random_sample']
|
189
|
-
end
|
190
|
-
|
191
|
-
def store_force_persist(sample)
|
192
|
-
@force_persist << sample
|
193
|
-
|
194
|
-
# WARNING - this clamp should be configurable
|
195
|
-
if @force_persist.length > 15
|
196
|
-
@force_persist.sort! {|a,b| b.duration <=> a.duration}
|
197
|
-
@force_persist = @force_persist[0..14]
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
# Samples take up a ton of memory, so we only store a lot of
|
202
|
-
# them in developer mode - we truncate to @max_samples
|
203
|
-
def store_sample_for_developer_mode(sample)
|
204
|
-
return unless Agent.config[:developer_mode]
|
205
|
-
@samples = [] unless @samples
|
206
|
-
@samples << sample
|
207
|
-
truncate_samples
|
208
|
-
end
|
209
|
-
|
210
|
-
# Sets @slowest_sample to the passed in sample if it is slower
|
211
|
-
# than the current sample in @slowest_sample
|
212
|
-
def store_slowest_sample(sample)
|
213
|
-
if slowest_sample?(@slowest_sample, sample) && sample.threshold &&
|
214
|
-
sample.duration >= sample.threshold
|
215
|
-
@slowest_sample = sample
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
# Checks to see if the old sample exists, or if its duration is
|
220
|
-
# less than the new sample
|
221
|
-
def slowest_sample?(old_sample, new_sample)
|
222
|
-
old_sample.nil? || (new_sample.duration > old_sample.duration)
|
223
|
-
end
|
224
|
-
|
225
|
-
# Smashes the @samples array down to the length of @max_samples
|
226
|
-
# by taking the last @max_samples elements of the array
|
227
|
-
def truncate_samples
|
228
|
-
if @samples.length > @max_samples
|
229
|
-
@samples = @samples[-@max_samples..-1]
|
120
|
+
@sample_buffers.each do |sample_buffer|
|
121
|
+
sample_buffer.store(sample)
|
230
122
|
end
|
231
123
|
end
|
232
124
|
|
@@ -329,8 +221,7 @@ module NewRelic
|
|
329
221
|
statement
|
330
222
|
end
|
331
223
|
|
332
|
-
# Adds non-sql metadata to a segment - generally the memcached
|
333
|
-
# key
|
224
|
+
# Adds non-sql metadata to a segment - generally the memcached key
|
334
225
|
#
|
335
226
|
# duration is seconds, float value.
|
336
227
|
def notice_nosql(key, duration)
|
@@ -343,96 +234,50 @@ module NewRelic
|
|
343
234
|
params.each { |k,v| builder.current_segment[k] = v }
|
344
235
|
end
|
345
236
|
|
346
|
-
#
|
347
|
-
#
|
348
|
-
#
|
349
|
-
# result array
|
350
|
-
#
|
351
|
-
# random sampling is very, very seldom used
|
352
|
-
def add_random_sample_to(result)
|
353
|
-
return unless @random_sample &&
|
354
|
-
Agent.config[:sample_rate] && Agent.config[:sample_rate].to_i > 0
|
355
|
-
@harvest_count += 1
|
356
|
-
if (@harvest_count.to_i % Agent.config[:sample_rate].to_i) == 0
|
357
|
-
result << @random_sample if @random_sample
|
358
|
-
@harvest_count = 0
|
359
|
-
end
|
360
|
-
nil # don't assume this method returns anything
|
361
|
-
end
|
362
|
-
|
363
|
-
def add_force_persist_to(result)
|
364
|
-
result.concat(@force_persist)
|
365
|
-
@force_persist = []
|
366
|
-
end
|
367
|
-
|
368
|
-
# Returns an array of slow samples, with either one or two
|
369
|
-
# elements - one element unless random sampling is enabled. The
|
370
|
-
# sample returned will be the slowest sample among those
|
371
|
-
# available during this harvest
|
372
|
-
def add_samples_to(result)
|
373
|
-
# pull out force persist
|
374
|
-
force_persist = result.select {|sample| sample.force_persist} || []
|
375
|
-
result.reject! {|sample| sample.force_persist}
|
376
|
-
|
377
|
-
force_persist.each {|sample| store_force_persist(sample)}
|
378
|
-
|
379
|
-
result << @slowest_sample if @slowest_sample
|
380
|
-
|
381
|
-
result.compact!
|
382
|
-
result = result.sort_by { |x| x.duration }
|
383
|
-
result = result[-1..-1] || [] # take the slowest sample
|
384
|
-
|
385
|
-
add_random_sample_to(result)
|
386
|
-
add_force_persist_to(result)
|
387
|
-
|
388
|
-
result.uniq
|
389
|
-
end
|
390
|
-
|
391
|
-
# get the set of collected samples, merging into previous samples,
|
392
|
-
# and clear the collected sample list. Truncates samples to a
|
393
|
-
# specified segment_limit to save memory and bandwith
|
394
|
-
# transmitting samples to the server.
|
237
|
+
# Gather transaction traces that we'd like to transmit to the server.
|
238
|
+
# choose_samples is responsible for determining the contents of that
|
239
|
+
# transmission, along with limits and ordering.
|
395
240
|
def harvest(previous=[])
|
396
241
|
return [] if !enabled?
|
397
|
-
result = Array(previous)
|
398
242
|
|
399
|
-
|
400
|
-
|
243
|
+
# If no unsent transactions from last time, we explicitly pass nil!
|
244
|
+
previous ||= []
|
401
245
|
|
402
|
-
|
403
|
-
@slowest_sample = nil
|
404
|
-
@random_sample = nil
|
246
|
+
@samples_lock.synchronize do
|
405
247
|
@last_sample = nil
|
248
|
+
choose_samples(previous)
|
406
249
|
end
|
250
|
+
end
|
407
251
|
|
408
|
-
|
409
|
-
|
410
|
-
|
252
|
+
# Runs previously untransmitted samples into buffers, then chooses what
|
253
|
+
# to send based on each buffer's internal logic
|
254
|
+
def choose_samples(previous_samples)
|
255
|
+
append_previous_samples_to_buffers(previous_samples)
|
256
|
+
harvest_from_sample_buffers
|
411
257
|
end
|
412
258
|
|
413
|
-
#
|
414
|
-
def
|
415
|
-
|
416
|
-
|
417
|
-
b.duration <=> a.duration
|
418
|
-
elsif a.force_persist
|
419
|
-
-1
|
420
|
-
elsif b.force_persist
|
421
|
-
1
|
422
|
-
else
|
423
|
-
b.duration <=> a.duration
|
424
|
-
end
|
259
|
+
# Previous samples are added to buffers to enforce limiting rules
|
260
|
+
def append_previous_samples_to_buffers(previous_samples)
|
261
|
+
@sample_buffers.each do |buffer|
|
262
|
+
buffer.store_previous(previous_samples)
|
425
263
|
end
|
264
|
+
end
|
426
265
|
|
427
|
-
|
266
|
+
def harvest_from_sample_buffers
|
267
|
+
# map + flatten hit mocking issues calling to_ary on 1.9.2. We only
|
268
|
+
# want a single level flatten anyway, but, as you probably already
|
269
|
+
# know, Ruby 1.8.6 :/
|
270
|
+
result = []
|
271
|
+
@sample_buffers.each {|buffer| result.concat(buffer.harvest_samples)}
|
272
|
+
result.uniq
|
428
273
|
end
|
429
274
|
|
430
|
-
# reset samples without rebooting the web server
|
275
|
+
# reset samples without rebooting the web server (used by dev mode)
|
431
276
|
def reset!
|
432
|
-
@
|
433
|
-
|
434
|
-
|
435
|
-
|
277
|
+
@samples_lock.synchronize do
|
278
|
+
@last_sample = nil
|
279
|
+
@sample_buffers.each { |sample_buffer| sample_buffer.reset! }
|
280
|
+
end
|
436
281
|
end
|
437
282
|
|
438
283
|
# Checks to see if the transaction sampler is disabled, if
|
@@ -10,6 +10,8 @@ module NewRelic
|
|
10
10
|
# A task is a proc or block with a specified call period in seconds.
|
11
11
|
class WorkerLoop
|
12
12
|
|
13
|
+
attr_accessor :period, :propagate_errors
|
14
|
+
|
13
15
|
# Optional argument :duration (in seconds) for how long the worker loop runs
|
14
16
|
# or :limit (integer) for max number of iterations
|
15
17
|
def initialize(opts={})
|
@@ -19,45 +21,53 @@ module NewRelic
|
|
19
21
|
@duration = opts[:duration] if opts[:duration]
|
20
22
|
@limit = opts[:limit] if opts[:limit]
|
21
23
|
@iterations = 0
|
24
|
+
@propagate_errors = opts.fetch(:propagate_errors, false)
|
22
25
|
end
|
23
26
|
|
24
|
-
#
|
25
|
-
def
|
26
|
-
|
27
|
+
# Reset state that is changed by running the worker loop
|
28
|
+
def setup(period, task)
|
29
|
+
@task = task
|
30
|
+
@period = period if period
|
31
|
+
@should_run = true
|
32
|
+
@iterations = 0
|
33
|
+
|
34
|
+
now = Time.now
|
35
|
+
@deadline = now + @duration if @duration
|
36
|
+
@next_invocation_time = (now + @period)
|
27
37
|
end
|
28
38
|
|
29
39
|
# Run infinitely, calling the registered tasks at their specified
|
30
40
|
# call periods. The caller is responsible for creating the thread
|
31
41
|
# that runs this worker loop. This will run the task immediately.
|
32
42
|
def run(period=nil, &block)
|
33
|
-
|
34
|
-
@period = period if period
|
35
|
-
@next_invocation_time = (Time.now + @period)
|
36
|
-
@task = block
|
43
|
+
setup(period, block)
|
37
44
|
while keep_running? do
|
38
|
-
|
39
|
-
|
40
|
-
sleep_time = @next_invocation_time - @now
|
41
|
-
sleep sleep_time if sleep_time > 0
|
42
|
-
@now = Time.now
|
43
|
-
end
|
45
|
+
sleep_time = schedule_next_invocation
|
46
|
+
sleep(sleep_time) if sleep_time > 0
|
44
47
|
run_task if keep_running?
|
45
|
-
@iterations += 1
|
48
|
+
@iterations += 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def schedule_next_invocation
|
53
|
+
now = Time.now
|
54
|
+
while @next_invocation_time <= now && @period > 0
|
55
|
+
@next_invocation_time += @period
|
46
56
|
end
|
57
|
+
@next_invocation_time - Time.now
|
47
58
|
end
|
48
59
|
|
49
60
|
# a simple accessor for @should_run
|
50
61
|
def keep_running?
|
51
|
-
@now = Time.now
|
52
62
|
@should_run && under_duration? && under_limit?
|
53
63
|
end
|
54
64
|
|
55
65
|
def under_duration?
|
56
|
-
!@deadline ||
|
66
|
+
!@deadline || Time.now < @deadline
|
57
67
|
end
|
58
68
|
|
59
69
|
def under_limit?
|
60
|
-
|
70
|
+
@limit.nil? || @iterations < @limit
|
61
71
|
end
|
62
72
|
|
63
73
|
# Sets @should_run to false. Returns false
|
@@ -69,30 +79,28 @@ module NewRelic
|
|
69
79
|
# possible errors. Also updates the execution time so that the
|
70
80
|
# next run occurs on schedule, even if we execute at some odd time
|
71
81
|
def run_task
|
72
|
-
|
73
|
-
|
82
|
+
if @propagate_errors
|
83
|
+
@task.call
|
84
|
+
else
|
85
|
+
begin
|
74
86
|
@task.call
|
87
|
+
rescue ServerError => e
|
88
|
+
::NewRelic::Agent.logger.debug "Server Error:", e
|
89
|
+
rescue NewRelic::Agent::ForceRestartException, NewRelic::Agent::ForceDisconnectException
|
90
|
+
# blow out the loop
|
91
|
+
raise
|
92
|
+
rescue RuntimeError => e
|
93
|
+
# This is probably a server error which has been logged in the server along
|
94
|
+
# with your account name.
|
95
|
+
::NewRelic::Agent.logger.error "Error running task in worker loop, likely a server error:", e
|
96
|
+
rescue Timeout::Error, NewRelic::Agent::ServerConnectionException
|
97
|
+
# Want to ignore these because they are handled already
|
98
|
+
rescue SystemExit, NoMemoryError, SignalException
|
99
|
+
raise
|
100
|
+
rescue => e
|
101
|
+
# Don't blow out the stack for anything that hasn't already propagated
|
102
|
+
::NewRelic::Agent.logger.error "Error running task in Agent Worker Loop:", e
|
75
103
|
end
|
76
|
-
rescue ServerError => e
|
77
|
-
::NewRelic::Agent.logger.debug "Server Error:", e
|
78
|
-
rescue NewRelic::Agent::ForceRestartException, NewRelic::Agent::ForceDisconnectException
|
79
|
-
# blow out the loop
|
80
|
-
raise
|
81
|
-
rescue RuntimeError => e
|
82
|
-
# This is probably a server error which has been logged in the server along
|
83
|
-
# with your account name.
|
84
|
-
::NewRelic::Agent.logger.error "Error running task in worker loop, likely a server error:", e
|
85
|
-
rescue Timeout::Error, NewRelic::Agent::ServerConnectionException
|
86
|
-
# Want to ignore these because they are handled already
|
87
|
-
rescue SystemExit, NoMemoryError, SignalException
|
88
|
-
raise
|
89
|
-
rescue => e
|
90
|
-
# Don't blow out the stack for anything that hasn't already propagated
|
91
|
-
::NewRelic::Agent.logger.error "Error running task in Agent Worker Loop:", e
|
92
|
-
end
|
93
|
-
now = Time.now
|
94
|
-
while @next_invocation_time <= now && @period > 0
|
95
|
-
@next_invocation_time += @period
|
96
104
|
end
|
97
105
|
end
|
98
106
|
end
|