newrelic_rpm 3.0.1 → 3.1.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 +2 -3
- data/README.rdoc +3 -3
- data/lib/new_relic/agent.rb +19 -7
- data/lib/new_relic/agent/agent.rb +83 -19
- data/lib/new_relic/agent/beacon_configuration.rb +8 -12
- data/lib/new_relic/agent/browser_monitoring.rb +8 -8
- data/lib/new_relic/agent/error_collector.rb +13 -13
- data/lib/new_relic/agent/instrumentation.rb +9 -0
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +10 -2
- data/lib/new_relic/agent/instrumentation/metric_frame.rb +41 -35
- data/lib/new_relic/agent/instrumentation/metric_frame/pop.rb +92 -0
- data/lib/new_relic/agent/method_tracer.rb +0 -2
- data/lib/new_relic/agent/shim_agent.rb +2 -0
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +89 -60
- data/lib/new_relic/agent/stats_engine/transactions.rb +1 -1
- data/lib/new_relic/agent/worker_loop.rb +1 -1
- data/lib/new_relic/collection_helper.rb +0 -2
- data/lib/new_relic/control/class_methods.rb +25 -12
- data/lib/new_relic/control/logging_methods.rb +30 -17
- data/lib/new_relic/data_serialization.rb +81 -0
- data/lib/new_relic/local_environment.rb +1 -1
- data/lib/new_relic/metric_data.rb +9 -5
- data/lib/new_relic/metric_spec.rb +7 -1
- data/lib/new_relic/rack/browser_monitoring.rb +1 -7
- data/lib/new_relic/stats.rb +4 -0
- data/lib/new_relic/transaction_analysis.rb +45 -88
- data/lib/new_relic/transaction_analysis/segment_summary.rb +47 -0
- data/lib/new_relic/transaction_sample.rb +15 -332
- data/lib/new_relic/transaction_sample/composite_segment.rb +27 -0
- data/lib/new_relic/transaction_sample/fake_segment.rb +9 -0
- data/lib/new_relic/transaction_sample/segment.rb +250 -0
- data/lib/new_relic/transaction_sample/summary_segment.rb +21 -0
- data/lib/new_relic/version.rb +3 -3
- data/newrelic.yml +3 -3
- data/newrelic_rpm.gemspec +27 -4
- data/test/active_record_fixtures.rb +31 -13
- data/test/new_relic/agent/agent/start_worker_thread_test.rb +1 -3
- data/test/new_relic/agent/agent_test.rb +73 -28
- data/test/new_relic/agent/agent_test_controller_test.rb +11 -10
- data/test/new_relic/agent/beacon_configuration_test.rb +37 -20
- data/test/new_relic/agent/browser_monitoring_test.rb +17 -28
- data/test/new_relic/agent/error_collector/notice_error_test.rb +9 -7
- data/test/new_relic/agent/error_collector_test.rb +6 -7
- data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +12 -5
- data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +195 -0
- data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +60 -58
- data/test/new_relic/agent/instrumentation/queue_time_test.rb +14 -0
- data/test/new_relic/agent/instrumentation/rack_test.rb +35 -0
- data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +0 -1
- data/test/new_relic/agent/method_tracer_test.rb +8 -8
- data/test/new_relic/agent/sampler_test.rb +19 -0
- data/test/new_relic/agent/shim_agent_test.rb +20 -0
- data/test/new_relic/agent/stats_engine/metric_stats/harvest_test.rb +150 -0
- data/test/new_relic/agent/stats_engine/metric_stats_test.rb +1 -0
- data/test/new_relic/agent/stats_engine/samplers_test.rb +4 -3
- data/test/new_relic/agent/{stats_engine/stats_engine_test.rb → stats_engine_test.rb} +8 -8
- data/test/new_relic/agent/transaction_sampler_test.rb +1 -1
- data/test/new_relic/agent/worker_loop_test.rb +2 -2
- data/test/new_relic/control/class_methods_test.rb +62 -0
- data/test/new_relic/control/logging_methods_test.rb +157 -0
- data/test/new_relic/control_test.rb +10 -10
- data/test/new_relic/data_serialization_test.rb +50 -0
- data/test/new_relic/local_environment_test.rb +13 -13
- data/test/new_relic/metric_data_test.rb +125 -0
- data/test/new_relic/metric_spec_test.rb +8 -0
- data/test/new_relic/transaction_analysis/segment_summary_test.rb +77 -0
- data/test/new_relic/transaction_analysis_test.rb +121 -0
- data/test/new_relic/transaction_sample/composite_segment_test.rb +35 -0
- data/test/new_relic/transaction_sample/fake_segment_test.rb +17 -0
- data/test/new_relic/transaction_sample/segment_test.rb +454 -0
- data/test/new_relic/transaction_sample/summary_segment_test.rb +31 -0
- data/test/new_relic/transaction_sample_test.rb +51 -0
- data/test/test_helper.rb +4 -14
- metadata +32 -7
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'new_relic/agent/instrumentation/metric_frame/pop'
|
2
|
+
|
1
3
|
# A struct holding the information required to measure a controller
|
2
4
|
# action. This is put on the thread local. Handles the issue of
|
3
5
|
# re-entrancy, or nested action calls.
|
@@ -8,6 +10,9 @@ module NewRelic
|
|
8
10
|
module Agent
|
9
11
|
module Instrumentation
|
10
12
|
class MetricFrame
|
13
|
+
# helper module refactored out of the `pop` method
|
14
|
+
include Pop
|
15
|
+
|
11
16
|
attr_accessor :start # A Time instance for the start time, never nil
|
12
17
|
attr_accessor :apdex_start # A Time instance used for calculating the apdex score, which
|
13
18
|
# might end up being @start, or it might be further upstream if
|
@@ -35,7 +40,7 @@ module NewRelic
|
|
35
40
|
# Reconnect to the server if necessary. This is only done
|
36
41
|
# for old versions of passenger that don't implement an explicit after_fork
|
37
42
|
# event.
|
38
|
-
|
43
|
+
agent.after_fork(:keep_retrying => false) if @@check_server_connection
|
39
44
|
|
40
45
|
Thread.current[:newrelic_metric_frame] = new
|
41
46
|
end
|
@@ -50,6 +55,10 @@ module NewRelic
|
|
50
55
|
current && current.referer
|
51
56
|
end
|
52
57
|
|
58
|
+
def self.agent
|
59
|
+
NewRelic::Agent.instance
|
60
|
+
end
|
61
|
+
|
53
62
|
@@java_classes_loaded = false
|
54
63
|
|
55
64
|
if defined? JRuby
|
@@ -71,10 +80,22 @@ module NewRelic
|
|
71
80
|
@process_cpu_start = process_cpu
|
72
81
|
end
|
73
82
|
|
83
|
+
def agent
|
84
|
+
NewRelic::Agent.instance
|
85
|
+
end
|
86
|
+
|
87
|
+
def transaction_sampler
|
88
|
+
agent.transaction_sampler
|
89
|
+
end
|
90
|
+
|
91
|
+
private :agent
|
92
|
+
private :transaction_sampler
|
93
|
+
|
94
|
+
|
74
95
|
# Indicate that we are entering a measured controller action or task.
|
75
96
|
# Make sure you unwind every push with a pop call.
|
76
97
|
def push(m)
|
77
|
-
|
98
|
+
transaction_sampler.notice_first_scope_push(start)
|
78
99
|
@path_stack.push NewRelic::MetricParser::MetricParser.for_metric_named(m)
|
79
100
|
end
|
80
101
|
|
@@ -96,15 +117,16 @@ module NewRelic
|
|
96
117
|
|
97
118
|
# Call this to ensure that the current transaction is not saved
|
98
119
|
def abort_transaction!
|
99
|
-
|
120
|
+
transaction_sampler.ignore_transaction
|
100
121
|
end
|
101
|
-
# This needs to be called after entering the call to trace the
|
102
|
-
#
|
122
|
+
# This needs to be called after entering the call to trace the
|
123
|
+
# controller action, otherwise the controller action blames
|
124
|
+
# itself. It gets reset in the normal #pop call.
|
103
125
|
def start_transaction
|
104
|
-
|
126
|
+
agent.stats_engine.start_transaction metric_name
|
105
127
|
# Only push the transaction context info once, on entry:
|
106
128
|
if @path_stack.size == 1
|
107
|
-
|
129
|
+
transaction_sampler.notice_transaction(metric_name, uri, filtered_params)
|
108
130
|
end
|
109
131
|
end
|
110
132
|
|
@@ -121,28 +143,11 @@ module NewRelic
|
|
121
143
|
# does the appropriate wrapup of the context.
|
122
144
|
def pop
|
123
145
|
metric = @path_stack.pop
|
124
|
-
if metric.nil?
|
125
|
-
NewRelic::Agent.logger.error "Underflow in metric frames: #{caller.join("\n ")}"
|
126
|
-
end
|
146
|
+
log_underflow if metric.nil?
|
127
147
|
if @path_stack.empty?
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
cpu_burn = process_cpu - @process_cpu_start
|
132
|
-
elsif @jruby_cpu_start
|
133
|
-
cpu_burn = jruby_cpu_time - @jruby_cpu_start
|
134
|
-
NewRelic::Agent.get_stats_no_scope(NewRelic::Metrics::USER_TIME).record_data_point(cpu_burn)
|
135
|
-
end
|
136
|
-
NewRelic::Agent.instance.transaction_sampler.notice_transaction_cpu_time(cpu_burn) if cpu_burn
|
137
|
-
NewRelic::Agent.instance.histogram.process((Time.now - start).to_f) if metric.is_web_transaction?
|
138
|
-
NewRelic::Agent.instance.transaction_sampler.notice_scope_empty
|
139
|
-
end
|
140
|
-
NewRelic::Agent.instance.stats_engine.end_transaction
|
141
|
-
Thread.current[:newrelic_start_time] = (Thread.current[:newrelic_metric_frame].start rescue nil)
|
142
|
-
Thread.current[:newrelic_metric_frame] = nil
|
143
|
-
else # path stack not empty
|
144
|
-
# change the transaction name back to whatever was on the stack.
|
145
|
-
NewRelic::Agent.instance.stats_engine.scope_name = metric_name
|
148
|
+
handle_empty_path_stack(metric)
|
149
|
+
else
|
150
|
+
set_new_scope!(current_stack_metric)
|
146
151
|
end
|
147
152
|
end
|
148
153
|
|
@@ -157,14 +162,15 @@ module NewRelic
|
|
157
162
|
# Anything left over is treated as custom params
|
158
163
|
|
159
164
|
def self.notice_error(e, options={})
|
160
|
-
|
165
|
+
request = options.delete(:request)
|
166
|
+
if request
|
161
167
|
options[:referer] = referer_from_request(request)
|
162
168
|
options[:uri] = uri_from_request(request)
|
163
169
|
end
|
164
170
|
if current
|
165
171
|
current.notice_error(e, options)
|
166
172
|
else
|
167
|
-
|
173
|
+
agent.error_collector.notice_error(e, options)
|
168
174
|
end
|
169
175
|
end
|
170
176
|
|
@@ -177,7 +183,7 @@ module NewRelic
|
|
177
183
|
options[:metric] = metric_name
|
178
184
|
options.merge!(custom_parameters)
|
179
185
|
if exception != e
|
180
|
-
result =
|
186
|
+
result = agent.error_collector.notice_error(e, options)
|
181
187
|
self.exception = result if result
|
182
188
|
end
|
183
189
|
end
|
@@ -242,7 +248,8 @@ module NewRelic
|
|
242
248
|
end
|
243
249
|
|
244
250
|
def self.recording_web_transaction?
|
245
|
-
|
251
|
+
c = Thread.current[:newrelic_metric_frame]
|
252
|
+
if c
|
246
253
|
c.recording_web_transaction?
|
247
254
|
end
|
248
255
|
end
|
@@ -276,8 +283,8 @@ module NewRelic
|
|
276
283
|
end
|
277
284
|
|
278
285
|
def self.record_apdex(current_metric, action_duration, total_duration, is_error)
|
279
|
-
summary_stat =
|
280
|
-
controller_stat =
|
286
|
+
summary_stat = agent.stats_engine.get_custom_stats("Apdex", NewRelic::ApdexStats)
|
287
|
+
controller_stat = agent.stats_engine.get_custom_stats(current_metric.apdex_metric_path, NewRelic::ApdexStats)
|
281
288
|
update_apdex(summary_stat, total_duration, is_error)
|
282
289
|
update_apdex(controller_stat, action_duration, is_error)
|
283
290
|
end
|
@@ -313,7 +320,6 @@ module NewRelic
|
|
313
320
|
java_utime = threadMBean.getCurrentThreadUserTime() # ns
|
314
321
|
-1 == java_utime ? 0.0 : java_utime/1e9
|
315
322
|
end
|
316
|
-
|
317
323
|
end
|
318
324
|
end
|
319
325
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'new_relic/agent/instrumentation'
|
2
|
+
module NewRelic
|
3
|
+
module Agent
|
4
|
+
module Instrumentation
|
5
|
+
class MetricFrame
|
6
|
+
module Pop
|
7
|
+
|
8
|
+
def clear_thread_metric_frame!
|
9
|
+
Thread.current[:newrelic_metric_frame] = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_last_start_time!
|
13
|
+
frame = Thread.current[:newrelic_metric_frame]
|
14
|
+
if frame && frame.respond_to?(:start)
|
15
|
+
Thread.current[:newrelic_start_time] = Thread.current[:newrelic_metric_frame].start
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_new_scope!(metric)
|
20
|
+
agent.stats_engine.scope_name = metric
|
21
|
+
end
|
22
|
+
|
23
|
+
def log_underflow
|
24
|
+
NewRelic::Agent.logger.error "Underflow in metric frames: #{caller.join("\n ")}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def process_histogram_for_transaction(ending)
|
28
|
+
agent.histogram.process((ending - start).to_f)
|
29
|
+
end
|
30
|
+
|
31
|
+
def notice_scope_empty
|
32
|
+
transaction_sampler.notice_scope_empty
|
33
|
+
end
|
34
|
+
|
35
|
+
def record_transaction_cpu
|
36
|
+
burn = cpu_burn
|
37
|
+
transaction_sampler.notice_transaction_cpu_time(burn) if burn
|
38
|
+
end
|
39
|
+
|
40
|
+
def normal_cpu_burn
|
41
|
+
return unless @process_cpu_start
|
42
|
+
process_cpu - @process_cpu_start
|
43
|
+
end
|
44
|
+
|
45
|
+
def jruby_cpu_burn
|
46
|
+
return unless @jruby_cpu_start
|
47
|
+
burn = (jruby_cpu_time - @jruby_cpu_start)
|
48
|
+
record_jruby_cpu_burn(burn)
|
49
|
+
burn
|
50
|
+
end
|
51
|
+
|
52
|
+
# we need to do this here because the normal cpu sampler
|
53
|
+
# process doesn't work on JRuby. See the cpu_sampler.rb file
|
54
|
+
# to understand where cpu is recorded for non-jruby processes
|
55
|
+
def record_jruby_cpu_burn(burn)
|
56
|
+
NewRelic::Agent.get_stats_no_scope(NewRelic::Metrics::USER_TIME).record_data_point(burn)
|
57
|
+
end
|
58
|
+
|
59
|
+
def cpu_burn
|
60
|
+
normal_cpu_burn || jruby_cpu_burn
|
61
|
+
end
|
62
|
+
|
63
|
+
def end_transaction!
|
64
|
+
agent.stats_engine.end_transaction
|
65
|
+
end
|
66
|
+
|
67
|
+
def notify_transaction_sampler(web_transaction)
|
68
|
+
record_transaction_cpu
|
69
|
+
process_histogram_for_transaction(Time.now) if web_transaction
|
70
|
+
notice_scope_empty
|
71
|
+
end
|
72
|
+
|
73
|
+
def traced?
|
74
|
+
NewRelic::Agent.is_execution_traced?
|
75
|
+
end
|
76
|
+
|
77
|
+
def handle_empty_path_stack(metric)
|
78
|
+
raise 'path stack not empty' unless @path_stack.empty?
|
79
|
+
notify_transaction_sampler(metric.is_web_transaction?) if traced?
|
80
|
+
end_transaction!
|
81
|
+
set_last_start_time!
|
82
|
+
clear_thread_metric_frame!
|
83
|
+
end
|
84
|
+
|
85
|
+
def current_stack_metric
|
86
|
+
metric_name
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -81,8 +81,6 @@ module NewRelic
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
EMPTY_ARRAY = [].freeze
|
85
|
-
|
86
84
|
# Deprecated. Use #trace_execution_scoped, a version with an options hash.
|
87
85
|
def trace_method_execution_with_scope(metric_names, produce_metric, deduct_call_time_from_parent, scoped_metric_only=false, &block) #:nodoc:
|
88
86
|
trace_execution_scoped(metric_names,
|
@@ -18,6 +18,8 @@ module NewRelic
|
|
18
18
|
def after_fork *args; end
|
19
19
|
def start *args; end
|
20
20
|
def shutdown; end
|
21
|
+
def serialize; end
|
22
|
+
def merge_data_from(*args); end
|
21
23
|
def push_trace_execution_flag(*args); end
|
22
24
|
def pop_trace_execution_flag(*args); end
|
23
25
|
def browser_timing_header; "" end
|
@@ -39,98 +39,127 @@ module NewRelic
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
# The stats hash hashes either a metric name for an unscoped metric,
|
43
|
-
# or a metric_spec for a scoped metric value.
|
44
|
-
def lookup_stat(metric_name)
|
45
|
-
stats_hash[metric_name]
|
46
|
-
end
|
47
|
-
|
48
42
|
def metrics
|
49
43
|
stats_hash.keys.map(&:to_s)
|
50
44
|
end
|
51
45
|
|
52
46
|
def get_stats_no_scope(metric_name)
|
53
|
-
stats_hash[metric_name] ||= NewRelic::MethodTraceStats.new
|
47
|
+
stats_hash[NewRelic::MetricSpec.new(metric_name, '')] ||= NewRelic::MethodTraceStats.new
|
54
48
|
end
|
55
49
|
|
56
50
|
# This version allows a caller to pass a stat class to use
|
57
51
|
#
|
58
52
|
def get_custom_stats(metric_name, stat_class)
|
59
|
-
stats_hash[metric_name] ||= stat_class.new
|
53
|
+
stats_hash[NewRelic::MetricSpec.new(metric_name)] ||= stat_class.new
|
60
54
|
end
|
61
55
|
|
62
56
|
# If use_scope is true, two chained metrics are created, one with scope and one without
|
63
57
|
# If scoped_metric_only is true, only a scoped metric is created (used by rendering metrics which by definition are per controller only)
|
64
58
|
def get_stats(metric_name, use_scope = true, scoped_metric_only = false, scope = nil)
|
65
|
-
|
66
|
-
|
59
|
+
scope ||= scope_name if use_scope
|
60
|
+
if scoped_metric_only
|
61
|
+
spec = NewRelic::MetricSpec.new metric_name, scope
|
62
|
+
stats = stats_hash[spec] ||= NewRelic::MethodTraceStats.new
|
63
|
+
else
|
64
|
+
stats = stats_hash[NewRelic::MetricSpec.new(metric_name)] ||= NewRelic::MethodTraceStats.new
|
65
|
+
if scope && scope != metric_name
|
67
66
|
spec = NewRelic::MetricSpec.new metric_name, scope
|
68
|
-
stats = stats_hash[spec] ||= NewRelic::
|
69
|
-
else
|
70
|
-
stats = stats_hash[metric_name] ||= NewRelic::MethodTraceStats.new
|
71
|
-
if scope && scope != metric_name
|
72
|
-
spec = NewRelic::MetricSpec.new metric_name, scope
|
73
|
-
stats = stats_hash[spec] ||= NewRelic::ScopedMethodTraceStats.new(stats)
|
74
|
-
end
|
67
|
+
stats = stats_hash[spec] ||= NewRelic::ScopedMethodTraceStats.new(stats)
|
75
68
|
end
|
76
|
-
|
69
|
+
end
|
70
|
+
stats
|
77
71
|
end
|
78
72
|
|
79
|
-
def lookup_stats(metric_name, scope_name =
|
80
|
-
|
81
|
-
stats_hash[metric_name]
|
73
|
+
def lookup_stats(metric_name, scope_name = '')
|
74
|
+
stats_hash[NewRelic::MetricSpec.new(metric_name, scope_name)]
|
82
75
|
end
|
83
|
-
# Harvest the timeslice data. First recombine current statss
|
84
|
-
# with any previously
|
85
|
-
# unsent metrics, clear out stats cache, and return the current
|
86
|
-
# stats.
|
87
|
-
# ---
|
88
|
-
# Note: this is not synchronized. There is still some risk in this and
|
89
|
-
# we will revisit later to see if we can make this more robust without
|
90
|
-
# sacrificing efficiency.
|
91
|
-
# +++
|
92
|
-
def harvest_timeslice_data(previous_timeslice_data, metric_ids)
|
93
|
-
timeslice_data = {}
|
94
|
-
poll harvest_samplers
|
95
|
-
stats_hash.keys.each do | metric_spec |
|
96
76
|
|
77
|
+
module Harvest
|
97
78
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
metric_spec =
|
79
|
+
def merge_data(metric_data_hash)
|
80
|
+
metric_data_hash.each do |metric_spec, metric_data|
|
81
|
+
new_data = lookup_stats(metric_spec.name, metric_spec.scope)
|
82
|
+
if new_data
|
83
|
+
new_data.merge!(metric_data.stats)
|
84
|
+
else
|
85
|
+
stats_hash[metric_spec] = metric_data.stats
|
105
86
|
end
|
87
|
+
end
|
88
|
+
end
|
106
89
|
|
107
|
-
|
108
|
-
|
109
|
-
|
90
|
+
private
|
91
|
+
def get_stats_hash_from(engine_or_hash)
|
92
|
+
if engine_or_hash.is_a?(StatsEngine)
|
93
|
+
engine_or_hash.stats_hash
|
94
|
+
else
|
95
|
+
engine_or_hash
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def coerce_to_metric_spec(metric_spec)
|
100
|
+
if metric_spec.is_a?(NewRelic::MetricSpec)
|
101
|
+
metric_spec
|
102
|
+
else
|
103
|
+
NewRelic::MetricSpec.new(metric_spec)
|
104
|
+
end
|
105
|
+
end
|
110
106
|
|
111
|
-
|
112
|
-
|
107
|
+
def clone_and_reset_stats(metric_spec, stats)
|
108
|
+
if stats.nil?
|
109
|
+
raise "Nil stats for #{metric_spec.name} (#{metric_spec.scope})"
|
110
|
+
end
|
113
111
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
stats_copy.merge! previous_metric_data.stats unless previous_metric_data.nil?
|
112
|
+
stats_copy = stats.clone
|
113
|
+
stats.reset
|
114
|
+
stats_copy
|
115
|
+
end
|
119
116
|
|
120
|
-
|
121
|
-
|
122
|
-
|
117
|
+
# if the previous timeslice data has not been reported (due to an error of some sort)
|
118
|
+
# then we need to merge this timeslice with the previously accumulated - but not sent
|
119
|
+
# data
|
120
|
+
def merge_old_data!(metric_spec, stats, old_data)
|
121
|
+
metric_data = old_data[metric_spec]
|
122
|
+
stats.merge!(metric_data.stats) unless metric_data.nil?
|
123
|
+
end
|
123
124
|
|
124
|
-
|
125
|
-
|
125
|
+
def add_data_to_send_unless_empty(data, stats, metric_spec, id)
|
126
|
+
# don't bother collecting and reporting stats that have
|
127
|
+
# zero-values for this timeslice. significant
|
128
|
+
# performance boost and storage savings.
|
129
|
+
return if stats.is_reset?
|
130
|
+
data[metric_spec] = NewRelic::MetricData.new((id ? nil : metric_spec), stats, id)
|
131
|
+
end
|
126
132
|
|
127
|
-
|
133
|
+
def merge_stats(other_engine_or_hash, metric_ids)
|
134
|
+
old_data = get_stats_hash_from(other_engine_or_hash)
|
128
135
|
|
129
|
-
|
130
|
-
|
131
|
-
end
|
136
|
+
timeslice_data = {}
|
137
|
+
stats_hash.each do | metric_spec, stats |
|
132
138
|
|
139
|
+
metric_spec = coerce_to_metric_spec(metric_spec)
|
140
|
+
stats_copy = clone_and_reset_stats(metric_spec, stats)
|
141
|
+
merge_old_data!(metric_spec, stats_copy, old_data)
|
142
|
+
add_data_to_send_unless_empty(timeslice_data, stats_copy, metric_spec, metric_ids[metric_spec])
|
143
|
+
end
|
133
144
|
timeslice_data
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
include Harvest
|
149
|
+
|
150
|
+
# Harvest the timeslice data. First recombine current statss
|
151
|
+
# with any previously
|
152
|
+
# unsent metrics, clear out stats cache, and return the current
|
153
|
+
# stats.
|
154
|
+
# ---
|
155
|
+
# Note: this is not synchronized. There is still some risk in this and
|
156
|
+
# we will revisit later to see if we can make this more robust without
|
157
|
+
# sacrificing efficiency.
|
158
|
+
# +++
|
159
|
+
def harvest_timeslice_data(previous_timeslice_data, metric_ids)
|
160
|
+
|
161
|
+
poll harvest_samplers
|
162
|
+
merge_stats(previous_timeslice_data, metric_ids)
|
134
163
|
end
|
135
164
|
|
136
165
|
# Remove all stats. For test code only.
|