newrelic_rpm 7.0.0 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +68 -0
- data/CONTRIBUTING.md +13 -2
- data/lib/new_relic/agent.rb +5 -2
- data/lib/new_relic/agent/agent.rb +2 -1
- data/lib/new_relic/agent/configuration/default_source.rb +200 -151
- data/lib/new_relic/agent/configuration/manager.rb +1 -1
- data/lib/new_relic/agent/connect/request_builder.rb +4 -2
- data/lib/new_relic/agent/error_collector.rb +52 -37
- data/lib/new_relic/agent/error_filter.rb +167 -0
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +1 -3
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -0
- data/lib/new_relic/agent/instrumentation/net_http.rb +6 -1
- data/lib/new_relic/agent/instrumentation/rack/chain.rb +3 -2
- data/lib/new_relic/agent/instrumentation/rack/prepend.rb +2 -1
- data/lib/new_relic/agent/instrumentation/redis.rb +4 -0
- data/lib/new_relic/agent/instrumentation/resque.rb +13 -4
- data/lib/new_relic/agent/instrumentation/resque/helper.rb +19 -0
- data/lib/new_relic/agent/instrumentation/resque/instrumentation.rb +5 -3
- data/lib/new_relic/agent/instrumentation/sinatra/instrumentation.rb +8 -2
- data/lib/new_relic/agent/javascript_instrumentor.rb +12 -7
- data/lib/new_relic/agent/new_relic_service.rb +12 -1
- data/lib/new_relic/agent/sql_sampler.rb +2 -2
- data/lib/new_relic/noticed_error.rb +3 -3
- data/lib/new_relic/version.rb +1 -1
- data/lib/tasks/config.html.erb +14 -25
- data/lib/tasks/config.rake +8 -7
- metadata +4 -2
@@ -80,6 +80,7 @@ module NewRelic
|
|
80
80
|
was_finished = finished_configuring?
|
81
81
|
|
82
82
|
invoke_callbacks(:add, source)
|
83
|
+
|
83
84
|
case source
|
84
85
|
when SecurityPolicySource then @security_policy_source = source
|
85
86
|
when HighSecuritySource then @high_security_source = source
|
@@ -159,7 +160,6 @@ module NewRelic
|
|
159
160
|
def invoke_callbacks(direction, source)
|
160
161
|
return unless source
|
161
162
|
source.keys.each do |key|
|
162
|
-
|
163
163
|
if @cache[key] != source[key]
|
164
164
|
@callbacks[key].each do |proc|
|
165
165
|
if direction == :add
|
@@ -48,8 +48,10 @@ module NewRelic
|
|
48
48
|
environment_report
|
49
49
|
end
|
50
50
|
|
51
|
-
def environment_metadata
|
52
|
-
|
51
|
+
def environment_metadata
|
52
|
+
env_copy = {}
|
53
|
+
ENV.keys.each {|k| env_copy[k] = ENV[k] if k =~ /^NEW_RELIC_METADATA_/}
|
54
|
+
env_copy
|
53
55
|
end
|
54
56
|
|
55
57
|
def local_host
|
@@ -22,23 +22,18 @@ module NewRelic
|
|
22
22
|
@error_trace_aggregator = ErrorTraceAggregator.new(MAX_ERROR_QUEUE_LENGTH)
|
23
23
|
@error_event_aggregator = ErrorEventAggregator.new events
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
@error_filter = NewRelic::Agent::ErrorFilter.new
|
26
|
+
|
27
|
+
%w(
|
28
|
+
ignore_errors ignore_classes ignore_messages ignore_status_codes
|
29
|
+
expected_classes expected_messages expected_status_codes
|
30
|
+
).each do |w|
|
31
|
+
Agent.config.register_callback(:"error_collector.#{w}") do |value|
|
32
|
+
@error_filter.load_from_config(w, value)
|
33
|
+
end
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
def initialize_ignored_errors(ignore_errors)
|
36
|
-
@ignore.clear
|
37
|
-
ignore_errors = ignore_errors.split(",") if ignore_errors.is_a? String
|
38
|
-
ignore_errors.each { |error| error.strip! }
|
39
|
-
ignore(ignore_errors)
|
40
|
-
end
|
41
|
-
|
42
37
|
def enabled?
|
43
38
|
error_trace_aggregator.enabled? || error_event_aggregator.enabled?
|
44
39
|
end
|
@@ -76,30 +71,39 @@ module NewRelic
|
|
76
71
|
defined?(@ignore_filter) ? @ignore_filter : nil
|
77
72
|
end
|
78
73
|
|
79
|
-
# errors is an array of Exception Class Names
|
80
|
-
#
|
81
74
|
def ignore(errors)
|
82
|
-
errors
|
83
|
-
|
84
|
-
|
85
|
-
|
75
|
+
@error_filter.ignore(errors)
|
76
|
+
end
|
77
|
+
|
78
|
+
def ignore?(ex, status_code = nil)
|
79
|
+
@error_filter.ignore?(ex, status_code)
|
80
|
+
end
|
81
|
+
|
82
|
+
def expect(errors)
|
83
|
+
@error_filter.expect(errors)
|
84
|
+
end
|
85
|
+
|
86
|
+
def expected?(ex, status_code = nil)
|
87
|
+
@error_filter.expected?(ex, status_code)
|
88
|
+
end
|
89
|
+
|
90
|
+
def load_error_filters
|
91
|
+
@error_filter.load_all
|
92
|
+
end
|
93
|
+
|
94
|
+
def reset_error_filters
|
95
|
+
@error_filter.reset
|
86
96
|
end
|
87
97
|
|
88
98
|
# Checks the provided error against the error filter, if there
|
89
99
|
# is an error filter
|
90
|
-
def
|
100
|
+
def ignored_by_filter_proc?(error)
|
91
101
|
respond_to?(:ignore_filter_proc) && !ignore_filter_proc(error)
|
92
102
|
end
|
93
103
|
|
94
|
-
# Checks the array of error names and the error filter against
|
95
|
-
# the provided error
|
96
|
-
def filtered_error?(error)
|
97
|
-
@ignore[error.class.name] || filtered_by_error_filter?(error)
|
98
|
-
end
|
99
|
-
|
100
104
|
# an error is ignored if it is nil or if it is filtered
|
101
|
-
def error_is_ignored?(error)
|
102
|
-
error &&
|
105
|
+
def error_is_ignored?(error, status_code = nil)
|
106
|
+
error && (@error_filter.ignore?(error, status_code) || ignored_by_filter_proc?(error))
|
103
107
|
rescue => e
|
104
108
|
NewRelic::Agent.logger.error("Error '#{error}' will NOT be ignored. Exception '#{e}' while determining whether to ignore or not.", e)
|
105
109
|
false
|
@@ -174,11 +178,18 @@ module NewRelic
|
|
174
178
|
end
|
175
179
|
end
|
176
180
|
|
177
|
-
def
|
181
|
+
def increment_expected_error_count!(state, exception)
|
182
|
+
stats_engine = NewRelic::Agent.agent.stats_engine
|
183
|
+
stats_engine.record_unscoped_metrics(state, ['ErrorsExpected/all']) do |stats|
|
184
|
+
stats.increment_count
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def skip_notice_error?(exception, status_code = nil)
|
178
189
|
disabled? ||
|
179
|
-
error_is_ignored?(exception) ||
|
180
190
|
exception.nil? ||
|
181
|
-
exception_tagged_with?(EXCEPTION_TAG_IVAR, exception)
|
191
|
+
exception_tagged_with?(EXCEPTION_TAG_IVAR, exception) ||
|
192
|
+
error_is_ignored?(exception, status_code)
|
182
193
|
end
|
183
194
|
|
184
195
|
# calls a method on an object, if it responds to it - used for
|
@@ -210,13 +221,17 @@ module NewRelic
|
|
210
221
|
|
211
222
|
# See NewRelic::Agent.notice_error for options and commentary
|
212
223
|
def notice_error(exception, options={}, span_id=nil)
|
213
|
-
|
224
|
+
state = ::NewRelic::Agent::Tracer.state
|
225
|
+
transaction = state.current_transaction
|
226
|
+
status_code = transaction ? transaction.http_response_code : nil
|
214
227
|
|
215
|
-
|
228
|
+
return if skip_notice_error?(exception, status_code)
|
216
229
|
|
217
|
-
|
230
|
+
tag_exception(exception)
|
218
231
|
|
219
|
-
|
232
|
+
if options[:expected] || @error_filter.expected?(exception, status_code)
|
233
|
+
increment_expected_error_count!(state, exception)
|
234
|
+
else
|
220
235
|
increment_error_count!(state, exception, options)
|
221
236
|
end
|
222
237
|
|
@@ -258,7 +273,7 @@ module NewRelic
|
|
258
273
|
noticed_error.line_number = sense_method(exception, :line_number)
|
259
274
|
noticed_error.stack_trace = truncate_trace(extract_stack_trace(exception))
|
260
275
|
|
261
|
-
noticed_error.expected = !!
|
276
|
+
noticed_error.expected = !!options.delete(:expected) || expected?(exception)
|
262
277
|
|
263
278
|
noticed_error.attributes_from_notice_error = options.delete(:custom_params) || {}
|
264
279
|
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic
|
6
|
+
module Agent
|
7
|
+
|
8
|
+
# Handles loading of ignored and expected errors from the agent configuration, and
|
9
|
+
# determining at runtime whether an exception is ignored or expected.
|
10
|
+
class ErrorFilter
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
reset
|
14
|
+
end
|
15
|
+
|
16
|
+
def reset
|
17
|
+
@ignore_classes, @expected_classes = [], []
|
18
|
+
@ignore_messages, @expected_messages = {}, {}
|
19
|
+
@ignore_status_codes, @expected_status_codes = [], []
|
20
|
+
end
|
21
|
+
|
22
|
+
def load_all
|
23
|
+
%i(
|
24
|
+
ignore_errors ignore_classes ignore_messages ignore_status_codes
|
25
|
+
expected_classes expected_messages expected_status_codes
|
26
|
+
).each { |setting| load_from_config(setting) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def load_from_config(setting, value = nil)
|
30
|
+
errors = nil
|
31
|
+
new_value = value || fetch_agent_config(setting.to_sym)
|
32
|
+
return if new_value.nil? || new_value.empty?
|
33
|
+
|
34
|
+
case setting.to_sym
|
35
|
+
when :ignore_errors, :ignore_classes
|
36
|
+
new_value = new_value.split(',').map!(&:strip) if new_value.is_a?(String)
|
37
|
+
errors = @ignore_classes = new_value
|
38
|
+
when :ignore_messages
|
39
|
+
errors = @ignore_messages = new_value || {}
|
40
|
+
when :ignore_status_codes
|
41
|
+
errors = @ignore_status_codes = parse_status_codes(new_value) || []
|
42
|
+
when :expected_classes
|
43
|
+
errors = @expected_classes = new_value || []
|
44
|
+
when :expected_messages
|
45
|
+
errors = @expected_messages = new_value || {}
|
46
|
+
when :expected_status_codes
|
47
|
+
errors = @expected_status_codes = parse_status_codes(new_value) || []
|
48
|
+
end
|
49
|
+
log_filter(setting, errors) if errors
|
50
|
+
end
|
51
|
+
|
52
|
+
def ignore?(ex, status_code = nil)
|
53
|
+
@ignore_classes.include?(ex.class.name) ||
|
54
|
+
(@ignore_messages.keys.include?(ex.class.name) &&
|
55
|
+
@ignore_messages[ex.class.name].any? { |m| ex.message.include?(m) }) ||
|
56
|
+
@ignore_status_codes.include?(status_code.to_i)
|
57
|
+
end
|
58
|
+
|
59
|
+
def expected?(ex, status_code = nil)
|
60
|
+
@expected_classes.include?(ex.class.name) ||
|
61
|
+
(@expected_messages.keys.include?(ex.class.name) &&
|
62
|
+
@expected_messages[ex.class.name].any? { |m| ex.message.include?(m) }) ||
|
63
|
+
@expected_status_codes.include?(status_code.to_i)
|
64
|
+
end
|
65
|
+
|
66
|
+
def fetch_agent_config(cfg)
|
67
|
+
NewRelic::Agent.config[:"error_collector.#{cfg}"]
|
68
|
+
end
|
69
|
+
|
70
|
+
# A generic method for adding ignore filters manually. This is kept for compatibility
|
71
|
+
# with the previous ErrorCollector#ignore method, and adds some flexibility for adding
|
72
|
+
# different ignore/expected error types by examining each argument.
|
73
|
+
def ignore(*args)
|
74
|
+
args.each do |errors|
|
75
|
+
case errors
|
76
|
+
when Array
|
77
|
+
errors.each { |e| ignore(e) }
|
78
|
+
when Integer
|
79
|
+
@ignore_status_codes << errors
|
80
|
+
when Hash
|
81
|
+
@ignore_messages.update(errors)
|
82
|
+
log_filter(:ignore_messages, errors)
|
83
|
+
when String
|
84
|
+
if errors.match(/^[\d\,\-]+$/)
|
85
|
+
@ignore_status_codes |= parse_status_codes(errors)
|
86
|
+
log_filter(:ignore_status_codes, errors)
|
87
|
+
else
|
88
|
+
new_ignore_classes = errors.split(',').map!(&:strip)
|
89
|
+
@ignore_classes |= new_ignore_classes
|
90
|
+
log_filter(:ignore_classes, new_ignore_classes)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# See #ignore above.
|
97
|
+
def expect(*args)
|
98
|
+
args.each do |errors|
|
99
|
+
case errors
|
100
|
+
when Array
|
101
|
+
errors.each { |e| expect(e) }
|
102
|
+
when Integer
|
103
|
+
@expected_status_codes << errors
|
104
|
+
when Hash
|
105
|
+
@expected_messages.update(errors)
|
106
|
+
log_filter(:expected_messages, errors)
|
107
|
+
when String
|
108
|
+
if errors.match(/^[\d\,\-]+$/)
|
109
|
+
@expected_status_codes |= parse_status_codes(errors)
|
110
|
+
log_filter(:expected_status_codes, errors)
|
111
|
+
else
|
112
|
+
new_expected_classes = errors.split(',').map!(&:strip)
|
113
|
+
@expected_classes |= new_expected_classes
|
114
|
+
log_filter(:expected_classes, new_expected_classes)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def log_filter(setting, errors)
|
123
|
+
case setting
|
124
|
+
when :ignore_errors, :ignore_classes
|
125
|
+
errors.each do |error|
|
126
|
+
::NewRelic::Agent.logger.debug("Ignoring errors of type '#{error}'")
|
127
|
+
end
|
128
|
+
when :ignore_messages
|
129
|
+
errors.each do |error,messages|
|
130
|
+
::NewRelic::Agent.logger.debug("Ignoring errors of type '#{error}' with messages: #{messages.join(',')}")
|
131
|
+
end
|
132
|
+
when :ignore_status_codes
|
133
|
+
::NewRelic::Agent.logger.debug("Ignoring errors associated with status codes: #{errors}")
|
134
|
+
when :expected_classes
|
135
|
+
errors.each do |error|
|
136
|
+
::NewRelic::Agent.logger.debug("Expecting errors of type '#{error}'")
|
137
|
+
end
|
138
|
+
when :expected_messages
|
139
|
+
errors.each do |error,messages|
|
140
|
+
::NewRelic::Agent.logger.debug("Expecting errors of type '#{error}' with messages: #{messages.join(',')}")
|
141
|
+
end
|
142
|
+
when :expected_status_codes
|
143
|
+
::NewRelic::Agent.logger.debug("Expecting errors associated with status codes: #{errors}")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def parse_status_codes(codes)
|
148
|
+
code_list = codes.is_a?(String) ? codes.split(',') : codes
|
149
|
+
result = []
|
150
|
+
code_list.each do |code|
|
151
|
+
result << code && next if code.is_a?(Integer)
|
152
|
+
m = code.match(/(\d{3})(-\d{3})?/)
|
153
|
+
if m.nil? || m[1].nil?
|
154
|
+
::NewRelic::Agent.logger.warn("Invalid HTTP status code: '#{code}'; ignoring config")
|
155
|
+
next
|
156
|
+
end
|
157
|
+
if m[2]
|
158
|
+
result += (m[1]..m[2].tr('-', '')).to_a.map(&:to_i)
|
159
|
+
else
|
160
|
+
result << m[1].to_i
|
161
|
+
end
|
162
|
+
end
|
163
|
+
result.uniq
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -84,8 +84,6 @@ module NewRelic
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def active_record_config(payload)
|
87
|
-
return unless payload[:connection_id]
|
88
|
-
|
89
87
|
# handle if the notification payload provides the AR connection
|
90
88
|
# available in Rails 6+ & our ActiveRecordNotifications#log extension
|
91
89
|
if payload[:connection]
|
@@ -93,8 +91,8 @@ module NewRelic
|
|
93
91
|
return connection_config if connection_config
|
94
92
|
end
|
95
93
|
|
94
|
+
return unless connection_id = payload[:connection_id]
|
96
95
|
connection = nil
|
97
|
-
connection_id = payload[:connection_id]
|
98
96
|
|
99
97
|
::ActiveRecord::Base.connection_handler.connection_pool_list.each do |handler|
|
100
98
|
connection = handler.connections.detect do |conn|
|
@@ -17,8 +17,13 @@ DependencyDetection.defer do
|
|
17
17
|
require 'new_relic/agent/http_clients/net_http_wrappers'
|
18
18
|
end
|
19
19
|
|
20
|
+
# Airbrake uses method chaining on Net::HTTP in versions < 10.0.2 (10.0.2 updated to prepend for Net:HTTP)
|
20
21
|
conflicts_with_prepend do
|
21
|
-
defined?(::Airbrake)
|
22
|
+
defined?(::Airbrake) && defined?(::Airbrake::AIRBRAKE_VERSION) && ::Gem::Version.create(::Airbrake::AIRBRAKE_VERSION) < ::Gem::Version.create('10.0.2')
|
23
|
+
end
|
24
|
+
|
25
|
+
conflicts_with_prepend do
|
26
|
+
defined?(::ScoutApm)
|
22
27
|
end
|
23
28
|
|
24
29
|
conflicts_with_prepend do
|
@@ -31,7 +31,8 @@ module NewRelic::Agent::Instrumentation
|
|
31
31
|
def use_with_newrelic(middleware_class, *args, &block)
|
32
32
|
use_with_tracing(middleware_class) { |wrapped_class| use_without_newrelic(wrapped_class, *args, &block) }
|
33
33
|
end
|
34
|
-
|
34
|
+
ruby2_keywords(:use_with_newrelic) if respond_to?(:ruby2_keywords, true)
|
35
|
+
|
35
36
|
alias_method :use_without_newrelic, :use
|
36
37
|
alias_method :use, :use_with_newrelic
|
37
38
|
end
|
@@ -54,4 +55,4 @@ module NewRelic::Agent::Instrumentation
|
|
54
55
|
end
|
55
56
|
end
|
56
57
|
end
|
57
|
-
end
|
58
|
+
end
|
@@ -31,6 +31,7 @@ module NewRelic::Agent::Instrumentation
|
|
31
31
|
def use(middleware_class, *args, &blk)
|
32
32
|
use_with_tracing(middleware_class) { |wrapped_class| super(wrapped_class, *args, &blk) }
|
33
33
|
end
|
34
|
+
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
34
35
|
end
|
35
36
|
end
|
36
|
-
end
|
37
|
+
end
|
@@ -18,6 +18,10 @@ DependencyDetection.defer do
|
|
18
18
|
defined?(::Redis) && defined?(::Redis::VERSION)
|
19
19
|
end
|
20
20
|
|
21
|
+
conflicts_with_prepend do
|
22
|
+
defined?(::PrometheusExporter)
|
23
|
+
end
|
24
|
+
|
21
25
|
depends_on do
|
22
26
|
NewRelic::Agent::Datastores::Redis.is_supported_version? &&
|
23
27
|
NewRelic::Agent::Datastores::Redis.safe_from_third_party_gem?
|
@@ -13,6 +13,11 @@ DependencyDetection.defer do
|
|
13
13
|
defined?(::Resque::Job) && !NewRelic::Agent.config[:disable_resque]
|
14
14
|
end
|
15
15
|
|
16
|
+
# Airbrake uses method chaining on Resque::Job on versions < 11.0.3
|
17
|
+
conflicts_with_prepend do
|
18
|
+
defined?(::Airbrake) && defined?(::Airbrake::AIRBRAKE_VERSION) && ::Gem::Version.create(::Airbrake::AIRBRAKE_VERSION) < ::Gem::Version.create('11.0.3')
|
19
|
+
end
|
20
|
+
|
16
21
|
executes do
|
17
22
|
::NewRelic::Agent.logger.info 'Installing Resque instrumentation'
|
18
23
|
end
|
@@ -32,7 +37,7 @@ DependencyDetection.defer do
|
|
32
37
|
chain_instrument NewRelic::Agent::Instrumentation::Resque::Chain
|
33
38
|
end
|
34
39
|
|
35
|
-
if NewRelic::
|
40
|
+
if NewRelic::Agent::Instrumentation::Resque::Helper.resque_fork_per_job?
|
36
41
|
::Resque.before_first_fork do
|
37
42
|
NewRelic::Agent.manual_start(:dispatcher => :resque,
|
38
43
|
:sync_startup => true,
|
@@ -40,9 +45,7 @@ DependencyDetection.defer do
|
|
40
45
|
end
|
41
46
|
|
42
47
|
::Resque.before_fork do |job|
|
43
|
-
|
44
|
-
NewRelic::Agent.register_report_channel(job.object_id)
|
45
|
-
end
|
48
|
+
NewRelic::Agent.register_report_channel(job.object_id)
|
46
49
|
end
|
47
50
|
|
48
51
|
::Resque.after_fork do |job|
|
@@ -51,6 +54,12 @@ DependencyDetection.defer do
|
|
51
54
|
NewRelic::Agent.after_fork(:report_to_channel => job.object_id,
|
52
55
|
:report_instance_busy => false)
|
53
56
|
end
|
57
|
+
else
|
58
|
+
::Resque.before_first_fork do
|
59
|
+
NewRelic::Agent.manual_start(:dispatcher => :resque,
|
60
|
+
:sync_startup => true,
|
61
|
+
:start_channel_listener => false)
|
62
|
+
end
|
54
63
|
end
|
55
64
|
end
|
56
65
|
end
|