newrelic_rpm 9.9.0 → 9.21.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/.build_ignore +1 -0
- data/CHANGELOG.md +463 -1
- data/CONTRIBUTING.md +2 -2
- data/README.md +16 -17
- data/Rakefile +1 -1
- data/lib/boot/strap.rb +102 -0
- data/lib/new_relic/agent/agent.rb +6 -0
- data/lib/new_relic/agent/agent_helpers/connect.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/shutdown.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +1 -0
- data/lib/new_relic/agent/agent_helpers/startup.rb +7 -0
- data/lib/new_relic/agent/agent_logger.rb +1 -0
- data/lib/new_relic/agent/aws.rb +68 -0
- data/lib/new_relic/agent/configuration/default_source.rb +603 -105
- data/lib/new_relic/agent/configuration/environment_source.rb +5 -1
- data/lib/new_relic/agent/configuration/manager.rb +28 -2
- data/lib/new_relic/agent/configuration/yaml_source.rb +7 -2
- data/lib/new_relic/agent/database/obfuscation_helpers.rb +11 -11
- data/lib/new_relic/agent/database/obfuscator.rb +1 -0
- data/lib/new_relic/agent/database.rb +41 -1
- data/lib/new_relic/agent/database_adapter.rb +1 -1
- data/lib/new_relic/agent/datastores/redis.rb +1 -1
- data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +1 -1
- data/lib/new_relic/agent/distributed_tracing.rb +4 -2
- data/lib/new_relic/agent/error_collector.rb +37 -10
- data/lib/new_relic/agent/external.rb +2 -0
- data/lib/new_relic/agent/health_check.rb +136 -0
- data/lib/new_relic/agent/http_clients/uri_util.rb +1 -1
- data/lib/new_relic/agent/instrumentation/action_dispatch.rb +1 -1
- data/lib/new_relic/agent/instrumentation/action_dispatch_subscriber.rb +1 -1
- data/lib/new_relic/agent/instrumentation/action_mailbox.rb +1 -1
- data/lib/new_relic/agent/instrumentation/action_mailer.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +6 -2
- data/lib/new_relic/agent/instrumentation/active_merchant.rb +0 -13
- data/lib/new_relic/agent/instrumentation/active_record.rb +7 -12
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +7 -3
- data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +11 -9
- data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +2 -2
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +9 -16
- data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +0 -2
- data/lib/new_relic/agent/instrumentation/active_support_logger.rb +0 -2
- data/lib/new_relic/agent/instrumentation/async_http.rb +2 -3
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb +66 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb +22 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +91 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb +22 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/chain.rb +33 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/instrumentation.rb +93 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/prepend.rb +23 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda.rb +23 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs/chain.rb +37 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs/instrumentation.rb +67 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs/prepend.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs.rb +23 -0
- data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +14 -0
- data/lib/new_relic/agent/instrumentation/bunny.rb +3 -4
- data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +1 -3
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/curb.rb +4 -5
- data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +0 -23
- data/lib/new_relic/agent/instrumentation/dynamodb/chain.rb +27 -0
- data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +64 -0
- data/lib/new_relic/agent/instrumentation/dynamodb/prepend.rb +19 -0
- data/lib/new_relic/agent/instrumentation/dynamodb.rb +23 -0
- data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +1 -2
- data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +53 -7
- data/lib/new_relic/agent/instrumentation/elasticsearch.rb +1 -3
- data/lib/new_relic/agent/instrumentation/ethon.rb +1 -5
- data/lib/new_relic/agent/instrumentation/excon.rb +1 -17
- data/lib/new_relic/agent/instrumentation/fiber/chain.rb +1 -1
- data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +1 -1
- data/lib/new_relic/agent/instrumentation/fiber.rb +0 -2
- data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +0 -3
- data/lib/new_relic/agent/instrumentation/grape.rb +1 -1
- data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +0 -1
- data/lib/new_relic/agent/instrumentation/httpclient.rb +1 -5
- data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
- data/lib/new_relic/agent/instrumentation/httpx/instrumentation.rb +1 -1
- data/lib/new_relic/agent/instrumentation/httpx.rb +1 -5
- data/lib/new_relic/agent/instrumentation/logger.rb +1 -3
- data/lib/new_relic/agent/instrumentation/logstasher/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb +24 -0
- data/lib/new_relic/agent/instrumentation/logstasher/prepend.rb +13 -0
- data/lib/new_relic/agent/instrumentation/logstasher.rb +25 -0
- data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +1 -1
- data/lib/new_relic/agent/instrumentation/memcache/helper.rb +2 -2
- data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +1 -1
- data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +1 -1
- data/lib/new_relic/agent/instrumentation/memcache.rb +0 -1
- data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +1 -1
- data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +3 -3
- data/lib/new_relic/agent/instrumentation/net_http.rb +2 -1
- data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +0 -2
- data/lib/new_relic/agent/instrumentation/opensearch/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/opensearch/instrumentation.rb +66 -0
- data/lib/{tasks/instrumentation_generator/templates/instrumentation.tt → new_relic/agent/instrumentation/opensearch/prepend.rb} +4 -4
- data/lib/new_relic/agent/instrumentation/opensearch.rb +23 -0
- data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
- data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +3 -0
- data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +9 -5
- data/lib/new_relic/agent/instrumentation/rake.rb +1 -2
- data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +72 -0
- data/lib/new_relic/agent/instrumentation/rdkafka/instrumentation.rb +70 -0
- data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +67 -0
- data/lib/new_relic/agent/instrumentation/rdkafka.rb +25 -0
- data/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb +26 -0
- data/lib/new_relic/agent/instrumentation/redis/constants.rb +2 -2
- data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +14 -11
- data/lib/new_relic/agent/instrumentation/redis/middleware.rb +3 -0
- data/lib/new_relic/agent/instrumentation/redis.rb +11 -5
- data/lib/new_relic/agent/instrumentation/resque.rb +8 -6
- data/lib/new_relic/agent/instrumentation/roda.rb +5 -5
- data/lib/new_relic/agent/instrumentation/ruby_kafka/chain.rb +55 -0
- data/lib/new_relic/agent/instrumentation/ruby_kafka/instrumentation.rb +67 -0
- data/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb +60 -0
- data/lib/new_relic/agent/instrumentation/ruby_kafka.rb +25 -0
- data/lib/new_relic/agent/instrumentation/ruby_openai.rb +2 -2
- data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delay_extensions.rb +24 -0
- data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +2 -2
- data/lib/new_relic/agent/instrumentation/sidekiq.rb +9 -15
- data/lib/new_relic/agent/instrumentation/sinatra.rb +3 -19
- data/lib/new_relic/agent/instrumentation/stripe.rb +1 -1
- data/lib/new_relic/agent/instrumentation/stripe_subscriber.rb +22 -1
- data/lib/new_relic/agent/instrumentation/thread.rb +0 -2
- data/lib/new_relic/agent/instrumentation/tilt.rb +0 -4
- data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +2 -2
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
- data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +11 -5
- data/lib/new_relic/agent/instrumentation/view_component.rb +0 -2
- data/lib/new_relic/agent/javascript_instrumentor.rb +2 -3
- data/lib/new_relic/agent/llm/chat_completion_summary.rb +1 -1
- data/lib/new_relic/agent/llm/embedding.rb +1 -1
- data/lib/new_relic/agent/local_log_decorator.rb +20 -3
- data/lib/new_relic/agent/log_event_aggregator.rb +119 -28
- data/lib/new_relic/agent/logging.rb +1 -1
- data/lib/new_relic/agent/messaging.rb +16 -5
- data/lib/new_relic/agent/method_tracer.rb +3 -0
- data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -1
- data/lib/new_relic/agent/monitors/synthetics_monitor.rb +1 -1
- data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +2 -2
- data/lib/new_relic/agent/new_relic_service.rb +8 -2
- data/lib/new_relic/agent/opentelemetry/context/propagation/trace_propagator.rb +66 -0
- data/lib/new_relic/agent/opentelemetry/context/propagation.rb +15 -0
- data/lib/{tasks/instrumentation_generator/templates/Envfile.tt → new_relic/agent/opentelemetry/context.rb} +9 -5
- data/lib/new_relic/agent/opentelemetry/trace/span.rb +31 -0
- data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +129 -0
- data/lib/new_relic/agent/opentelemetry/trace/tracer_provider.rb +18 -0
- data/lib/new_relic/agent/opentelemetry/trace.rb +15 -0
- data/lib/new_relic/agent/opentelemetry/transaction_patch.rb +69 -0
- data/lib/new_relic/agent/opentelemetry_bridge.rb +32 -0
- data/lib/new_relic/agent/parameter_filtering.rb +1 -1
- data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
- data/lib/new_relic/agent/samplers/memory_sampler.rb +1 -1
- data/lib/new_relic/agent/serverless_handler.rb +247 -12
- data/lib/new_relic/agent/serverless_handler_event_sources.json +155 -0
- data/lib/new_relic/agent/serverless_handler_event_sources.rb +49 -0
- data/lib/new_relic/agent/span_event_primitive.rb +16 -11
- data/lib/new_relic/agent/system_info.rb +14 -0
- data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
- data/lib/new_relic/agent/tracer.rb +1 -1
- data/lib/new_relic/agent/transaction/abstract_segment.rb +2 -1
- data/lib/new_relic/agent/transaction/datastore_segment.rb +1 -1
- data/lib/new_relic/agent/transaction/distributed_tracer.rb +3 -3
- data/lib/new_relic/agent/transaction/external_request_segment.rb +0 -10
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +4 -1
- data/lib/new_relic/agent/transaction/request_attributes.rb +14 -7
- data/lib/new_relic/agent/transaction/trace_context.rb +34 -5
- data/lib/new_relic/agent/transaction/tracing.rb +3 -3
- data/lib/new_relic/agent/transaction.rb +4 -7
- data/lib/new_relic/agent/transaction_time_aggregator.rb +1 -1
- data/lib/new_relic/agent/utilization/ecs.rb +22 -0
- data/lib/new_relic/agent/utilization/ecs_v4.rb +22 -0
- data/lib/new_relic/agent/utilization_data.rb +40 -5
- data/lib/new_relic/agent/vm/c_ruby_vm.rb +3 -3
- data/lib/new_relic/agent.rb +124 -2
- data/lib/new_relic/constants.rb +1 -0
- data/lib/new_relic/control/frameworks/grape.rb +14 -0
- data/lib/new_relic/control/frameworks/padrino.rb +14 -0
- data/lib/new_relic/control/frameworks/rails4.rb +1 -3
- data/lib/new_relic/control/instance_methods.rb +6 -0
- data/lib/new_relic/control/instrumentation.rb +1 -1
- data/lib/new_relic/control/private_instance_methods.rb +4 -0
- data/lib/new_relic/control/security_interface.rb +57 -0
- data/lib/new_relic/control.rb +1 -1
- data/lib/new_relic/dependency_detection.rb +11 -14
- data/lib/new_relic/environment_report.rb +2 -2
- data/lib/new_relic/helper.rb +22 -0
- data/lib/new_relic/language_support.rb +3 -1
- data/lib/new_relic/local_environment.rb +1 -4
- data/lib/new_relic/rack/browser_monitoring.rb +20 -8
- data/lib/new_relic/version.rb +1 -1
- data/lib/sequel/extensions/new_relic_instrumentation.rb +3 -2
- data/lib/tasks/config.rake +7 -3
- data/lib/tasks/gha.rake +31 -0
- data/lib/tasks/helpers/config.html.erb +3 -2
- data/lib/tasks/helpers/format.rb +1 -1
- data/lib/tasks/helpers/newrelicyml.rb +80 -13
- data/newrelic.yml +425 -162
- data/newrelic_rpm.gemspec +3 -1
- data/test/agent_helper.rb +24 -2
- metadata +91 -22
- data/lib/tasks/instrumentation_generator/README.md +0 -63
- data/lib/tasks/instrumentation_generator/TODO.md +0 -33
- data/lib/tasks/instrumentation_generator/instrumentation.thor +0 -121
- data/lib/tasks/instrumentation_generator/templates/chain.tt +0 -21
- data/lib/tasks/instrumentation_generator/templates/chain_method.tt +0 -7
- data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +0 -29
- data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +0 -3
- data/lib/tasks/instrumentation_generator/templates/newrelic.yml.tt +0 -19
- data/lib/tasks/instrumentation_generator/templates/prepend.tt +0 -13
- data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +0 -3
- data/lib/tasks/instrumentation_generator/templates/test.tt +0 -15
@@ -92,7 +92,11 @@ module NewRelic
|
|
92
92
|
elsif type == Symbol
|
93
93
|
self[config_key] = value.to_sym
|
94
94
|
elsif type == Array
|
95
|
-
self[config_key] =
|
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
|
96
100
|
elsif type == NewRelic::Agent::Configuration::Boolean
|
97
101
|
if /false|off|no/i.match?(value)
|
98
102
|
self[config_key] = false
|
@@ -142,6 +142,9 @@ module NewRelic
|
|
142
142
|
default = enforce_allowlist(key, evaluated)
|
143
143
|
return default if default
|
144
144
|
|
145
|
+
boolean = enforce_boolean(key, value)
|
146
|
+
evaluated = boolean if [true, false].include?(boolean)
|
147
|
+
|
145
148
|
apply_transformations(key, evaluated)
|
146
149
|
end
|
147
150
|
|
@@ -167,6 +170,18 @@ module NewRelic
|
|
167
170
|
default
|
168
171
|
end
|
169
172
|
|
173
|
+
def enforce_boolean(key, value)
|
174
|
+
type = default_source.value_from_defaults(key, :type)
|
175
|
+
return unless type == Boolean
|
176
|
+
|
177
|
+
bool_value = default_source.boolean_for(key, value)
|
178
|
+
return bool_value unless bool_value.nil?
|
179
|
+
|
180
|
+
default = default_source.default_for(key)
|
181
|
+
NewRelic::Agent.logger.warn "Invalid value '#{value}' for #{key}, applying default value of '#{default}'"
|
182
|
+
default
|
183
|
+
end
|
184
|
+
|
170
185
|
def transform_from_default(key)
|
171
186
|
default_source.transform_for(key)
|
172
187
|
end
|
@@ -367,6 +382,7 @@ module NewRelic
|
|
367
382
|
@security_policy_source = nil
|
368
383
|
@high_security_source = nil
|
369
384
|
@environment_source = EnvironmentSource.new
|
385
|
+
log_config(:add, @environment_source) # this is the only place the EnvironmentSource is ever created, so we should log it
|
370
386
|
@server_source = nil
|
371
387
|
@manual_source = nil
|
372
388
|
@yaml_source = nil
|
@@ -382,6 +398,14 @@ module NewRelic
|
|
382
398
|
def reset_cache
|
383
399
|
return new_cache unless defined?(@cache) && @cache
|
384
400
|
|
401
|
+
# Modifying the @cache hash under JRuby - even with a `synchronize do`
|
402
|
+
# block and a `Hash#dup` operation - has been known to cause issues
|
403
|
+
# with JRuby for concurrent access of the hash while it is being
|
404
|
+
# modified. The hash really only needs to be modified for the benefit
|
405
|
+
# of the security agent, so if JRuby is in play and the security agent
|
406
|
+
# is not, don't attempt to modify the hash at all and return early.
|
407
|
+
return new_cache if NewRelic::LanguageSupport.jruby? && !Agent.config[:'security.agent.enabled']
|
408
|
+
|
385
409
|
@lock.synchronize do
|
386
410
|
preserved = @cache.dup.select { |_k, v| DEPENDENCY_DETECTION_VALUES.include?(v) }
|
387
411
|
new_cache
|
@@ -401,8 +425,10 @@ module NewRelic
|
|
401
425
|
# actually going to be logging the message based on our current log
|
402
426
|
# level, so use a `do` block.
|
403
427
|
NewRelic::Agent.logger.debug do
|
404
|
-
|
405
|
-
|
428
|
+
source_hash = source.dup.to_h.delete_if { |k, _v| DEFAULTS.fetch(k, {}).fetch(:exclude_from_reported_settings, false) }
|
429
|
+
final_hash = flattened.delete_if { |k, _h| DEFAULTS.fetch(k, {}).fetch(:exclude_from_reported_settings, false) }
|
430
|
+
|
431
|
+
"Updating config (#{direction}) from #{source.class} with values: #{source_hash}. \nConfig Stack Results: #{final_hash.inspect}"
|
406
432
|
end
|
407
433
|
end
|
408
434
|
|
@@ -36,6 +36,7 @@ module NewRelic
|
|
36
36
|
erb_file = process_erb(raw_file)
|
37
37
|
config = process_yaml(erb_file, env, config, @file_path)
|
38
38
|
rescue ScriptError, StandardError => e
|
39
|
+
NewRelic::Agent.agent&.health_check&.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_PARSE_CONFIG)
|
39
40
|
log_failure("Failed to read or parse configuration file at #{path}", e)
|
40
41
|
end
|
41
42
|
|
@@ -66,7 +67,7 @@ module NewRelic
|
|
66
67
|
end
|
67
68
|
|
68
69
|
def warn_missing_config_file(path)
|
69
|
-
based_on =
|
70
|
+
based_on = NewRelic::UNKNOWN_LOWER
|
70
71
|
source = ::NewRelic::Agent.config.source(:config_path)
|
71
72
|
candidate_paths = [path]
|
72
73
|
|
@@ -99,7 +100,11 @@ module NewRelic
|
|
99
100
|
file.gsub!(/^\s*#.*$/, '#')
|
100
101
|
ERB.new(file).result(binding)
|
101
102
|
rescue ScriptError, StandardError => e
|
102
|
-
|
103
|
+
NewRelic::Agent.agent&.health_check&.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_PARSE_CONFIG)
|
104
|
+
message = 'Failed ERB processing configuration file. This is typically caused by a Ruby error in <% %> templating blocks in your newrelic.yml file.'
|
105
|
+
failure_array = [message, e]
|
106
|
+
failure_array << e.backtrace[0] if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '3.4.0')
|
107
|
+
log_failure(*failure_array)
|
103
108
|
nil
|
104
109
|
end
|
105
110
|
end
|
@@ -7,17 +7,17 @@ module NewRelic
|
|
7
7
|
module Database
|
8
8
|
module ObfuscationHelpers
|
9
9
|
COMPONENTS_REGEX_MAP = {
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
20
|
-
}
|
10
|
+
single_quotes: /'(?:[^']|'')*?(?:\\'.*|'(?!'))/,
|
11
|
+
double_quotes: /"(?:[^"]|"")*?(?:\\".*|"(?!"))/,
|
12
|
+
dollar_quotes: /(\$(?!\d)[^$]*?\$).*?(?:\1|$)/,
|
13
|
+
uuids: /\{?(?:[0-9a-fA-F]-*){32}\}?/,
|
14
|
+
numeric_literals: /-?\b(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/,
|
15
|
+
boolean_literals: /\b(?:true|false|null)\b/i,
|
16
|
+
hexadecimal_literals: /0x[0-9a-fA-F]+/,
|
17
|
+
comments: /(?:#|--).*?(?=\r|\n|$)/i,
|
18
|
+
multi_line_comments: %r{/\*.*?\*/}m,
|
19
|
+
oracle_quoted_strings: /q'\[.*?(?:\]'|$)|q'\{.*?(?:\}'|$)|q'<.*?(?:>'|$)|q'\(.*?(?:\)'|$)/
|
20
|
+
}.freeze
|
21
21
|
|
22
22
|
DIALECT_COMPONENTS = {
|
23
23
|
:fallback => COMPONENTS_REGEX_MAP.keys,
|
@@ -90,6 +90,42 @@ module NewRelic
|
|
90
90
|
ConnectionManager.instance.get_connection(config, &connector)
|
91
91
|
end
|
92
92
|
|
93
|
+
def explain_this(statement, use_execute = false)
|
94
|
+
if supports_with_connection?
|
95
|
+
explain_this_using_with_connection(statement)
|
96
|
+
else
|
97
|
+
explain_this_using_adapter_connection(statement, use_execute)
|
98
|
+
end
|
99
|
+
rescue => e
|
100
|
+
NewRelic::Agent.logger.error("Couldn't fetch the explain plan for statement: #{e}")
|
101
|
+
end
|
102
|
+
|
103
|
+
def explain_this_using_with_connection(statement)
|
104
|
+
::ActiveRecord::Base.with_connection do |conn|
|
105
|
+
conn.exec_query("EXPLAIN #{statement.sql}", "Explain #{statement.name}", statement.binds)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def explain_this_using_adapter_connection(statement, use_execute)
|
110
|
+
connection = get_connection(statement.config) do
|
111
|
+
::ActiveRecord::Base.send(:"#{statement.config[:adapter]}_connection", statement.config)
|
112
|
+
end
|
113
|
+
|
114
|
+
if use_execute
|
115
|
+
connection.execute("EXPLAIN #{statement.sql}")
|
116
|
+
else
|
117
|
+
connection.exec_query("EXPLAIN #{statement.sql}", "Explain #{statement.name}", statement.binds)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# ActiveRecord v7.2.0 introduced with_connection
|
122
|
+
def supports_with_connection?
|
123
|
+
return @supports_with_connection if defined?(@supports_with_connection)
|
124
|
+
|
125
|
+
@supports_with_connection = defined?(::ActiveRecord::VERSION::STRING) &&
|
126
|
+
NewRelic::Helper.version_satisfied?(ActiveRecord::VERSION::STRING, '>=', '7.2.0')
|
127
|
+
end
|
128
|
+
|
93
129
|
def close_connections
|
94
130
|
ConnectionManager.instance.close_connections
|
95
131
|
end
|
@@ -241,9 +277,11 @@ module NewRelic
|
|
241
277
|
MYSQL_PREFIX = 'mysql'.freeze
|
242
278
|
MYSQL2_PREFIX = 'mysql2'.freeze
|
243
279
|
SQLITE_PREFIX = 'sqlite'.freeze
|
280
|
+
TRILOGY_PREFIX = 'trilogy'.freeze
|
281
|
+
REDSHIFT_PREFIX = 'redshift'.freeze
|
244
282
|
|
245
283
|
def symbolized_adapter(adapter)
|
246
|
-
if adapter.start_with?(POSTGRES_PREFIX) || adapter == POSTGIS_PREFIX
|
284
|
+
if adapter.start_with?(POSTGRES_PREFIX) || adapter == POSTGIS_PREFIX || adapter == REDSHIFT_PREFIX
|
247
285
|
:postgres
|
248
286
|
elsif adapter == MYSQL_PREFIX
|
249
287
|
:mysql
|
@@ -253,6 +291,8 @@ module NewRelic
|
|
253
291
|
:mysql2
|
254
292
|
elsif adapter.start_with?(SQLITE_PREFIX)
|
255
293
|
:sqlite
|
294
|
+
elsif adapter == TRILOGY_PREFIX
|
295
|
+
:trilogy
|
256
296
|
else
|
257
297
|
adapter.to_sym
|
258
298
|
end
|
@@ -25,7 +25,7 @@ module NewRelic
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def value
|
28
|
-
match = VERSIONS.keys.find { |key| version >=
|
28
|
+
match = VERSIONS.keys.find { |key| NewRelic::Helper.version_satisfied?(version, '>=', key) }
|
29
29
|
return unless match
|
30
30
|
|
31
31
|
VERSIONS[match].call(env)
|
@@ -39,13 +39,14 @@ module NewRelic
|
|
39
39
|
# @return {Transaction} The transaction the headers were inserted from,
|
40
40
|
# or +nil+ if headers were not inserted.
|
41
41
|
#
|
42
|
+
# @!scope class
|
42
43
|
# @api public
|
43
44
|
#
|
44
45
|
def insert_distributed_trace_headers(headers = {})
|
45
46
|
record_api_supportability_metric(:insert_distributed_trace_headers)
|
46
47
|
|
47
48
|
unless Agent.config[:'distributed_tracing.enabled']
|
48
|
-
NewRelic::Agent.logger.
|
49
|
+
NewRelic::Agent.logger.debug('Not configured to insert distributed trace headers')
|
49
50
|
return nil
|
50
51
|
end
|
51
52
|
|
@@ -93,13 +94,14 @@ module NewRelic
|
|
93
94
|
#
|
94
95
|
# @return {Transaction} if successful, +nil+ otherwise
|
95
96
|
#
|
97
|
+
# @!scope class
|
96
98
|
# @api public
|
97
99
|
#
|
98
100
|
def accept_distributed_trace_headers(headers, transport_type = NewRelic::HTTP)
|
99
101
|
record_api_supportability_metric(:accept_distributed_trace_headers)
|
100
102
|
|
101
103
|
unless Agent.config[:'distributed_tracing.enabled']
|
102
|
-
NewRelic::Agent.logger.
|
104
|
+
NewRelic::Agent.logger.debug('Not configured to accept distributed trace headers')
|
103
105
|
return nil
|
104
106
|
end
|
105
107
|
|
@@ -110,6 +110,29 @@ module NewRelic
|
|
110
110
|
false
|
111
111
|
end
|
112
112
|
|
113
|
+
# Neither ignored nor expected errors impact apdex.
|
114
|
+
#
|
115
|
+
# Ignored errors are checked via `#error_is_ignored?`
|
116
|
+
# Expected errors are checked in 2 separate ways:
|
117
|
+
# 1. The presence of an `expected: true` attribute key/value pair in the
|
118
|
+
# options hash, which will be set if that key/value pair was used in
|
119
|
+
# the `notice_error` public API.
|
120
|
+
# 2. By calling `#expected?` which in turn calls `ErrorFilter#expected?`
|
121
|
+
# which checks for 3 things:
|
122
|
+
# - A match for user-defined HTTP status codes to expect
|
123
|
+
# - A match for user-defined error classes to expect
|
124
|
+
# - A match for user-defined error messages to expect
|
125
|
+
def error_affects_apdex?(error, options)
|
126
|
+
return false if error_is_ignored?(error)
|
127
|
+
return false if options[:expected]
|
128
|
+
|
129
|
+
!expected?(error, ::NewRelic::Agent::Tracer.state.current_transaction&.http_response_code)
|
130
|
+
rescue => e
|
131
|
+
NewRelic::Agent.logger.error("Could not determine if error '#{error}' should impact Apdex - " \
|
132
|
+
"#{e.class}: #{e.message}. Defaulting to 'true' (it should impact Apdex).")
|
133
|
+
true
|
134
|
+
end
|
135
|
+
|
113
136
|
# Calling instance_variable_set on a wrapped Java object in JRuby will
|
114
137
|
# generate a warning unless that object's class has already been marked
|
115
138
|
# as persistent, so we skip tagging of exception objects that are actually
|
@@ -214,7 +237,8 @@ module NewRelic
|
|
214
237
|
end
|
215
238
|
|
216
239
|
def notice_segment_error(segment, exception, options = {})
|
217
|
-
|
240
|
+
status_code = process_http_status_code(exception, options)
|
241
|
+
return if skip_notice_error?(exception, status_code)
|
218
242
|
|
219
243
|
options.merge!(segment.llm_event.error_attributes(exception)) if segment.llm_event
|
220
244
|
|
@@ -227,15 +251,13 @@ module NewRelic
|
|
227
251
|
|
228
252
|
# See NewRelic::Agent.notice_error for options and commentary
|
229
253
|
def notice_error(exception, options = {}, span_id = nil)
|
230
|
-
|
231
|
-
transaction = state.current_transaction
|
232
|
-
status_code = transaction&.http_response_code
|
233
|
-
|
254
|
+
status_code = process_http_status_code(exception, options)
|
234
255
|
return if skip_notice_error?(exception, status_code)
|
235
256
|
|
236
257
|
tag_exception(exception)
|
237
258
|
|
238
|
-
|
259
|
+
state = ::NewRelic::Agent::Tracer.state
|
260
|
+
if options[:expected]
|
239
261
|
increment_expected_error_count!(state, exception)
|
240
262
|
else
|
241
263
|
increment_error_count!(state, exception, options)
|
@@ -243,10 +265,8 @@ module NewRelic
|
|
243
265
|
|
244
266
|
noticed_error = create_noticed_error(exception, options)
|
245
267
|
error_trace_aggregator.add_to_error_queue(noticed_error)
|
246
|
-
|
247
|
-
|
248
|
-
span_id ||= transaction&.current_segment ? transaction.current_segment.guid : nil
|
249
|
-
error_event_aggregator.record(noticed_error, payload, span_id)
|
268
|
+
span_id ||= state.current_transaction&.current_segment&.guid
|
269
|
+
error_event_aggregator.record(noticed_error, state.current_transaction&.payload, span_id)
|
250
270
|
exception
|
251
271
|
rescue => e
|
252
272
|
::NewRelic::Agent.logger.warn("Failure when capturing error '#{exception}':", e)
|
@@ -336,6 +356,13 @@ module NewRelic
|
|
336
356
|
def error_group_callback
|
337
357
|
NewRelic::Agent.error_group_callback
|
338
358
|
end
|
359
|
+
|
360
|
+
def process_http_status_code(exception, options)
|
361
|
+
status_code = ::NewRelic::Agent::Tracer.state.current_transaction&.http_response_code
|
362
|
+
options[:expected] = true if !options[:expected] && @error_filter.expected?(exception, status_code)
|
363
|
+
|
364
|
+
status_code
|
365
|
+
end
|
339
366
|
end
|
340
367
|
end
|
341
368
|
end
|
@@ -29,6 +29,7 @@ module NewRelic
|
|
29
29
|
#
|
30
30
|
# @param request_metadata [String] received obfuscated request metadata
|
31
31
|
#
|
32
|
+
# @!scope class
|
32
33
|
# @api public
|
33
34
|
#
|
34
35
|
def process_request_metadata(request_metadata)
|
@@ -74,6 +75,7 @@ module NewRelic
|
|
74
75
|
#
|
75
76
|
# @return [String] obfuscated response metadata to send
|
76
77
|
#
|
78
|
+
# @!scope class
|
77
79
|
# @api public
|
78
80
|
#
|
79
81
|
def get_response_metadata
|
@@ -0,0 +1,136 @@
|
|
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
|
+
class HealthCheck
|
8
|
+
def initialize
|
9
|
+
@start_time = nano_time
|
10
|
+
@continue = true
|
11
|
+
@status = HEALTHY
|
12
|
+
# the following assignments may set @continue = false if they are invalid
|
13
|
+
set_enabled
|
14
|
+
set_delivery_location
|
15
|
+
set_frequency
|
16
|
+
end
|
17
|
+
|
18
|
+
HEALTHY = {healthy: true, last_error: 'NR-APM-000', message: 'Healthy'}.freeze
|
19
|
+
INVALID_LICENSE_KEY = {healthy: false, last_error: 'NR-APM-001', message: 'Invalid license key (HTTP status code 401)'}.freeze
|
20
|
+
MISSING_LICENSE_KEY = {healthy: false, last_error: 'NR-APM-002', message: 'License key missing in configuration'}.freeze
|
21
|
+
FORCED_DISCONNECT = {healthy: false, last_error: 'NR-APM-003', message: 'Forced disconnect received from New Relic (HTTP status code 410)'}.freeze
|
22
|
+
HTTP_ERROR = {healthy: false, last_error: 'NR-APM-004', message: 'HTTP error response code [%s] recevied from New Relic while sending data type [%s]'}.freeze
|
23
|
+
MISSING_APP_NAME = {healthy: false, last_error: 'NR-APM-005', message: 'Missing application name in agent configuration'}.freeze
|
24
|
+
APP_NAME_EXCEEDED = {healthy: false, last_error: 'NR-APM-006', message: 'The maximum number of configured app names (3) exceeded'}.freeze
|
25
|
+
PROXY_CONFIG_ERROR = {healthy: false, last_error: 'NR-APM-007', message: 'HTTP Proxy configuration error; response code [%s]'}.freeze
|
26
|
+
AGENT_DISABLED = {healthy: false, last_error: 'NR-APM-008', message: 'Agent is disabled via configuration'}.freeze
|
27
|
+
FAILED_TO_CONNECT = {healthy: false, last_error: 'NR-APM-009', message: 'Failed to connect to New Relic data collector'}.freeze
|
28
|
+
FAILED_TO_PARSE_CONFIG = {healthy: false, last_error: 'NR-APM-010', message: 'Agent config file is not able to be parsed'}.freeze
|
29
|
+
SHUTDOWN = {healthy: true, last_error: 'NR-APM-099', message: 'Agent has shutdown'}.freeze
|
30
|
+
|
31
|
+
def create_and_run_health_check_loop
|
32
|
+
return unless health_checks_enabled? && @continue
|
33
|
+
|
34
|
+
NewRelic::Agent.logger.debug('Agent Control health check conditions met. Starting health checks.')
|
35
|
+
NewRelic::Agent.record_metric('Supportability/AgentControl/Health/enabled', 1)
|
36
|
+
|
37
|
+
Thread.new do
|
38
|
+
while @continue
|
39
|
+
begin
|
40
|
+
sleep @frequency
|
41
|
+
write_file
|
42
|
+
@continue = false if @status == SHUTDOWN
|
43
|
+
rescue StandardError => e
|
44
|
+
NewRelic::Agent.logger.error("Aborting Agent Control health check. Error raised: #{e}")
|
45
|
+
@continue = false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_status(status, options = [])
|
52
|
+
return unless @continue
|
53
|
+
|
54
|
+
@status = status.dup
|
55
|
+
update_message(options) unless options.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
def healthy?
|
59
|
+
@status == HEALTHY
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def set_enabled
|
65
|
+
@enabled = if ENV['NEW_RELIC_AGENT_CONTROL_ENABLED'] == 'true'
|
66
|
+
true
|
67
|
+
else
|
68
|
+
NewRelic::Agent.logger.debug('NEW_RELIC_AGENT_CONTROL_ENABLED not true, disabling health checks')
|
69
|
+
@continue = false
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def set_delivery_location
|
75
|
+
@delivery_location = if ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_DELIVERY_LOCATION']
|
76
|
+
# The spec states file paths for the delivery location will begin with file://
|
77
|
+
# This does not create a valid path in Ruby, so remove the prefix when present
|
78
|
+
ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_DELIVERY_LOCATION']&.gsub('file://', '')
|
79
|
+
else
|
80
|
+
# The spec default is 'file:///newrelic/apm/health', but since we're just going to remove it anyway...
|
81
|
+
'/newrelic/apm/health'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_frequency
|
86
|
+
@frequency = ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_FREQUENCY'] ? ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_FREQUENCY'].to_i : 5
|
87
|
+
|
88
|
+
if @frequency <= 0
|
89
|
+
NewRelic::Agent.logger.debug('NEW_RELIC_AGENT_CONTROL_HEALTH_FREQUENCY zero or less, disabling health checks')
|
90
|
+
@continue = false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def contents
|
95
|
+
<<~CONTENTS
|
96
|
+
healthy: #{@status[:healthy]}
|
97
|
+
status: #{@status[:message]}#{last_error}
|
98
|
+
start_time_unix_nano: #{@start_time}
|
99
|
+
status_time_unix_nano: #{nano_time}
|
100
|
+
CONTENTS
|
101
|
+
end
|
102
|
+
|
103
|
+
def last_error
|
104
|
+
@status[:healthy] ? '' : "\nlast_error: #{@status[:last_error]}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def nano_time
|
108
|
+
Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
|
109
|
+
end
|
110
|
+
|
111
|
+
def file_name
|
112
|
+
"health-#{NewRelic::Agent::GuidGenerator.generate_guid(32)}.yml"
|
113
|
+
end
|
114
|
+
|
115
|
+
def write_file
|
116
|
+
@file ||= "#{@delivery_location}/#{file_name}"
|
117
|
+
|
118
|
+
File.write(@file, contents)
|
119
|
+
rescue StandardError => e
|
120
|
+
NewRelic::Agent.logger.error("Agent Control health check raised an error while writing a file: #{e}")
|
121
|
+
@continue = false
|
122
|
+
end
|
123
|
+
|
124
|
+
def health_checks_enabled?
|
125
|
+
@enabled && @delivery_location && @frequency > 0
|
126
|
+
end
|
127
|
+
|
128
|
+
def update_message(options)
|
129
|
+
@status[:message] = sprintf(@status[:message], *options)
|
130
|
+
rescue StandardError => e
|
131
|
+
NewRelic::Agent.logger.debug("Error raised while updating Agent Control health check message: #{e}." \
|
132
|
+
"options = #{options}, @status[:message] = #{@status[:message]}")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -16,7 +16,7 @@ DependencyDetection.defer do
|
|
16
16
|
defined?(ActionDispatch) &&
|
17
17
|
defined?(ActionPack) &&
|
18
18
|
ActionPack.respond_to?(:gem_version) &&
|
19
|
-
ActionPack.gem_version >=
|
19
|
+
NewRelic::Helper.version_satisfied?(ActionPack.gem_version, '>=', '6.0.0') && # notifications for dispatch added in Rails 6
|
20
20
|
!NewRelic::Agent::Instrumentation::ActionDispatchSubscriber.subscribed?
|
21
21
|
end
|
22
22
|
|
@@ -15,7 +15,7 @@ DependencyDetection.defer do
|
|
15
15
|
defined?(ActiveSupport) &&
|
16
16
|
defined?(ActionMailbox) &&
|
17
17
|
ActionMailbox.respond_to?(:gem_version) && # 'require "action_mailbox"' doesn't require version...
|
18
|
-
ActionMailbox.gem_version >=
|
18
|
+
NewRelic::Helper.version_satisfied?(ActionMailbox.gem_version, '>=', '7.1.0.alpha') && # notifications added in Rails 7.1
|
19
19
|
!NewRelic::Agent::Instrumentation::ActionMailboxSubscriber.subscribed?
|
20
20
|
end
|
21
21
|
|
@@ -15,7 +15,7 @@ DependencyDetection.defer do
|
|
15
15
|
defined?(ActiveSupport) &&
|
16
16
|
defined?(ActionMailer) &&
|
17
17
|
ActionMailer.respond_to?(:gem_version) &&
|
18
|
-
ActionMailer.gem_version >=
|
18
|
+
NewRelic::Helper.version_satisfied?(ActionMailer.gem_version, '>=', '5.0') &&
|
19
19
|
!NewRelic::Agent::Instrumentation::ActionMailerSubscriber.subscribed?
|
20
20
|
end
|
21
21
|
|
@@ -30,7 +30,7 @@ DependencyDetection.defer do
|
|
30
30
|
executes do
|
31
31
|
if defined?(ActiveSupport) &&
|
32
32
|
ActiveJob.respond_to?(:gem_version) &&
|
33
|
-
ActiveJob.gem_version >=
|
33
|
+
NewRelic::Helper.version_satisfied?(ActiveJob.gem_version, '>=', '6.0.0') &&
|
34
34
|
!NewRelic::Agent.config[:disable_activejob] &&
|
35
35
|
!NewRelic::Agent::Instrumentation::ActiveJobSubscriber.subscribed?
|
36
36
|
NewRelic::Agent.logger.info('Installing notifications based ActiveJob instrumentation')
|
@@ -8,7 +8,7 @@ module NewRelic
|
|
8
8
|
module Agent
|
9
9
|
module Instrumentation
|
10
10
|
class ActiveJobSubscriber < NotificationsSubscriber
|
11
|
-
PAYLOAD_KEYS = %i[adapter db_runtime error job wait]
|
11
|
+
PAYLOAD_KEYS = %i[adapter db_runtime error job wait jobs]
|
12
12
|
|
13
13
|
def add_segment_params(segment, payload)
|
14
14
|
PAYLOAD_KEYS.each do |key|
|
@@ -16,8 +16,12 @@ module NewRelic
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
# NOTE: For `enqueue_all.active_job`, only the first job is used to determine the queue.
|
20
|
+
# Therefore, this assumes all jobs given as arguments for perform_all_later share the same queue.
|
19
21
|
def metric_name(name, payload)
|
20
|
-
|
22
|
+
job = payload[:job] || payload[:jobs].first
|
23
|
+
|
24
|
+
queue = job.queue_name
|
21
25
|
method = method_from_name(name)
|
22
26
|
"Ruby/ActiveJob/#{queue}/#{method}"
|
23
27
|
end
|
@@ -35,17 +35,4 @@ DependencyDetection.defer do
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
39
|
-
executes do
|
40
|
-
next unless Gem::Version.new(ActiveMerchant::VERSION) < Gem::Version.new('1.65.0')
|
41
|
-
|
42
|
-
deprecation_msg = 'The Ruby agent is dropping support for ActiveMerchant versions below 1.65.0 ' \
|
43
|
-
'in version 9.0.0. Please upgrade your ActiveMerchant version to continue receiving full support. ' \
|
44
|
-
|
45
|
-
NewRelic::Agent.logger.log_once(
|
46
|
-
:warn,
|
47
|
-
:deprecated_active_merchant_version,
|
48
|
-
deprecation_msg
|
49
|
-
)
|
50
|
-
end
|
51
38
|
end
|