newrelic_rpm 9.23.0 → 10.0.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 +136 -0
- data/README.md +0 -7
- data/lib/new_relic/agent/agent.rb +9 -4
- data/lib/new_relic/agent/configuration/default_source.rb +103 -181
- data/lib/new_relic/agent/configuration/environment_source.rb +7 -38
- data/lib/new_relic/agent/configuration/manager.rb +141 -59
- data/lib/new_relic/agent/configuration/sampler_config_validator.rb +54 -0
- data/lib/new_relic/agent/configuration/server_source.rb +0 -1
- data/lib/new_relic/agent/connect/response_handler.rb +0 -11
- data/lib/new_relic/agent/datastores.rb +13 -17
- data/lib/new_relic/agent/distributed_tracing.rb +0 -3
- data/lib/new_relic/agent/health_check.rb +1 -0
- data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +2 -1
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -4
- data/lib/new_relic/agent/instrumentation/active_support.rb +8 -1
- data/lib/new_relic/agent/instrumentation/active_support_subscriber.rb +22 -14
- data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +1 -4
- data/lib/new_relic/agent/instrumentation/bunny.rb +0 -1
- data/lib/new_relic/agent/instrumentation/curb/chain.rb +2 -2
- data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +2 -3
- data/lib/new_relic/agent/instrumentation/curb.rb +0 -1
- data/lib/new_relic/agent/instrumentation/excon/middleware.rb +1 -1
- data/lib/new_relic/agent/instrumentation/excon.rb +2 -3
- data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +1 -2
- data/lib/new_relic/agent/instrumentation/httpclient.rb +0 -1
- data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
- data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +0 -2
- data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +0 -2
- data/lib/new_relic/agent/instrumentation/rack/helpers.rb +1 -3
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
- data/lib/new_relic/agent/llm/chat_completion_summary.rb +1 -8
- data/lib/new_relic/agent/llm/embedding.rb +1 -8
- data/lib/new_relic/agent/messaging.rb +12 -5
- data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -2
- data/lib/new_relic/agent/monitors/synthetics_monitor.rb +2 -1
- data/lib/new_relic/agent/monitors.rb +0 -3
- data/lib/new_relic/agent/new_relic_service/encoders.rb +0 -14
- data/lib/new_relic/agent/new_relic_service.rb +11 -49
- data/lib/new_relic/agent/opentelemetry/trace/span.rb +41 -0
- data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +16 -7
- data/lib/new_relic/agent/opentelemetry_bridge.rb +9 -5
- data/lib/new_relic/agent/serverless_handler.rb +2 -2
- data/lib/new_relic/agent/span_event_primitive.rb +1 -1
- data/lib/new_relic/agent/sql_sampler.rb +0 -31
- data/lib/new_relic/agent/stats_engine.rb +1 -0
- data/lib/new_relic/agent/transaction/distributed_tracer.rb +12 -56
- data/lib/new_relic/agent/transaction/distributed_tracing.rb +11 -19
- data/lib/new_relic/agent/transaction/external_request_segment.rb +1 -131
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +0 -2
- data/lib/new_relic/agent/transaction/trace_context.rb +33 -11
- data/lib/new_relic/agent/transaction.rb +35 -4
- data/lib/new_relic/agent/transaction_error_primitive.rb +0 -8
- data/lib/new_relic/agent/transaction_event_primitive.rb +0 -14
- data/lib/new_relic/agent/utilization/gcp.rb +2 -0
- data/lib/new_relic/agent.rb +11 -3
- data/lib/new_relic/cli/command.rb +2 -11
- data/lib/new_relic/control/instance_methods.rb +2 -15
- data/lib/new_relic/control/private_instance_methods.rb +2 -4
- data/lib/new_relic/control/server_methods.rb +0 -6
- data/lib/new_relic/helper.rb +21 -2
- data/lib/new_relic/language_support.rb +3 -34
- data/lib/new_relic/supportability_helper.rb +0 -4
- data/lib/new_relic/version.rb +2 -2
- data/lib/tasks/helpers/newrelicyml.rb +2 -2
- data/lib/tasks/helpers/version_bump.rb +1 -2
- data/newrelic.yml +25 -28
- data/newrelic_rpm.gemspec +10 -9
- metadata +27 -26
- data/bin/newrelic +0 -8
- data/lib/new_relic/agent/configuration/security_policy_source.rb +0 -246
- data/lib/new_relic/agent/distributed_tracing/cross_app_payload.rb +0 -44
- data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +0 -253
- data/lib/new_relic/agent/external.rb +0 -112
- data/lib/new_relic/agent/monitors/cross_app_monitor.rb +0 -117
- data/lib/new_relic/agent/new_relic_service/security_policy_settings.rb +0 -61
- data/lib/new_relic/cli/commands/deployments.rb +0 -206
- data/lib/new_relic/recipes/capistrano3.rb +0 -23
- data/lib/new_relic/recipes/capistrano_legacy.rb +0 -95
- data/lib/new_relic/recipes/helpers/send_deployment.rb +0 -70
- data/lib/new_relic/recipes.rb +0 -24
- data/recipes/newrelic.rb +0 -10
|
@@ -13,17 +13,15 @@ module NewRelic
|
|
|
13
13
|
/^NEW_RELIC_METADATA_/ # read by NewRelic::Agent::Connect::RequestBuilder
|
|
14
14
|
]
|
|
15
15
|
|
|
16
|
-
attr_accessor :alias_map
|
|
16
|
+
attr_accessor :alias_map
|
|
17
17
|
|
|
18
18
|
def initialize
|
|
19
19
|
set_log_file
|
|
20
20
|
set_config_file
|
|
21
21
|
|
|
22
22
|
@alias_map = {}
|
|
23
|
-
@type_map = {}
|
|
24
23
|
|
|
25
24
|
DEFAULTS.each do |config_setting, value|
|
|
26
|
-
self.type_map[config_setting] = value[:type]
|
|
27
25
|
set_aliases(config_setting, value)
|
|
28
26
|
end
|
|
29
27
|
|
|
@@ -70,43 +68,14 @@ module NewRelic
|
|
|
70
68
|
nr_env_var_keys.each do |key|
|
|
71
69
|
next if SPECIAL_CASE_KEYS.any? { |pattern| pattern === key.upcase }
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def set_value_from_environment_variable(key)
|
|
78
|
-
config_key = convert_environment_key_to_config_key(key)
|
|
79
|
-
set_key_by_type(config_key, key)
|
|
80
|
-
end
|
|
71
|
+
config_key = convert_environment_key_to_config_key(key)
|
|
81
72
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if type == String
|
|
87
|
-
self[config_key] = value
|
|
88
|
-
elsif type == Integer
|
|
89
|
-
self[config_key] = value.to_i
|
|
90
|
-
elsif type == Float
|
|
91
|
-
self[config_key] = value.to_f
|
|
92
|
-
elsif type == Symbol
|
|
93
|
-
self[config_key] = value.to_sym
|
|
94
|
-
elsif type == Array
|
|
95
|
-
self[config_key] = if DEFAULTS[config_key].key?(:transform)
|
|
96
|
-
DEFAULTS[config_key][:transform].call(value)
|
|
97
|
-
else
|
|
98
|
-
value.split(/\s*,\s*/)
|
|
99
|
-
end
|
|
100
|
-
elsif type == NewRelic::Agent::Configuration::Boolean
|
|
101
|
-
if /false|off|no/i.match?(value)
|
|
102
|
-
self[config_key] = false
|
|
103
|
-
elsif !value.nil?
|
|
104
|
-
self[config_key] = true
|
|
73
|
+
unless DEFAULTS.key?(config_key) || serverless?
|
|
74
|
+
::NewRelic::Agent.logger.info("#{key} does not have a corresponding configuration setting (#{config_key} does not exist).")
|
|
75
|
+
::NewRelic::Agent.logger.info('Run `rake newrelic:config:docs` or visit https://docs.newrelic.com/docs/apm/agents/ruby-agent/configuration/ruby-agent-configuration to see a list of available configuration settings.')
|
|
105
76
|
end
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
::NewRelic::Agent.logger.info('Run `rake newrelic:config:docs` or visit https://docs.newrelic.com/docs/apm/agents/ruby-agent/configuration/ruby-agent-configuration to see a list of available configuration settings.')
|
|
109
|
-
self[config_key] = value
|
|
77
|
+
|
|
78
|
+
self[config_key] = ENV[key]
|
|
110
79
|
end
|
|
111
80
|
end
|
|
112
81
|
|
|
@@ -9,7 +9,6 @@ require 'new_relic/agent/configuration/default_source'
|
|
|
9
9
|
require 'new_relic/agent/configuration/server_source'
|
|
10
10
|
require 'new_relic/agent/configuration/environment_source'
|
|
11
11
|
require 'new_relic/agent/configuration/high_security_source'
|
|
12
|
-
require 'new_relic/agent/configuration/security_policy_source'
|
|
13
12
|
|
|
14
13
|
module NewRelic
|
|
15
14
|
module Agent
|
|
@@ -17,6 +16,28 @@ module NewRelic
|
|
|
17
16
|
class Manager
|
|
18
17
|
DEPENDENCY_DETECTION_VALUES = %i[prepend chain unsatisfied].freeze
|
|
19
18
|
|
|
19
|
+
BOOLEAN_MAP = {
|
|
20
|
+
'true' => true,
|
|
21
|
+
'yes' => true,
|
|
22
|
+
'on' => true,
|
|
23
|
+
'false' => false,
|
|
24
|
+
'no' => false,
|
|
25
|
+
'off' => false
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
INSTRUMENTATION_VALUES = %w[chain prepend unsatisfied]
|
|
29
|
+
NUMERIC_TYPES = [Integer, Float]
|
|
30
|
+
STRINGLIKE_TYPES = [String, Symbol]
|
|
31
|
+
|
|
32
|
+
TYPE_COERCIONS = {Integer => {pattern: /^\d+$/, proc: proc { |s| s.to_i }},
|
|
33
|
+
Float => {pattern: /^\d+\.\d+$/, proc: proc { |s| s.to_f }},
|
|
34
|
+
Array => {proc: proc { |s| s.split(/\s*,\s*/) }},
|
|
35
|
+
Hash => {proc: proc { |s| s.split(/\s*,\s*/).each_with_object({}) { |i, h| k, v = i.split(/\s*=\s*/); h[k] = v } }},
|
|
36
|
+
NewRelic::Agent::Configuration::Boolean => {pattern: /^(?:#{BOOLEAN_MAP.keys.join('|')})$/,
|
|
37
|
+
proc: proc { |s| BOOLEAN_MAP[s] }}}.freeze
|
|
38
|
+
|
|
39
|
+
USER_CONFIG_CLASSES = [NewRelic::Agent::Configuration::EnvironmentSource, NewRelic::Agent::Configuration::YamlSource]
|
|
40
|
+
|
|
20
41
|
# Defining these explicitly saves object allocations that we incur
|
|
21
42
|
# if we use Forwardable and def_delegators.
|
|
22
43
|
def [](key)
|
|
@@ -48,7 +69,6 @@ module NewRelic
|
|
|
48
69
|
|
|
49
70
|
def remove_config_type(sym)
|
|
50
71
|
source = case sym
|
|
51
|
-
when :security_policy then @security_policy_source
|
|
52
72
|
when :high_security then @high_security_source
|
|
53
73
|
when :environment then @environment_source
|
|
54
74
|
when :server then @server_source
|
|
@@ -62,7 +82,6 @@ module NewRelic
|
|
|
62
82
|
|
|
63
83
|
def remove_config(source)
|
|
64
84
|
case source
|
|
65
|
-
when SecurityPolicySource then @security_policy_source = nil
|
|
66
85
|
when HighSecuritySource then @high_security_source = nil
|
|
67
86
|
when EnvironmentSource then @environment_source = nil
|
|
68
87
|
when ServerSource then @server_source = nil
|
|
@@ -85,7 +104,6 @@ module NewRelic
|
|
|
85
104
|
invoke_callbacks(:add, source)
|
|
86
105
|
|
|
87
106
|
case source
|
|
88
|
-
when SecurityPolicySource then @security_policy_source = source
|
|
89
107
|
when HighSecuritySource then @high_security_source = source
|
|
90
108
|
when EnvironmentSource then @environment_source = source
|
|
91
109
|
when ServerSource then @server_source = source
|
|
@@ -116,74 +134,139 @@ module NewRelic
|
|
|
116
134
|
next unless config
|
|
117
135
|
|
|
118
136
|
accessor = key.to_sym
|
|
137
|
+
next unless config.has_key?(accessor)
|
|
119
138
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
next
|
|
125
|
-
end
|
|
139
|
+
begin
|
|
140
|
+
return evaluate_and_apply_transformations(accessor, config[accessor], config_category(config.class))
|
|
141
|
+
rescue
|
|
142
|
+
next
|
|
126
143
|
end
|
|
127
144
|
end
|
|
128
145
|
|
|
129
146
|
nil
|
|
130
147
|
end
|
|
131
148
|
|
|
132
|
-
def
|
|
133
|
-
if
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
value
|
|
137
|
-
end
|
|
138
|
-
end
|
|
149
|
+
def config_category(klass)
|
|
150
|
+
return :user if USER_CONFIG_CLASSES.include?(klass)
|
|
151
|
+
return :test if [DottedHash, Hash].include?(klass)
|
|
152
|
+
return :manual if klass == ManualSource
|
|
139
153
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
default = enforce_allowlist(key, evaluated)
|
|
143
|
-
return default if default
|
|
154
|
+
return :nr
|
|
155
|
+
end
|
|
144
156
|
|
|
145
|
-
|
|
146
|
-
evaluated =
|
|
157
|
+
def evaluate_and_apply_transformations(key, value, category)
|
|
158
|
+
evaluated = value.respond_to?(:call) ? instance_eval(&value) : value
|
|
159
|
+
evaluated = type_coerce(key, evaluated, category)
|
|
160
|
+
evaluated = enforce_allowlist(key, evaluated)
|
|
147
161
|
|
|
148
162
|
apply_transformations(key, evaluated)
|
|
149
163
|
end
|
|
150
164
|
|
|
151
|
-
def
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
165
|
+
def boolean?(type, value)
|
|
166
|
+
return false unless type == NewRelic::Agent::Configuration::Boolean
|
|
167
|
+
|
|
168
|
+
value.class == TrueClass || value.class == FalseClass
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# auto-instrumentation configuration params can be symbols or strings
|
|
172
|
+
# and unless we want to refactor the configuration hash to support both
|
|
173
|
+
# types, we handle the special case here
|
|
174
|
+
def instrumentation?(type, value)
|
|
175
|
+
return false unless type == String || type == Symbol
|
|
176
|
+
return true if INSTRUMENTATION_VALUES.include?(value.to_s)
|
|
177
|
+
|
|
178
|
+
false
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def handle_nil_type(key, value, category)
|
|
182
|
+
return value if %i[manual test].include?(category)
|
|
183
|
+
|
|
184
|
+
# TODO: identify all config params such as :web_transactions_apdex
|
|
185
|
+
# that can exist in the @config hash without having an entry
|
|
186
|
+
# in the DEFAULTS hash. then warn here when a key is in play
|
|
187
|
+
# that is not on that allowlist. for now, just permit any key
|
|
188
|
+
# and return the value.
|
|
189
|
+
# https://github.com/newrelic/newrelic-ruby-agent/issues/3340
|
|
190
|
+
default_without_warning(key) || value
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# permit an int to be supplied for a float based param and vice versa
|
|
194
|
+
def numeric_conversion(value)
|
|
195
|
+
value.is_a?(Integer) ? value.to_f : value.round
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# permit a symbol to be supplied for a string based param and vice versa
|
|
199
|
+
def string_conversion(value)
|
|
200
|
+
value.is_a?(Symbol) ? value.to_s : value.to_sym
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def type_coerce(key, value, category)
|
|
204
|
+
return validate_nil(key, category) if value.nil?
|
|
205
|
+
|
|
206
|
+
type = DEFAULTS.dig(key, :type)
|
|
207
|
+
return handle_nil_type(key, value, category) unless type
|
|
208
|
+
return value if value.is_a?(type) || boolean?(type, value) || instrumentation?(type, value)
|
|
209
|
+
return numeric_conversion(value) if NUMERIC_TYPES.include?(type) && NUMERIC_TYPES.include?(value.class)
|
|
210
|
+
return string_conversion(value) if STRINGLIKE_TYPES.include?(type) && STRINGLIKE_TYPES.include?(value.class)
|
|
211
|
+
|
|
212
|
+
# convert bool to string for regex usage and bool hash lookup
|
|
213
|
+
value = value.to_s if type == Boolean
|
|
214
|
+
if value.class != String
|
|
215
|
+
return value if category == :test || likely_transformed_already?(key, value)
|
|
216
|
+
|
|
217
|
+
return default_with_warning(key, value, "Expected to receive a value of type #{type} but " \
|
|
218
|
+
"received #{value.class}.")
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
pattern = TYPE_COERCIONS.dig(type, :pattern)
|
|
222
|
+
if pattern && value !~ pattern
|
|
223
|
+
return default_with_warning(key, value, "Expected to receive a value of type #{type} matching " \
|
|
224
|
+
"pattern '#{pattern}'.")
|
|
161
225
|
end
|
|
226
|
+
|
|
227
|
+
procedure = TYPE_COERCIONS.dig(type, :proc)
|
|
228
|
+
return value unless procedure
|
|
229
|
+
|
|
230
|
+
procedure.call(value)
|
|
162
231
|
end
|
|
163
232
|
|
|
164
|
-
def
|
|
165
|
-
|
|
166
|
-
|
|
233
|
+
def likely_transformed_already?(key, value)
|
|
234
|
+
DEFAULTS.dig(key, :transformed_type) == value.class
|
|
235
|
+
end
|
|
167
236
|
|
|
168
|
-
|
|
169
|
-
|
|
237
|
+
def default_with_warning(key, value, msg)
|
|
238
|
+
default = default_without_warning(key)
|
|
239
|
+
NewRelic::Agent.logger.warn "Received an invalid '#{value}' value for the '#{key}' configuration " \
|
|
240
|
+
"parameter! #{msg} Using the default value of '#{default}'."
|
|
170
241
|
default
|
|
171
242
|
end
|
|
172
243
|
|
|
173
|
-
def
|
|
174
|
-
|
|
175
|
-
|
|
244
|
+
def default_without_warning(key)
|
|
245
|
+
default = DEFAULTS.dig(key, :default)
|
|
246
|
+
default.respond_to?(:call) ? default.call : default
|
|
247
|
+
end
|
|
176
248
|
|
|
177
|
-
|
|
178
|
-
return
|
|
249
|
+
def validate_nil(key, category)
|
|
250
|
+
return if DEFAULTS.dig(key, :allow_nil) || category == :test # tests are free to specify nil
|
|
251
|
+
return default_without_warning(key) unless category == :user # only user supplied config raises a warning
|
|
179
252
|
|
|
180
|
-
|
|
181
|
-
NewRelic::Agent.logger.warn "Invalid value '#{value}' for #{key}, applying default value of '#{default}'"
|
|
182
|
-
default
|
|
253
|
+
default_with_warning(key, nil, 'Nil values are not permitted for the parameter.')
|
|
183
254
|
end
|
|
184
255
|
|
|
185
|
-
def
|
|
186
|
-
default_source.transform_for(key)
|
|
256
|
+
def apply_transformations(key, value)
|
|
257
|
+
return value unless transform = default_source.transform_for(key)
|
|
258
|
+
|
|
259
|
+
transform.call(value)
|
|
260
|
+
rescue => e
|
|
261
|
+
default_with_warning(key, value, "Error encountered while applying transformation: >>#{e}<<")
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def enforce_allowlist(key, value)
|
|
265
|
+
return value unless allowlist = default_source.allowlist_for(key)
|
|
266
|
+
return value if allowlist.include?(value)
|
|
267
|
+
|
|
268
|
+
default_with_warning(key, value, 'Expected to receive a value found on the following list: ' \
|
|
269
|
+
">>#{allowlist}<<, but received '#{value}'.")
|
|
187
270
|
end
|
|
188
271
|
|
|
189
272
|
def default_source
|
|
@@ -197,17 +280,19 @@ module NewRelic
|
|
|
197
280
|
|
|
198
281
|
def invoke_callbacks(direction, source)
|
|
199
282
|
return unless source
|
|
283
|
+
return if source.respond_to?(:empty?) && source.empty?
|
|
200
284
|
|
|
201
285
|
source.keys.each do |key|
|
|
286
|
+
next unless @callbacks.key?(key)
|
|
287
|
+
|
|
202
288
|
begin
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
evaluated_source = evaluate_and_apply_transformations(key, source[key])
|
|
207
|
-
rescue
|
|
289
|
+
evaluated_source = evaluate_and_apply_transformations(key, source[key], config_category(source.class))
|
|
290
|
+
rescue => e
|
|
291
|
+
NewRelic::Agent.logger.warn("Error evaluating callback for direction '#{direction}' with key '#{key}': #{e}")
|
|
208
292
|
next
|
|
209
293
|
end
|
|
210
294
|
|
|
295
|
+
evaluated_cache = @cache[key]
|
|
211
296
|
if evaluated_cache != evaluated_source
|
|
212
297
|
@callbacks[key].each do |proc|
|
|
213
298
|
if direction == :add
|
|
@@ -256,8 +341,8 @@ module NewRelic
|
|
|
256
341
|
end
|
|
257
342
|
|
|
258
343
|
def apply_mask(hash)
|
|
259
|
-
MASK_DEFAULTS
|
|
260
|
-
.select { |_, proc| proc.call }
|
|
344
|
+
MASK_DEFAULTS
|
|
345
|
+
.select { |_, proc| proc.call }
|
|
261
346
|
.each { |key, _| hash.delete(key) }
|
|
262
347
|
hash
|
|
263
348
|
end
|
|
@@ -379,7 +464,6 @@ module NewRelic
|
|
|
379
464
|
|
|
380
465
|
# Generally only useful during initial construction and tests
|
|
381
466
|
def reset_to_defaults
|
|
382
|
-
@security_policy_source = nil
|
|
383
467
|
@high_security_source = nil
|
|
384
468
|
@environment_source = EnvironmentSource.new
|
|
385
469
|
log_config(:add, @environment_source) # this is the only place the EnvironmentSource is ever created, so we should log it
|
|
@@ -433,7 +517,6 @@ module NewRelic
|
|
|
433
517
|
end
|
|
434
518
|
|
|
435
519
|
def delete_all_configs_for_testing
|
|
436
|
-
@security_policy_source = nil
|
|
437
520
|
@high_security_source = nil
|
|
438
521
|
@environment_source = nil
|
|
439
522
|
@server_source = nil
|
|
@@ -454,8 +537,7 @@ module NewRelic
|
|
|
454
537
|
private
|
|
455
538
|
|
|
456
539
|
def config_stack
|
|
457
|
-
stack = [@
|
|
458
|
-
@high_security_source,
|
|
540
|
+
stack = [@high_security_source,
|
|
459
541
|
@environment_source,
|
|
460
542
|
@server_source,
|
|
461
543
|
@manual_source,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
module NewRelic
|
|
6
|
+
module Agent
|
|
7
|
+
module Configuration
|
|
8
|
+
# Handles validation for the `distributed_tracing.sampler.*` configs
|
|
9
|
+
# Focuses on validating the trace id ratio based ratios
|
|
10
|
+
module SamplerConfigValidator
|
|
11
|
+
@sampler_strategy_warnings = {}
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def validate_sampling_ratio(ratio)
|
|
15
|
+
return nil if ratio.nil?
|
|
16
|
+
return nil unless valid_ratio?(ratio)
|
|
17
|
+
|
|
18
|
+
ratio
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def validate_sampler_strategy_with_ratio(strategy_key, ratio_key)
|
|
22
|
+
proc do |strategy|
|
|
23
|
+
next strategy unless strategy == 'trace_id_ratio_based'
|
|
24
|
+
|
|
25
|
+
ratio = NewRelic::Agent.config[ratio_key]
|
|
26
|
+
|
|
27
|
+
next strategy if valid_ratio?(ratio)
|
|
28
|
+
|
|
29
|
+
unless @sampler_strategy_warnings[strategy_key]
|
|
30
|
+
NewRelic::Agent.logger.warn(
|
|
31
|
+
"Invalid or missing ratio for #{ratio_key} (value: #{ratio.inspect}). " \
|
|
32
|
+
"Falling back to 'adaptive' for #{strategy_key}."
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
@sampler_strategy_warnings[strategy_key] = true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
'adaptive'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def valid_ratio?(ratio)
|
|
43
|
+
ratio.is_a?(Float) && (0.0..1.0).cover?(ratio)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# used for testing
|
|
47
|
+
def reset_warnings!
|
|
48
|
+
@sampler_strategy_warnings = {}
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -23,10 +23,7 @@ module NewRelic
|
|
|
23
23
|
|
|
24
24
|
@agent.agent_id = config_data['agent_run_id']
|
|
25
25
|
|
|
26
|
-
security_policies = config_data.delete('security_policies')
|
|
27
|
-
|
|
28
26
|
add_server_side_config(config_data)
|
|
29
|
-
add_security_policy_config(security_policies) if security_policies
|
|
30
27
|
|
|
31
28
|
@agent.transaction_rules = RulesEngine.create_transaction_rules(config_data)
|
|
32
29
|
@agent.stats_engine.metric_rules = RulesEngine.create_metric_rules(config_data)
|
|
@@ -44,14 +41,6 @@ module NewRelic
|
|
|
44
41
|
server_config = NewRelic::Agent::Configuration::ServerSource.new(config_data, @config)
|
|
45
42
|
@config.replace_or_add_config(server_config)
|
|
46
43
|
end
|
|
47
|
-
|
|
48
|
-
def add_security_policy_config(security_policies)
|
|
49
|
-
::NewRelic::Agent.logger.info('Installing security policies')
|
|
50
|
-
security_policy_source = NewRelic::Agent::Configuration::SecurityPolicySource.new(security_policies)
|
|
51
|
-
@config.replace_or_add_config(security_policy_source)
|
|
52
|
-
# drop data collected before applying security policies
|
|
53
|
-
@agent.drop_buffered_data
|
|
54
|
-
end
|
|
55
44
|
end
|
|
56
45
|
end
|
|
57
46
|
end
|
|
@@ -85,13 +85,12 @@ module NewRelic
|
|
|
85
85
|
# statement-level metrics (i.e. table or model name)
|
|
86
86
|
#
|
|
87
87
|
# @param [Proc,#call] callback proc or other callable to invoke after
|
|
88
|
-
# running the datastore block. Receives
|
|
89
|
-
# yield
|
|
90
|
-
# call. An example use is attaching SQL to Transaction Traces at the end
|
|
88
|
+
# running the datastore block. Receives one argument: result of the
|
|
89
|
+
# yield. An example use is attaching SQL to Transaction Traces at the end
|
|
91
90
|
# of a wrapped datastore call.
|
|
92
91
|
#
|
|
93
|
-
# callback = Proc.new do |result
|
|
94
|
-
# NewRelic::Agent::Datastores.notice_sql(query
|
|
92
|
+
# callback = Proc.new do |result|
|
|
93
|
+
# NewRelic::Agent::Datastores.notice_sql(query)
|
|
95
94
|
# end
|
|
96
95
|
#
|
|
97
96
|
# NewRelic::Agent::Datastores.wrap("FauxDB", "find", "items", callback) do
|
|
@@ -107,6 +106,11 @@ module NewRelic
|
|
|
107
106
|
# @api public
|
|
108
107
|
#
|
|
109
108
|
def self.wrap(product, operation, collection = nil, callback = nil)
|
|
109
|
+
NewRelic::Agent.logger.warn('The NewRelic::Agent::Datastores.wrap method is changing. ' \
|
|
110
|
+
'In a future major version, proc will only accept a single argument, the result of the yield. ' \
|
|
111
|
+
'The scoped metric name and elapsed arguments will be removed, as they are being removed from the ' \
|
|
112
|
+
'Datastores.notice_sql method. The scoped metric name and elapsed values are derived from the ' \
|
|
113
|
+
'current segment when the wrap yields.')
|
|
110
114
|
NewRelic::Agent.record_api_supportability_metric(:wrap)
|
|
111
115
|
|
|
112
116
|
return yield unless operation
|
|
@@ -138,19 +142,13 @@ module NewRelic
|
|
|
138
142
|
# If you are recording non-SQL data, please use {notice_statement}
|
|
139
143
|
# instead.
|
|
140
144
|
#
|
|
141
|
-
# NewRelic::Agent::Datastores.notice_sql(query
|
|
145
|
+
# NewRelic::Agent::Datastores.notice_sql(query)
|
|
142
146
|
#
|
|
143
147
|
# @param [String] query the SQL text to be captured. Note that depending
|
|
144
148
|
# on user settings, this string will be run through obfuscation, but
|
|
145
149
|
# some dialects of SQL (or non-SQL queries) are not guaranteed to be
|
|
146
150
|
# properly obfuscated by these routines!
|
|
147
151
|
#
|
|
148
|
-
# @param [String] scoped_metric The most specific metric relating to this
|
|
149
|
-
# query. Typically the result of
|
|
150
|
-
# NewRelic::Agent::Datastores::MetricHelper#metrics_for
|
|
151
|
-
#
|
|
152
|
-
# @param [Float] elapsed the elapsed time during query execution
|
|
153
|
-
#
|
|
154
152
|
# @note THERE ARE SECURITY CONCERNS WHEN CAPTURING QUERY TEXT!
|
|
155
153
|
# New Relic's Transaction Tracing and Slow SQL features will
|
|
156
154
|
# attempt to apply obfuscation to the passed queries, but it is possible
|
|
@@ -159,7 +157,7 @@ module NewRelic
|
|
|
159
157
|
#
|
|
160
158
|
# @api public
|
|
161
159
|
#
|
|
162
|
-
def self.notice_sql(query
|
|
160
|
+
def self.notice_sql(query)
|
|
163
161
|
NewRelic::Agent.record_api_supportability_metric(:notice_sql)
|
|
164
162
|
|
|
165
163
|
if (txn = Tracer.current_transaction) && (segment = txn.current_segment) && segment.respond_to?(:notice_sql)
|
|
@@ -176,12 +174,10 @@ module NewRelic
|
|
|
176
174
|
# ensure that user information is obfuscated if the agent setting
|
|
177
175
|
# `transaction_tracer.record_sql` is set to `obfuscated`
|
|
178
176
|
#
|
|
179
|
-
# NewRelic::Agent::Datastores.notice_statement("key"
|
|
177
|
+
# NewRelic::Agent::Datastores.notice_statement("key")
|
|
180
178
|
#
|
|
181
179
|
# @param [String] statement text of the statement to capture.
|
|
182
180
|
#
|
|
183
|
-
# @param [Float] elapsed the elapsed time during query execution
|
|
184
|
-
#
|
|
185
181
|
# @note THERE ARE SECURITY CONCERNS WHEN CAPTURING STATEMENTS!
|
|
186
182
|
# This method will properly ignore statements when the user has turned
|
|
187
183
|
# off capturing queries, but it is not able to obfuscate arbitrary data!
|
|
@@ -191,7 +187,7 @@ module NewRelic
|
|
|
191
187
|
#
|
|
192
188
|
# @api public
|
|
193
189
|
#
|
|
194
|
-
def self.notice_statement(statement
|
|
190
|
+
def self.notice_statement(statement)
|
|
195
191
|
NewRelic::Agent.record_api_supportability_metric(:notice_statement)
|
|
196
192
|
|
|
197
193
|
# Settings may change eventually, but for now we follow the same
|
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
|
3
3
|
# frozen_string_literal: true
|
|
4
4
|
|
|
5
|
-
require_relative 'distributed_tracing/cross_app_payload'
|
|
6
|
-
require_relative 'distributed_tracing/cross_app_tracing'
|
|
7
|
-
|
|
8
5
|
require_relative 'distributed_tracing/distributed_trace_transport_type'
|
|
9
6
|
require_relative 'distributed_tracing/distributed_trace_payload'
|
|
10
7
|
|
|
@@ -71,7 +71,7 @@ module NewRelic
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def self.run_in_trace(job, block, event)
|
|
74
|
-
trace_execution_scoped("ActiveJob/#{adapter.sub(/^ActiveJob::/, '')}/Queue/#{event}/Named/#{job.queue_name}",
|
|
74
|
+
trace_execution_scoped("ActiveJob/#{adapter.sub(/^ActiveJob::/, '')}/Queue/#{event}/Named/#{job.queue_name}/#{job.class}",
|
|
75
75
|
code_information: code_information_for_job(job)) do
|
|
76
76
|
block.call
|
|
77
77
|
end
|
|
@@ -22,8 +22,9 @@ module NewRelic
|
|
|
22
22
|
job = payload[:job] || payload[:jobs].first
|
|
23
23
|
|
|
24
24
|
queue = job.queue_name
|
|
25
|
+
job_class = job.class.name.include?('::') ? job.class.name[job.class.name.rindex('::') + 2..-1] : job.class.name
|
|
25
26
|
method = method_from_name(name)
|
|
26
|
-
"Ruby/ActiveJob/#{queue}/#{method}"
|
|
27
|
+
"Ruby/ActiveJob/#{queue}/#{job_class}/#{method}"
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
PATTERN = /\A([^\.]+)\.active_job\z/
|
|
@@ -99,10 +99,7 @@ module NewRelic
|
|
|
99
99
|
# convert vendor (makara, etc.) wrapper names to their bare names
|
|
100
100
|
# ex: postgresql_makara -> postgresql
|
|
101
101
|
def bare_adapter_name(adapter_name)
|
|
102
|
-
|
|
103
|
-
# With Ruby 2.5+ we could use #delete_suffix instead of #chomp for a
|
|
104
|
-
# potential speed boost
|
|
105
|
-
return adapter_name.chomp(MAKARA_SUFFIX) if adapter_name&.end_with?(MAKARA_SUFFIX)
|
|
102
|
+
return adapter_name.delete_suffix(MAKARA_SUFFIX) if adapter_name&.end_with?(MAKARA_SUFFIX)
|
|
106
103
|
|
|
107
104
|
adapter_name
|
|
108
105
|
end
|
|
@@ -7,6 +7,8 @@ require 'new_relic/agent/instrumentation/active_support_subscriber'
|
|
|
7
7
|
DependencyDetection.defer do
|
|
8
8
|
named :active_support
|
|
9
9
|
|
|
10
|
+
EVENT_NAMES_PARAMETER = :'instrumentation.active_support_notifications.active_support_events'
|
|
11
|
+
|
|
10
12
|
depends_on do
|
|
11
13
|
!NewRelic::Agent.config[:disable_active_support]
|
|
12
14
|
end
|
|
@@ -16,12 +18,17 @@ DependencyDetection.defer do
|
|
|
16
18
|
!NewRelic::Agent::Instrumentation::ActiveSupportSubscriber.subscribed?
|
|
17
19
|
end
|
|
18
20
|
|
|
21
|
+
depends_on do
|
|
22
|
+
!NewRelic::Agent.config[EVENT_NAMES_PARAMETER].empty?
|
|
23
|
+
end
|
|
24
|
+
|
|
19
25
|
executes do
|
|
20
26
|
NewRelic::Agent.logger.info('Installing ActiveSupport instrumentation')
|
|
21
27
|
end
|
|
22
28
|
|
|
23
29
|
executes do
|
|
24
|
-
|
|
30
|
+
event_names = NewRelic::Agent.config[EVENT_NAMES_PARAMETER].map { |n| Regexp.escape(n) }.join('|')
|
|
31
|
+
ActiveSupport::Notifications.subscribe(/\A(?:#{event_names})\z/,
|
|
25
32
|
NewRelic::Agent::Instrumentation::ActiveSupportSubscriber.new)
|
|
26
33
|
end
|
|
27
34
|
end
|