newrelic_rpm 3.9.4.245 → 3.9.5.251
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +57 -0
- data/Guardfile +1 -0
- data/lib/new_relic/agent/agent.rb +3 -3
- data/lib/new_relic/agent/audit_logger.rb +5 -2
- data/lib/new_relic/agent/configuration/default_source.rb +11 -5
- data/lib/new_relic/agent/error_collector.rb +14 -1
- data/lib/new_relic/agent/hostname.rb +22 -1
- data/lib/new_relic/agent/instrumentation/middleware_tracing.rb +8 -2
- data/lib/new_relic/agent/instrumentation/queue_time.rb +9 -6
- data/lib/new_relic/agent/method_tracer.rb +51 -172
- data/lib/new_relic/agent/method_tracer_helpers.rb +90 -0
- data/lib/new_relic/agent/new_relic_service.rb +33 -11
- data/lib/new_relic/agent/new_relic_service/encoders.rb +9 -5
- data/lib/new_relic/agent/request_sampler.rb +20 -12
- data/lib/new_relic/agent/rules_engine.rb +31 -78
- data/lib/new_relic/agent/rules_engine/replacement_rule.rb +76 -0
- data/lib/new_relic/agent/rules_engine/segment_terms_rule.rb +48 -0
- data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
- data/lib/new_relic/agent/sql_sampler.rb +39 -10
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +1 -0
- data/lib/new_relic/agent/stats_engine/stats_hash.rb +7 -13
- data/lib/new_relic/agent/system_info.rb +96 -10
- data/lib/new_relic/agent/threading/agent_thread.rb +4 -1
- data/lib/new_relic/agent/threading/backtrace_node.rb +67 -57
- data/lib/new_relic/agent/threading/thread_profile.rb +30 -15
- data/lib/new_relic/agent/transaction.rb +11 -4
- data/lib/new_relic/environment_report.rb +21 -20
- data/lib/new_relic/version.rb +1 -1
- data/test/agent_helper.rb +12 -0
- data/test/fixtures/cross_agent_tests/README.md +1 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_1core_1logical.txt +3 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_1core_2logical.txt +14 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_2core_2logical.txt +14 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/1pack_4core_4logical.txt +28 -0
- data/test/fixtures/{proc_cpuinfo.txt → cross_agent_tests/proc_cpuinfo/2pack_12core_24logical.txt} +0 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_20core_40logical.txt +999 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_2core_2logical.txt +51 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_2core_4logical.txt +28 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/2pack_4core_4logical.txt +28 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/4pack_4core_4logical.txt +103 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/8pack_8core_8logical.txt +199 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/README.md +24 -0
- data/test/fixtures/cross_agent_tests/proc_cpuinfo/Xpack_Xcore_2logical.txt +43 -0
- data/test/fixtures/cross_agent_tests/transaction_segment_terms.json +101 -0
- data/test/multiverse/lib/multiverse/suite.rb +1 -1
- data/test/multiverse/suites/agent_only/agent_run_id_handling_test.rb +40 -0
- data/test/multiverse/suites/agent_only/labels_test.rb +9 -14
- data/test/multiverse/suites/agent_only/marshaling_test.rb +4 -6
- data/test/multiverse/suites/agent_only/rename_rule_test.rb +41 -4
- data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +11 -3
- data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +8 -8
- data/test/multiverse/suites/rack/example_app.rb +20 -0
- data/test/multiverse/suites/rack/http_response_code_test.rb +51 -0
- data/test/multiverse/suites/sidekiq/Envfile +13 -6
- data/test/multiverse/suites/sidekiq/sidekiq_server.rb +4 -3
- data/test/new_relic/agent/audit_logger_test.rb +27 -0
- data/test/new_relic/agent/error_collector_test.rb +26 -5
- data/test/new_relic/agent/hostname_test.rb +66 -14
- data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +8 -12
- data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +7 -45
- data/test/new_relic/agent/method_tracer_test.rb +52 -1
- data/test/new_relic/agent/new_relic_service_test.rb +76 -0
- data/test/new_relic/agent/request_sampler_test.rb +7 -0
- data/test/new_relic/agent/rules_engine_test.rb +87 -56
- data/test/new_relic/agent/sql_sampler_test.rb +50 -14
- data/test/new_relic/agent/stats_engine/metric_stats_test.rb +2 -2
- data/test/new_relic/agent/stats_engine/samplers_test.rb +1 -1
- data/test/new_relic/agent/{stats_hash_test.rb → stats_engine/stats_hash_test.rb} +1 -38
- data/test/new_relic/agent/system_info_test.rb +45 -0
- data/test/new_relic/agent/threading/agent_thread_test.rb +30 -0
- data/test/new_relic/agent/threading/backtrace_node_test.rb +27 -44
- data/test/new_relic/agent/threading/thread_profile_test.rb +35 -14
- data/test/new_relic/agent/transaction_test.rb +13 -10
- data/test/new_relic/environment_report_test.rb +7 -6
- data/test/new_relic/fake_collector.rb +10 -6
- data/test/new_relic/multiverse_helpers.rb +4 -11
- data/test/new_relic/rack/agent_hooks_test.rb +1 -1
- data/test/performance/lib/performance/baseline_compare_reporter.rb +24 -7
- data/test/performance/lib/performance/result.rb +3 -1
- data/test/performance/lib/performance/runner.rb +10 -0
- data/test/performance/lib/performance/timer.rb +6 -10
- data/test/performance/script/runner +18 -1
- data/test/performance/suites/queue_time.rb +21 -0
- data/test/performance/suites/stats_hash.rb +34 -0
- data/test/performance/suites/thread_profiling.rb +26 -0
- metadata +25 -4
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,62 @@
|
|
1
1
|
# New Relic Ruby Agent Release Notes #
|
2
2
|
|
3
|
+
## v3.9.5 ##
|
4
|
+
|
5
|
+
* Per-dyno data on Heroku
|
6
|
+
|
7
|
+
When running on Heroku, data from the agent can now be broken out by dyno
|
8
|
+
name, allowing you to more easily see what's happening on a per-dyno level.
|
9
|
+
Dynos on Heroku are now treated in the same way that distinct hosts on other
|
10
|
+
platforms work.
|
11
|
+
|
12
|
+
By default, 'scheduler' and 'run' dyno names will be aggregated into
|
13
|
+
'scheduler.*' and 'run.*' to avoid unbounded growth in the number of reported
|
14
|
+
hostnames.
|
15
|
+
|
16
|
+
Read more about this feature on our Heroku docs page:
|
17
|
+
https://docs.newrelic.com/docs/agents/ruby-agent/miscellaneous/ruby-agent-heroku
|
18
|
+
|
19
|
+
* HTTP response codes in Insights events
|
20
|
+
|
21
|
+
The Ruby agent will now capture HTTP response codes from Rack applications
|
22
|
+
(including Rails and Sinatra apps) and include them under the httpResponseCode
|
23
|
+
attribute on events sent to Insights.
|
24
|
+
|
25
|
+
* Stricter limits on memory usage of metrics and SQL traces
|
26
|
+
|
27
|
+
The agent now imposes stricter limits on the number of distinct SQL traces and
|
28
|
+
metrics that it will buffer in memory at any point in time, leading to more
|
29
|
+
predictable memory consumption even in exceptional circumstances.
|
30
|
+
|
31
|
+
* Improved reliability of thread profiling
|
32
|
+
|
33
|
+
Several issues that would previously have prevented the successful completion
|
34
|
+
and transmission of thread profiles to New Relic's servers have been fixed.
|
35
|
+
|
36
|
+
These issues were related to the use of recursion in processing thread
|
37
|
+
profiles, and have been addressed by both limiting the maximum depth of the
|
38
|
+
backtraces recorded in thread profiles, and eliminating the agent's use of
|
39
|
+
recursion in processing profile data.
|
40
|
+
|
41
|
+
* Allow tracing Rails view helpers with add_method_tracer
|
42
|
+
|
43
|
+
Previously, attempting to trace a Rails view helper method using
|
44
|
+
add_method_tracer on the view helper module would lead to a NoMethodError
|
45
|
+
when the traced method was called (undefined method `trace_execution_scoped').
|
46
|
+
This has been fixed.
|
47
|
+
|
48
|
+
This issue was an instance of the Ruby 'dynamic module inclusion' or 'double
|
49
|
+
inclusion' problem. Usage of add_method_tracer now no longer relies upon the
|
50
|
+
target class having actually picked up the trace_execution_scoped method from
|
51
|
+
the NewRelic::Agent::MethodTracer module.
|
52
|
+
|
53
|
+
* Improved performance of queue time parsing
|
54
|
+
|
55
|
+
The number of objects allocated while parsing the front-end timestamps on
|
56
|
+
incoming HTTP requests has been significantly reduced.
|
57
|
+
|
58
|
+
Thanks to Aleksei Magusev for the contribution!
|
59
|
+
|
3
60
|
## v3.9.4 ##
|
4
61
|
|
5
62
|
* Allow agent to use alternate certificate stores
|
data/Guardfile
CHANGED
@@ -4,4 +4,5 @@ guard :minitest, :test_folders => ['test/new_relic'], :all_after_pass => false d
|
|
4
4
|
watch(%r{^test/rum/.*}) { "test/new_relic/rack/browser_monitoring_test.rb" }
|
5
5
|
watch('test/test_helper.rb') { "test/new_relic" }
|
6
6
|
watch('test/agent_helper.rb') { "test/new_relic" }
|
7
|
+
watch('lib/new_relic/agent/configuration/default_source.rb') { "test/new_relic/agent/configuration/orphan_configuration_test.rb" }
|
7
8
|
end
|
@@ -770,7 +770,7 @@ module NewRelic
|
|
770
770
|
:agent_version => NewRelic::VERSION::STRING,
|
771
771
|
:environment => @environment_report,
|
772
772
|
:settings => Agent.config.to_collector_hash,
|
773
|
-
:high_security => Agent.config[:high_security]
|
773
|
+
:high_security => Agent.config[:high_security]
|
774
774
|
}
|
775
775
|
end
|
776
776
|
|
@@ -811,8 +811,8 @@ module NewRelic
|
|
811
811
|
Agent.config.replace_or_add_config(server_config)
|
812
812
|
log_connection!(config_data) if @service
|
813
813
|
|
814
|
-
@transaction_rules = RulesEngine.
|
815
|
-
@stats_engine.metric_rules = RulesEngine.
|
814
|
+
@transaction_rules = RulesEngine.create_transaction_rules(config_data)
|
815
|
+
@stats_engine.metric_rules = RulesEngine.create_metric_rules(config_data)
|
816
816
|
|
817
817
|
# If you're adding something else here to respond to the server-side config,
|
818
818
|
# use Agent.instance.events.subscribe(:finished_configuring) callback instead!
|
@@ -35,8 +35,11 @@ module NewRelic
|
|
35
35
|
@log.info("REQUEST: #{uri}")
|
36
36
|
@log.info("REQUEST BODY: #{request_body}")
|
37
37
|
end
|
38
|
-
rescue SystemCallError => e
|
39
|
-
::NewRelic::Agent.logger.warn("Failed writing to audit log
|
38
|
+
rescue StandardError, SystemStackError, SystemCallError => e
|
39
|
+
::NewRelic::Agent.logger.warn("Failed writing to audit log", e)
|
40
|
+
rescue Exception => e
|
41
|
+
::NewRelic::Agent.logger.warn("Failed writing to audit log with exception. Re-raising in case of interupt.", e)
|
42
|
+
raise
|
40
43
|
end
|
41
44
|
|
42
45
|
def setup_logger
|
@@ -659,7 +659,7 @@ module NewRelic
|
|
659
659
|
:default => true,
|
660
660
|
:public => true,
|
661
661
|
:type => Boolean,
|
662
|
-
:description => 'Enable or disable the collection of explain plans.'
|
662
|
+
:description => 'Enable or disable the collection of explain plans in transaction traces. This setting will also apply to explain plans in Slow SQL traces if slow_sql.explain_enabled is not set separately.'
|
663
663
|
},
|
664
664
|
:'transaction_tracer.stack_trace_threshold' => {
|
665
665
|
:default => 0.5,
|
@@ -709,7 +709,7 @@ module NewRelic
|
|
709
709
|
:default => DefaultSource.slow_sql_explain_enabled,
|
710
710
|
:public => true,
|
711
711
|
:type => Boolean,
|
712
|
-
:description => 'Enable or disable the collection of explain plans in slow SQL queries.'
|
712
|
+
:description => 'Enable or disable the collection of explain plans in slow SQL queries. If this setting is omitted, the transaction_tracer.explain_enabled setting will be applied as the default setting for explain plans in Slow SQL as well.'
|
713
713
|
},
|
714
714
|
:'slow_sql.record_sql' => {
|
715
715
|
:default => DefaultSource.slow_sql_record_sql,
|
@@ -1032,12 +1032,18 @@ module NewRelic
|
|
1032
1032
|
:type => Boolean,
|
1033
1033
|
:description => 'Defines whether the agent will wrap third-party middlewares in instrumentation (regardless of whether they are installed via Rack::Builder or Rails).'
|
1034
1034
|
},
|
1035
|
-
:
|
1036
|
-
:default =>
|
1037
|
-
:public =>
|
1035
|
+
:'heroku.use_dyno_names' => {
|
1036
|
+
:default => true,
|
1037
|
+
:public => true,
|
1038
1038
|
:type => Boolean,
|
1039
1039
|
:description => 'Controls whether or not we use the heroku dyno name as the hostname.'
|
1040
1040
|
},
|
1041
|
+
:'heroku.dyno_name_prefixes_to_shorten' => {
|
1042
|
+
:default => ['scheduler', 'run'],
|
1043
|
+
:public => true,
|
1044
|
+
:type => Array,
|
1045
|
+
:description => 'List of prefixes for heroku dyno names (such as "scheduler") to report as hostname without trailing dot and process ID.'
|
1046
|
+
},
|
1041
1047
|
:labels => {
|
1042
1048
|
:default => '',
|
1043
1049
|
:public => true,
|
@@ -133,6 +133,19 @@ module NewRelic
|
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
136
|
+
def aggregated_metric_names(txn)
|
137
|
+
metric_names = ["Errors/all"]
|
138
|
+
return metric_names unless txn
|
139
|
+
|
140
|
+
if txn.recording_web_transaction?
|
141
|
+
metric_names << "Errors/allWeb"
|
142
|
+
else
|
143
|
+
metric_names << "Errors/allOther"
|
144
|
+
end
|
145
|
+
|
146
|
+
metric_names
|
147
|
+
end
|
148
|
+
|
136
149
|
# Increments a statistic that tracks total error rate
|
137
150
|
# Be sure not to double-count same exception. This clears per harvest.
|
138
151
|
def increment_error_count!(exception, options={}) #THREAD_LOCAL_ACCESS
|
@@ -142,7 +155,7 @@ module NewRelic
|
|
142
155
|
return if seen?(txn, exception)
|
143
156
|
tag_as_seen(txn, exception)
|
144
157
|
|
145
|
-
metric_names
|
158
|
+
metric_names = aggregated_metric_names(txn)
|
146
159
|
blamed_metric = blamed_metric_name(txn, options)
|
147
160
|
metric_names << blamed_metric if blamed_metric
|
148
161
|
|
@@ -6,12 +6,33 @@ module NewRelic
|
|
6
6
|
module Agent
|
7
7
|
module Hostname
|
8
8
|
def self.get
|
9
|
-
|
9
|
+
dyno_name = ENV['DYNO']
|
10
|
+
if dyno_name && ::NewRelic::Agent.config[:'heroku.use_dyno_names']
|
11
|
+
matching_prefix = heroku_dyno_name_prefix(dyno_name)
|
12
|
+
dyno_name = "#{matching_prefix}.*" if matching_prefix
|
10
13
|
dyno_name
|
11
14
|
else
|
12
15
|
Socket.gethostname
|
13
16
|
end
|
14
17
|
end
|
18
|
+
|
19
|
+
def self.heroku_dyno_name_prefix(dyno_name)
|
20
|
+
get_dyno_prefixes.find do |dyno_prefix|
|
21
|
+
dyno_name.start_with?(dyno_prefix + ".")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# TODO: Once config transforms are in, use those instead of handcoding
|
26
|
+
def self.get_dyno_prefixes
|
27
|
+
dyno_prefixes = ::NewRelic::Agent.config[:'heroku.dyno_name_prefixes_to_shorten'] || []
|
28
|
+
if dyno_prefixes.is_a?(String)
|
29
|
+
dyno_prefixes = dyno_prefixes.split(',')
|
30
|
+
elsif !dyno_prefixes.respond_to?(:find)
|
31
|
+
::NewRelic::Agent.logger.warn("Ignoring invalid setting found for 'heroku.dyno_name_prefixes_to_shorten', #{dyno_prefixes}.")
|
32
|
+
dyno_prefixes = []
|
33
|
+
end
|
34
|
+
dyno_prefixes
|
35
|
+
end
|
15
36
|
end
|
16
37
|
end
|
17
38
|
end
|
@@ -52,10 +52,16 @@ module NewRelic
|
|
52
52
|
begin
|
53
53
|
Transaction.start(state, category, opts)
|
54
54
|
if target == self
|
55
|
-
traced_call(env)
|
55
|
+
result = traced_call(env)
|
56
56
|
else
|
57
|
-
target.call(env)
|
57
|
+
result = target.call(env)
|
58
58
|
end
|
59
|
+
|
60
|
+
if result.is_a?(Array)
|
61
|
+
state.current_transaction.http_response_code = result[0]
|
62
|
+
end
|
63
|
+
|
64
|
+
result
|
59
65
|
rescue => e
|
60
66
|
NewRelic::Agent.notice_error(e)
|
61
67
|
raise
|
@@ -16,13 +16,15 @@ module NewRelic
|
|
16
16
|
ALL_QUEUE_METRIC = 'WebFrontend/QueueTime'.freeze
|
17
17
|
# any timestamps before this are thrown out and the parser
|
18
18
|
# will try again with a larger unit (2000/1/1 UTC)
|
19
|
-
|
19
|
+
EARLIEST_ACCEPTABLE_TIME = Time.at(946684800)
|
20
20
|
|
21
21
|
CANDIDATE_HEADERS = [
|
22
22
|
REQUEST_START_HEADER,
|
23
23
|
QUEUE_START_HEADER,
|
24
24
|
MIDDLEWARE_START_HEADER
|
25
25
|
].freeze
|
26
|
+
|
27
|
+
DIVISORS = [1_000_000, 1_000, 1]
|
26
28
|
end
|
27
29
|
|
28
30
|
module_function
|
@@ -62,17 +64,18 @@ module NewRelic
|
|
62
64
|
end
|
63
65
|
|
64
66
|
def parse_timestamp(string)
|
65
|
-
|
66
|
-
[1_000_000, 1_000, 1].map do |divisor|
|
67
|
+
DIVISORS.each do |divisor|
|
67
68
|
begin
|
68
|
-
Time.at(string.to_f / divisor)
|
69
|
+
t = Time.at(string.to_f / divisor)
|
70
|
+
return t if t > EARLIEST_ACCEPTABLE_TIME
|
69
71
|
rescue RangeError
|
70
72
|
# On Ruby versions built with a 32-bit time_t, attempting to
|
71
73
|
# instantiate a Time object in the far future raises a RangeError,
|
72
74
|
# in which case we know we've chosen the wrong divisor.
|
73
|
-
nil
|
74
75
|
end
|
75
|
-
end
|
76
|
+
end
|
77
|
+
|
78
|
+
nil
|
76
79
|
end
|
77
80
|
end
|
78
81
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
4
|
|
5
5
|
require 'new_relic/control'
|
6
|
+
require 'new_relic/agent/method_tracer_helpers'
|
7
|
+
|
6
8
|
module NewRelic
|
7
9
|
module Agent
|
8
10
|
# This module contains class methods added to support installing custom
|
@@ -49,18 +51,22 @@ module NewRelic
|
|
49
51
|
clazz.extend ClassMethods
|
50
52
|
end
|
51
53
|
|
52
|
-
#
|
53
|
-
#
|
54
|
+
# Trace a given block with stats and keep track of the caller.
|
55
|
+
# See NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer for a description of the arguments.
|
56
|
+
# +metric_names+ is either a single name or an array of metric names.
|
57
|
+
# If more than one metric is passed, the +produce_metric+ option only applies to the first. The
|
58
|
+
# others are always recorded. Only the first metric is pushed onto the scope stack.
|
59
|
+
#
|
60
|
+
# Generally you pass an array of metric names if you want to record the metric under additional
|
61
|
+
# categories, but generally this *should never ever be done*. Most of the time you can aggregate
|
62
|
+
# on the server.
|
54
63
|
#
|
55
64
|
# @api public
|
56
|
-
# @deprecated
|
57
65
|
#
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
else
|
63
|
-
trace_execution_unscoped(metric_names, &block)
|
66
|
+
def trace_execution_scoped(metric_names, options={}) #THREAD_LOCAL_ACCESS
|
67
|
+
NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(metric_names, options) do
|
68
|
+
# Using an implicit block avoids object allocation for a &block param
|
69
|
+
yield
|
64
70
|
end
|
65
71
|
end
|
66
72
|
|
@@ -79,7 +85,22 @@ module NewRelic
|
|
79
85
|
yield
|
80
86
|
ensure
|
81
87
|
duration = (Time.now - t0).to_f # for some reason this is 3 usec faster than Time - Time
|
82
|
-
|
88
|
+
NewRelic::Agent.instance.stats_engine.tl_record_unscoped_metrics(metric_names, duration)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Deprecated: original method preserved for API backward compatibility.
|
93
|
+
# Use either #trace_execution_scoped or #trace_execution_unscoped
|
94
|
+
#
|
95
|
+
# @api public
|
96
|
+
# @deprecated
|
97
|
+
#
|
98
|
+
def trace_method_execution(metric_names, push_scope, produce_metric, deduct_call_time_from_parent, &block) #:nodoc:
|
99
|
+
if push_scope
|
100
|
+
trace_execution_scoped(metric_names, :metric => produce_metric,
|
101
|
+
:deduct_call_time_from_parent => deduct_call_time_from_parent, &block)
|
102
|
+
else
|
103
|
+
trace_execution_unscoped(metric_names, &block)
|
83
104
|
end
|
84
105
|
end
|
85
106
|
|
@@ -96,147 +117,27 @@ module NewRelic
|
|
96
117
|
|
97
118
|
alias trace_method_execution_no_scope trace_execution_unscoped #:nodoc:
|
98
119
|
|
99
|
-
# Refactored out of the previous trace_execution_scoped
|
100
|
-
# method, most methods in this module relate to code used in
|
101
|
-
# the #trace_execution_scoped method in this module
|
102
|
-
module TraceExecutionScoped
|
103
|
-
extend self
|
104
|
-
|
105
|
-
# Shorthand to return the NewRelic::Agent.instance
|
106
|
-
def agent_instance
|
107
|
-
NewRelic::Agent.instance
|
108
|
-
end
|
109
|
-
|
110
|
-
# Shorthand to return the current statistics engine
|
111
|
-
def stat_engine
|
112
|
-
agent_instance.stats_engine
|
113
|
-
end
|
114
|
-
|
115
|
-
# returns a scoped metric stat for the specified name
|
116
|
-
def get_stats_scoped(first_name, scoped_metric_only)
|
117
|
-
stat_engine.get_stats(first_name, true, scoped_metric_only)
|
118
|
-
end
|
119
|
-
|
120
|
-
# Shorthand method to get stats from the stat engine
|
121
|
-
def get_stats_unscoped(name)
|
122
|
-
stat_engine.get_stats_no_scope(name)
|
123
|
-
end
|
124
|
-
|
125
|
-
# Helper for setting a hash key if the hash key is nil,
|
126
|
-
# instead of the default ||= behavior which sets if it is
|
127
|
-
# false as well
|
128
|
-
def set_if_nil(hash, key)
|
129
|
-
hash[key] = true if hash[key].nil?
|
130
|
-
end
|
131
|
-
|
132
|
-
# helper for logging errors to the newrelic_agent.log
|
133
|
-
# properly. Logs the error at error level
|
134
|
-
def log_errors(code_area)
|
135
|
-
yield
|
136
|
-
rescue => e
|
137
|
-
::NewRelic::Agent.logger.error("Caught exception in #{code_area}.", e)
|
138
|
-
end
|
139
|
-
|
140
|
-
# provides the header for our traced execution scoped
|
141
|
-
# method - gets the initial time, sets the tracing flag if
|
142
|
-
# needed, and pushes the frame onto the metric stack
|
143
|
-
# logs any errors that occur and returns the start time and
|
144
|
-
# the frame so that we can check for it later, to maintain
|
145
|
-
# sanity. If the frame stack becomes unbalanced, this
|
146
|
-
# transaction loses meaning.
|
147
|
-
def trace_execution_scoped_header(state, t0)
|
148
|
-
log_errors(:trace_execution_scoped_header) do
|
149
|
-
stack = state.traced_method_stack
|
150
|
-
stack.push_frame(state, :method_tracer, t0)
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
def record_metrics(state, first_name, other_names, duration, exclusive, options)
|
155
|
-
# The default value for :scoped_metric is true, so set it as true
|
156
|
-
# if it was unset.
|
157
|
-
record_scoped_metric = options.has_key?(:scoped_metric) ? options[:scoped_metric] : true
|
158
|
-
|
159
|
-
if options[:metric]
|
160
|
-
if record_scoped_metric
|
161
|
-
stat_engine.record_scoped_and_unscoped_metrics(state, first_name, other_names, duration, exclusive)
|
162
|
-
else
|
163
|
-
metrics = [first_name].concat(other_names)
|
164
|
-
stat_engine.record_unscoped_metrics(state, metrics, duration, exclusive)
|
165
|
-
end
|
166
|
-
else
|
167
|
-
stat_engine.record_unscoped_metrics(state, other_names, duration, exclusive)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
# Handles the end of the #trace_execution_scoped method -
|
172
|
-
# calculating the time taken, popping the tracing flag if
|
173
|
-
# needed, deducting time taken by children, and tracing the
|
174
|
-
# subsidiary unscoped metrics if any
|
175
|
-
#
|
176
|
-
# this method fails safely if the header does not manage to
|
177
|
-
# push the scope onto the stack - it simply does not trace
|
178
|
-
# any metrics.
|
179
|
-
def trace_execution_scoped_footer(state, t0, first_name, metric_names, expected_frame, options, t1=Time.now.to_f)
|
180
|
-
log_errors(:trace_method_execution_footer) do
|
181
|
-
if expected_frame
|
182
|
-
stack = state.traced_method_stack
|
183
|
-
frame = stack.pop_frame(state, expected_frame, first_name, t1, !!options[:metric])
|
184
|
-
duration = t1 - t0
|
185
|
-
if duration < 1_000_000_000 # roughly 31 years
|
186
|
-
if duration < 0
|
187
|
-
::NewRelic::Agent.logger.log_once(:warn, "metric_duration_negative:#{first_name}",
|
188
|
-
"Metric #{first_name} has negative duration: #{duration} s")
|
189
|
-
end
|
190
|
-
|
191
|
-
exclusive = duration - frame.children_time
|
192
|
-
if exclusive < 0
|
193
|
-
::NewRelic::Agent.logger.log_once(:warn, "metric_exclusive_negative:#{first_name}",
|
194
|
-
"Metric #{first_name} has negative exclusive time: duration = #{duration} s, child_time = #{frame.children_time}")
|
195
|
-
end
|
196
|
-
|
197
|
-
record_metrics(state, first_name, metric_names, duration, exclusive, options)
|
198
|
-
else
|
199
|
-
::NewRelic::Agent.logger.log_once(:warn, "too_huge_metric:#{first_name}",
|
200
|
-
"Ignoring metric #{first_name} with unacceptably large duration: #{duration} s")
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
include TraceExecutionScoped
|
207
|
-
|
208
|
-
# Trace a given block with stats and keep track of the caller.
|
209
|
-
# See NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer for a description of the arguments.
|
210
|
-
# +metric_names+ is either a single name or an array of metric names.
|
211
|
-
# If more than one metric is passed, the +produce_metric+ option only applies to the first. The
|
212
|
-
# others are always recorded. Only the first metric is pushed onto the scope stack.
|
213
120
|
#
|
214
|
-
#
|
215
|
-
#
|
216
|
-
#
|
121
|
+
# This method is deprecated and exists only for backwards-compatibility
|
122
|
+
# reasons. Usages should be replaced with calls to
|
123
|
+
# NewRelic::Agent.record_metric.
|
217
124
|
#
|
218
125
|
# @api public
|
126
|
+
# @deprecated
|
219
127
|
#
|
220
|
-
def
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
metric_names = Array(metric_names)
|
225
|
-
first_name = metric_names.shift
|
226
|
-
return yield if first_name.nil?
|
227
|
-
|
228
|
-
set_if_nil(options, :metric)
|
229
|
-
additional_metrics_callback = options[:additional_metrics_callback]
|
230
|
-
start_time = Time.now.to_f
|
231
|
-
expected_scope = trace_execution_scoped_header(state, start_time)
|
128
|
+
def get_stats_scoped(first_name, scoped_metric_only)
|
129
|
+
NewRelic::Agent.instance.stats_engine.get_stats(first_name, true, scoped_metric_only)
|
130
|
+
end
|
232
131
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
132
|
+
# This method is deprecated and exists only for backwards-compatibility
|
133
|
+
# reasons. Usages should be replaced with calls to
|
134
|
+
# NewRelic::Agent.record_metric.
|
135
|
+
#
|
136
|
+
# @api public
|
137
|
+
# @deprecated
|
138
|
+
#
|
139
|
+
def get_stats_unscoped(name)
|
140
|
+
NewRelic::Agent.instance.stats_engine.get_stats_no_scope(name)
|
240
141
|
end
|
241
142
|
|
242
143
|
# Defines methods used at the class level, for adding instrumentation
|
@@ -324,11 +225,9 @@ module NewRelic
|
|
324
225
|
# instrumentation into effectively one method call overhead
|
325
226
|
# when the agent is disabled
|
326
227
|
def assemble_code_header(method_name, metric_name_code, options)
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
header
|
228
|
+
header = "return #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) unless NewRelic::Agent.tl_is_execution_traced?\n"
|
229
|
+
header += options[:code_header].to_s
|
230
|
+
header
|
332
231
|
end
|
333
232
|
|
334
233
|
# returns an eval-able string that contains the traced
|
@@ -351,29 +250,9 @@ module NewRelic
|
|
351
250
|
# returns an eval-able string that contains the tracing code
|
352
251
|
# for a fully traced metric including scoping
|
353
252
|
def method_with_push_scope(method_name, metric_name_code, options)
|
354
|
-
# At this point, we expect 'self' to point to a Class or Module that
|
355
|
-
# has included the NewRelic::Agent::MethodTracer module, which means
|
356
|
-
# it should have an instance method defined called
|
357
|
-
# 'trace_execution_scoped'.
|
358
|
-
#
|
359
|
-
# If this is not the case, assume that
|
360
|
-
# we're relying on the fact that MethodTracer is included into the
|
361
|
-
# Module class by init_plugin, and try to call
|
362
|
-
# trace_execution_scoped as a class rather than instance method.
|
363
|
-
#
|
364
|
-
# The inclusion of MethodTracer into Module will be going away in
|
365
|
-
# the future, so if we detect people relying on that behavior, warn
|
366
|
-
# and record a supportability metric.
|
367
|
-
if self.method_defined?(:trace_execution_scoped)
|
368
|
-
klass = 'self'
|
369
|
-
else
|
370
|
-
NewRelic::Agent.logger.warn("Called add_method_tracer from #{self} without including the NewRelic::Agent::MethodTracer module. This is deprecated and will stop working in the future. Please see http://docs.newrelic.com/docs/ruby/ruby-custom-metric-collection for examples of correct add_method_tracer usage.")
|
371
|
-
NewRelic::Agent.increment_metric("Supportability/usage/improper_add_method_tracer")
|
372
|
-
klass = 'self.class'
|
373
|
-
end
|
374
253
|
"def #{_traced_method_name(method_name, metric_name_code)}(*args, &block)
|
375
254
|
#{options[:code_header]}
|
376
|
-
result =
|
255
|
+
result = ::NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(\"#{metric_name_code}\",
|
377
256
|
:metric => #{options[:metric]}) do
|
378
257
|
#{_untraced_method_name(method_name, metric_name_code)}(*args, &block)
|
379
258
|
end
|