newrelic_rpm 8.11.0 → 8.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -3
  3. data/.rubocop_todo.yml +14 -7
  4. data/Brewfile +1 -0
  5. data/CHANGELOG.md +78 -16
  6. data/README.md +1 -1
  7. data/bin/nrdebug +2 -0
  8. data/docker-compose.yml +22 -0
  9. data/lib/new_relic/agent/agent/shutdown.rb +1 -0
  10. data/lib/new_relic/agent/agent/special_startup.rb +2 -0
  11. data/lib/new_relic/agent/agent/startup.rb +1 -0
  12. data/lib/new_relic/agent/agent_logger.rb +1 -1
  13. data/lib/new_relic/agent/attributes.rb +1 -0
  14. data/lib/new_relic/agent/audit_logger.rb +2 -1
  15. data/lib/new_relic/agent/commands/thread_profiler_session.rb +1 -0
  16. data/lib/new_relic/agent/configuration/default_source.rb +1415 -1359
  17. data/lib/new_relic/agent/configuration/dotted_hash.rb +1 -0
  18. data/lib/new_relic/agent/configuration/environment_source.rb +3 -2
  19. data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
  20. data/lib/new_relic/agent/configuration/manager.rb +3 -0
  21. data/lib/new_relic/agent/configuration/security_policy_source.rb +10 -0
  22. data/lib/new_relic/agent/configuration/yaml_source.rb +1 -0
  23. data/lib/new_relic/agent/connect/request_builder.rb +1 -0
  24. data/lib/new_relic/agent/database/obfuscation_helpers.rb +1 -0
  25. data/lib/new_relic/agent/database.rb +7 -0
  26. data/lib/new_relic/agent/database_adapter.rb +2 -0
  27. data/lib/new_relic/agent/datastores/mongo/event_formatter.rb +3 -2
  28. data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +1 -1
  29. data/lib/new_relic/agent/datastores/nosql_obfuscator.rb +41 -0
  30. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +3 -0
  31. data/lib/new_relic/agent/distributed_tracing/distributed_trace_attributes.rb +3 -0
  32. data/lib/new_relic/agent/distributed_tracing/distributed_trace_metrics.rb +1 -0
  33. data/lib/new_relic/agent/distributed_tracing/distributed_trace_payload.rb +1 -0
  34. data/lib/new_relic/agent/distributed_tracing/trace_context.rb +1 -0
  35. data/lib/new_relic/agent/encoding_normalizer.rb +2 -0
  36. data/lib/new_relic/agent/error_collector.rb +3 -0
  37. data/lib/new_relic/agent/error_filter.rb +1 -0
  38. data/lib/new_relic/agent/error_trace_aggregator.rb +1 -0
  39. data/lib/new_relic/agent/event_aggregator.rb +1 -0
  40. data/lib/new_relic/agent/event_loop.rb +2 -0
  41. data/lib/new_relic/agent/http_clients/abstract.rb +2 -0
  42. data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +1 -1
  43. data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +1 -1
  44. data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +1 -0
  45. data/lib/new_relic/agent/instrumentation/active_merchant.rb +1 -2
  46. data/lib/new_relic/agent/instrumentation/active_storage_subscriber.rb +2 -0
  47. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +1 -2
  48. data/lib/new_relic/agent/instrumentation/authlogic.rb +0 -2
  49. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -0
  50. data/lib/new_relic/agent/instrumentation/data_mapper.rb +0 -1
  51. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +1 -2
  52. data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +29 -0
  53. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +66 -0
  54. data/lib/new_relic/agent/instrumentation/elasticsearch/prepend.rb +13 -0
  55. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +31 -0
  56. data/lib/new_relic/agent/instrumentation/excon.rb +17 -0
  57. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +1 -0
  58. data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +4 -0
  59. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +2 -0
  60. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +2 -0
  61. data/lib/new_relic/agent/instrumentation/rack/chain.rb +10 -2
  62. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +3 -0
  63. data/lib/new_relic/agent/instrumentation/rack/prepend.rb +9 -2
  64. data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +0 -1
  65. data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +1 -0
  66. data/lib/new_relic/agent/instrumentation/redis/chain.rb +18 -6
  67. data/lib/new_relic/agent/instrumentation/redis/constants.rb +17 -0
  68. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +28 -18
  69. data/lib/new_relic/agent/instrumentation/redis/middleware.rb +16 -0
  70. data/lib/new_relic/agent/instrumentation/redis/prepend.rb +6 -0
  71. data/lib/new_relic/agent/instrumentation/redis.rb +6 -0
  72. data/lib/new_relic/agent/instrumentation/sidekiq/client.rb +20 -0
  73. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +30 -0
  74. data/lib/new_relic/agent/instrumentation/sidekiq/server.rb +37 -0
  75. data/lib/new_relic/agent/instrumentation/sidekiq.rb +7 -70
  76. data/lib/new_relic/agent/instrumentation/sinatra.rb +1 -2
  77. data/lib/new_relic/agent/instrumentation/sunspot.rb +0 -2
  78. data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +1 -0
  79. data/lib/new_relic/agent/instrumentation/tilt/instrumentation.rb +1 -0
  80. data/lib/new_relic/agent/javascript_instrumentor.rb +1 -0
  81. data/lib/new_relic/agent/local_log_decorator.rb +1 -0
  82. data/lib/new_relic/agent/log_event_aggregator.rb +1 -0
  83. data/lib/new_relic/agent/messaging.rb +1 -0
  84. data/lib/new_relic/agent/method_tracer.rb +4 -0
  85. data/lib/new_relic/agent/method_tracer_helpers.rb +1 -1
  86. data/lib/new_relic/agent/monitors/distributed_tracing_monitor.rb +1 -0
  87. data/lib/new_relic/agent/new_relic_service.rb +2 -0
  88. data/lib/new_relic/agent/parameter_filtering.rb +7 -1
  89. data/lib/new_relic/agent/pipe_channel_manager.rb +2 -0
  90. data/lib/new_relic/agent/rules_engine.rb +1 -0
  91. data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -0
  92. data/lib/new_relic/agent/samplers/memory_sampler.rb +5 -0
  93. data/lib/new_relic/agent/span_event_primitive.rb +1 -0
  94. data/lib/new_relic/agent/stats.rb +1 -0
  95. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +1 -0
  96. data/lib/new_relic/agent/system_info.rb +3 -0
  97. data/lib/new_relic/agent/threading/agent_thread.rb +1 -0
  98. data/lib/new_relic/agent/threading/backtrace_service.rb +1 -0
  99. data/lib/new_relic/agent/threading/thread_profile.rb +3 -0
  100. data/lib/new_relic/agent/tracer.rb +5 -1
  101. data/lib/new_relic/agent/transaction/abstract_segment.rb +3 -0
  102. data/lib/new_relic/agent/transaction/datastore_segment.rb +3 -0
  103. data/lib/new_relic/agent/transaction/distributed_tracer.rb +4 -0
  104. data/lib/new_relic/agent/transaction/distributed_tracing.rb +1 -0
  105. data/lib/new_relic/agent/transaction/external_request_segment.rb +1 -0
  106. data/lib/new_relic/agent/transaction/message_broker_segment.rb +1 -0
  107. data/lib/new_relic/agent/transaction/segment.rb +1 -0
  108. data/lib/new_relic/agent/transaction/trace.rb +4 -0
  109. data/lib/new_relic/agent/transaction/trace_node.rb +1 -0
  110. data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +2 -0
  111. data/lib/new_relic/agent/transaction.rb +10 -0
  112. data/lib/new_relic/agent/transaction_event_aggregator.rb +1 -0
  113. data/lib/new_relic/agent/transaction_time_aggregator.rb +1 -0
  114. data/lib/new_relic/agent/utilization/pcf.rb +1 -0
  115. data/lib/new_relic/agent/utilization/vendor.rb +2 -0
  116. data/lib/new_relic/agent/utilization_data.rb +3 -0
  117. data/lib/new_relic/agent.rb +4 -2
  118. data/lib/new_relic/cli/commands/install.rb +1 -0
  119. data/lib/new_relic/coerce.rb +6 -0
  120. data/lib/new_relic/collection_helper.rb +1 -0
  121. data/lib/new_relic/constants.rb +2 -0
  122. data/lib/new_relic/control/frameworks/rails.rb +5 -0
  123. data/lib/new_relic/control/instrumentation.rb +6 -8
  124. data/lib/new_relic/dependency_detection.rb +2 -0
  125. data/lib/new_relic/helper.rb +1 -0
  126. data/lib/new_relic/language_support.rb +1 -0
  127. data/lib/new_relic/latest_changes.rb +1 -0
  128. data/lib/new_relic/local_environment.rb +7 -1
  129. data/lib/new_relic/metric_spec.rb +2 -0
  130. data/lib/new_relic/rack/agent_middleware.rb +2 -0
  131. data/lib/new_relic/rack/browser_monitoring.rb +1 -0
  132. data/lib/new_relic/traced_thread.rb +1 -0
  133. data/lib/new_relic/version.rb +1 -1
  134. data/lib/tasks/helpers/format.rb +3 -0
  135. data/lib/tasks/helpers/prompt.rb +1 -1
  136. data/lib/tasks/instrumentation_generator/README.md +2 -2
  137. data/lib/tasks/instrumentation_generator/TODO.md +5 -5
  138. data/lib/tasks/instrumentation_generator/instrumentation.thor +27 -5
  139. data/lib/tasks/instrumentation_generator/templates/chain.tt +2 -1
  140. data/lib/tasks/instrumentation_generator/templates/chain_method.tt +3 -2
  141. data/lib/tasks/instrumentation_generator/templates/instrumentation.tt +2 -1
  142. data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +1 -1
  143. data/lib/tasks/instrumentation_generator/templates/prepend.tt +1 -1
  144. data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +1 -1
  145. data/lib/tasks/instrumentation_generator/templates/test.tt +1 -1
  146. data/newrelic.yml +13 -3
  147. data/newrelic_rpm.gemspec +7 -7
  148. data/test/agent_helper.rb +24 -0
  149. metadata +18 -79
  150. data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +0 -43
@@ -36,6 +36,7 @@ module NewRelic
36
36
  def dot_flattened(nested_hash, names = [], result = {})
37
37
  nested_hash.each do |key, val|
38
38
  next if val.nil?
39
+
39
40
  if val.respond_to?(:has_key?)
40
41
  dot_flattened(val, names + [key], result)
41
42
  else
@@ -34,6 +34,7 @@ module NewRelic
34
34
  set_dotted_alias(config_setting)
35
35
 
36
36
  return unless value[:aliases]
37
+
37
38
  value[:aliases].each do |config_alias|
38
39
  self.alias_map[config_alias] = config_setting
39
40
  end
@@ -50,8 +51,8 @@ module NewRelic
50
51
 
51
52
  def set_log_file
52
53
  if ENV['NEW_RELIC_LOG']
53
- if ENV['NEW_RELIC_LOG'].casecmp('STDOUT').zero?
54
- self[:log_file_path] = self[:log_file_name] = 'STDOUT'
54
+ if ENV['NEW_RELIC_LOG'].casecmp(NewRelic::STANDARD_OUT) == 0
55
+ self[:log_file_path] = self[:log_file_name] = NewRelic::STANDARD_OUT
55
56
  else
56
57
  self[:log_file_path] = File.dirname(ENV['NEW_RELIC_LOG'])
57
58
  self[:log_file_name] = File.basename(ENV['NEW_RELIC_LOG'])
@@ -18,6 +18,7 @@ module NewRelic
18
18
  :'transaction_tracer.record_sql' => record_sql_setting(local_settings, :'transaction_tracer.record_sql'),
19
19
  :'slow_sql.record_sql' => record_sql_setting(local_settings, :'slow_sql.record_sql'),
20
20
  :'mongo.obfuscate_queries' => true,
21
+ :'elasticsearch.obfuscate_queries' => true,
21
22
  :'transaction_tracer.record_redis_arguments' => false,
22
23
 
23
24
  :'custom_insights_events.enabled' => false,
@@ -36,6 +36,7 @@ module NewRelic
36
36
 
37
37
  def add_config_for_testing(source, level = 0)
38
38
  raise 'Invalid config type for testing' unless [Hash, DottedHash].include?(source.class)
39
+
39
40
  invoke_callbacks(:add, source)
40
41
  @configs_for_testing << [source.freeze, level]
41
42
  reset_cache
@@ -110,6 +111,7 @@ module NewRelic
110
111
  def fetch(key)
111
112
  config_stack.each do |config|
112
113
  next unless config
114
+
113
115
  accessor = key.to_sym
114
116
 
115
117
  if config.has_key?(accessor)
@@ -160,6 +162,7 @@ module NewRelic
160
162
 
161
163
  def invoke_callbacks(direction, source)
162
164
  return unless source
165
+
163
166
  source.keys.each do |key|
164
167
  begin
165
168
  # we need to evaluate and apply transformations for the value to deal with procs as values
@@ -79,6 +79,15 @@ module NewRelic
79
79
  change_setting(policies, :'mongo.obfuscate_queries', true)
80
80
  }
81
81
  },
82
+ {
83
+ option: :'elasticsearch.capture_queries',
84
+ supported: true,
85
+ enabled_fn: method(:enabled?),
86
+ disabled_value: false,
87
+ permitted_fn: proc { |policies|
88
+ change_setting(policies, :'elasticsearch.obfuscate_queries', true)
89
+ }
90
+ },
82
91
  {
83
92
  option: :'transaction_tracer.record_redis_arguments',
84
93
  supported: true,
@@ -212,6 +221,7 @@ module NewRelic
212
221
  security_policies.inject({}) do |settings, (policy_name, policy_settings)|
213
222
  SECURITY_SETTINGS_MAP[policy_name].each do |policy|
214
223
  next unless policy[:supported]
224
+
215
225
  if policy_settings[ENABLED]
216
226
  if policy[:enabled_fn].call(policy[:option])
217
227
  if permitted_fn = policy[:permitted_fn]
@@ -156,6 +156,7 @@ module NewRelic
156
156
  def dot_flattened(nested_hash, names = [], result = {})
157
157
  nested_hash.each do |key, val|
158
158
  next if val.nil?
159
+
159
160
  if val.respond_to?(:has_key?) && !CONFIG_WITH_HASH_VALUE.include?(key)
160
161
  dot_flattened(val, names + [key], result)
161
162
  else
@@ -42,6 +42,7 @@ module NewRelic
42
42
  # clear out so downstream code doesn't have to check again.
43
43
  def sanitize_environment_report(environment_report)
44
44
  return NewRelic::EMPTY_ARRAY unless @service.valid_to_marshal?(environment_report)
45
+
45
46
  environment_report
46
47
  end
47
48
 
@@ -53,6 +53,7 @@ module NewRelic
53
53
 
54
54
  def obfuscate_single_quote_literals(sql)
55
55
  return sql unless sql =~ COMPONENTS_REGEX_MAP[:single_quotes]
56
+
56
57
  sql.gsub(COMPONENTS_REGEX_MAP[:single_quotes], PLACEHOLDER)
57
58
  end
58
59
 
@@ -32,6 +32,8 @@ module NewRelic
32
32
  # Take care not to the dup the query more than once as
33
33
  # correctly encoded may also dup the query.
34
34
  def capture_query(query)
35
+ return unless query
36
+
35
37
  id = query.object_id
36
38
  query = Helper.correctly_encoded(truncate_query(query))
37
39
  if query.object_id == id
@@ -42,6 +44,8 @@ module NewRelic
42
44
  end
43
45
 
44
46
  def truncate_query(query)
47
+ return unless query
48
+
45
49
  if query.length > (MAX_QUERY_LENGTH - 4)
46
50
  query[0..MAX_QUERY_LENGTH - 4] << ELLIPSIS
47
51
  else
@@ -114,6 +118,7 @@ module NewRelic
114
118
  # in a report period, selected for shipment to New Relic
115
119
  def explain_sql(statement)
116
120
  return nil unless statement.sql && statement.explainer && statement.config
121
+
117
122
  statement.sql = statement.sql.split(";\n")[0] # only explain the first
118
123
  return statement.explain || []
119
124
  end
@@ -223,6 +228,7 @@ module NewRelic
223
228
 
224
229
  def explain
225
230
  return unless explainable?
231
+
226
232
  handle_exception_in_explain do
227
233
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
228
234
  plan = @explainer.call(self)
@@ -238,6 +244,7 @@ module NewRelic
238
244
 
239
245
  def append_sql(new_sql)
240
246
  return if new_sql.empty?
247
+
241
248
  @sql = Database.truncate_query(@sql << NEWLINE << new_sql)
242
249
  end
243
250
 
@@ -13,6 +13,7 @@ module NewRelic
13
13
 
14
14
  def self.value
15
15
  return unless defined? ActiveRecord::Base
16
+
16
17
  new(::NewRelic::Control.instance.env, ActiveRecord::VERSION::STRING).value
17
18
  end
18
19
 
@@ -26,6 +27,7 @@ module NewRelic
26
27
  def value
27
28
  match = VERSIONS.keys.find { |key| version >= Gem::Version.new(key) }
28
29
  return unless match
30
+
29
31
  VERSIONS[match].call(env)
30
32
  end
31
33
  end
@@ -2,7 +2,7 @@
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 'new_relic/agent/datastores/mongo/obfuscator'
5
+ require_relative '../nosql_obfuscator'
6
6
 
7
7
  module NewRelic
8
8
  module Agent
@@ -26,6 +26,7 @@ module NewRelic
26
26
 
27
27
  command.each do |key, value|
28
28
  next if DENYLISTED_KEYS.include?(key)
29
+
29
30
  if OBFUSCATE_KEYS.include?(key)
30
31
  obfuscated = obfuscate(value)
31
32
  result[key] = obfuscated if obfuscated
@@ -38,7 +39,7 @@ module NewRelic
38
39
 
39
40
  def self.obfuscate(statement)
40
41
  if NewRelic::Agent.config[:'mongo.obfuscate_queries']
41
- statement = Obfuscator.obfuscate_statement(statement)
42
+ statement = NewRelic::Agent::Datastores::NosqlObfuscator.obfuscate_statement(statement)
42
43
  end
43
44
  statement
44
45
  end
@@ -2,7 +2,7 @@
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 'new_relic/agent/datastores/mongo/obfuscator'
5
+ require 'new_relic/agent/datastores/nosql_obfuscator'
6
6
  require 'new_relic/agent/datastores/metric_helper'
7
7
 
8
8
  module NewRelic
@@ -0,0 +1,41 @@
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 Datastores
8
+ module NosqlObfuscator
9
+ ALLOWLIST = [:operation].freeze
10
+
11
+ def self.obfuscate_statement(source, allowlist = ALLOWLIST)
12
+ if source.is_a?(Hash)
13
+ obfuscated = {}
14
+ source.each do |key, value|
15
+ if allowlist.include?(key)
16
+ obfuscated[key] = value
17
+ else
18
+ obfuscated[key] = obfuscate_value(value, allowlist)
19
+ end
20
+ end
21
+ obfuscated
22
+ else
23
+ obfuscate_value(source, allowlist)
24
+ end
25
+ end
26
+
27
+ QUESTION_MARK = '?'.freeze
28
+
29
+ def self.obfuscate_value(value, allowlist = ALLOWLIST)
30
+ if value.is_a?(Hash)
31
+ obfuscate_statement(value, allowlist)
32
+ elsif value.is_a?(Array)
33
+ value.map { |v| obfuscate_value(v, allowlist) }
34
+ else
35
+ QUESTION_MARK
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -64,6 +64,7 @@ module NewRelic
64
64
 
65
65
  def add_message_cat_headers(headers)
66
66
  return unless CrossAppTracing.cross_app_enabled?
67
+
67
68
  @is_cross_app_caller = true
68
69
  insert_message_headers(headers,
69
70
  transaction.guid,
@@ -112,9 +113,11 @@ module NewRelic
112
113
  end
113
114
 
114
115
  return unless transaction.include_guid?
116
+
115
117
  payload[:guid] = transaction.guid
116
118
 
117
119
  return unless is_cross_app?
120
+
118
121
  trip_id = cat_trip_id
119
122
  path_hash = cat_path_hash
120
123
  referring_path_hash = cat_referring_path_hash
@@ -25,6 +25,7 @@ module NewRelic
25
25
  # inserts them into the specified destination.
26
26
  def copy_to_hash(transaction_payload, destination)
27
27
  return unless enabled?
28
+
28
29
  INTRINSIC_KEYS.each do |key|
29
30
  value = transaction_payload[key]
30
31
  destination[key] = value unless value.nil?
@@ -35,8 +36,10 @@ module NewRelic
35
36
  # inserts them as intrinsics in the specified transaction_attributes
36
37
  def copy_to_attributes(transaction_payload, destination)
37
38
  return unless enabled?
39
+
38
40
  INTRINSIC_KEYS.each do |key|
39
41
  next unless transaction_payload.key?(key)
42
+
40
43
  destination.add_intrinsic_attribute(key, transaction_payload[key])
41
44
  end
42
45
  end
@@ -23,6 +23,7 @@ module NewRelic
23
23
 
24
24
  def record_metrics_for_transaction(transaction)
25
25
  return unless Agent.config[:'distributed_tracing.enabled']
26
+
26
27
  dt = transaction.distributed_tracer
27
28
  payload = dt.distributed_trace_payload || dt.trace_state_payload
28
29
 
@@ -58,6 +58,7 @@ module NewRelic
58
58
  def from_json(serialized_payload)
59
59
  raw_payload = JSON.parse(serialized_payload)
60
60
  return raw_payload if raw_payload.nil?
61
+
61
62
  payload_data = raw_payload[DATA_KEY]
62
63
 
63
64
  payload = new
@@ -96,6 +96,7 @@ module NewRelic
96
96
  def extract_traceparent(format, carrier)
97
97
  header_name = trace_parent_header_for_format(format)
98
98
  return unless header = carrier[header_name]
99
+
99
100
  if matchdata = header.match(TRACE_PARENT_REGEX)
100
101
  TRACE_PARENT_REGEX.named_captures.inject({}) do |hash, (name, (index))|
101
102
  hash[name] = matchdata[index]
@@ -19,9 +19,11 @@ module NewRelic
19
19
  normalize_string(object.to_s)
20
20
  when Array
21
21
  return object if object.empty?
22
+
22
23
  object.map { |x| normalize_object(x) }
23
24
  when Hash
24
25
  return object if object.empty?
26
+
25
27
  hash = {}
26
28
  object.each_pair do |k, v|
27
29
  k = normalize_string(k) if k.is_a?(String)
@@ -123,11 +123,13 @@ module NewRelic
123
123
 
124
124
  def exception_tagged_with?(ivar, exception)
125
125
  return false if exception_is_java_object?(exception)
126
+
126
127
  exception.instance_variable_defined?(ivar)
127
128
  end
128
129
 
129
130
  def tag_exception_using(ivar, exception)
130
131
  return if exception_is_java_object?(exception) || exception.frozen?
132
+
131
133
  begin
132
134
  exception.instance_variable_set(ivar, true)
133
135
  rescue => e
@@ -137,6 +139,7 @@ module NewRelic
137
139
 
138
140
  def tag_exception(exception)
139
141
  return if exception_is_java_object?(exception) || exception.frozen?
142
+
140
143
  begin
141
144
  exception.instance_variable_set(EXCEPTION_TAG_IVAR, true)
142
145
  rescue => e
@@ -155,6 +155,7 @@ module NewRelic
155
155
  result = []
156
156
  code_list.each do |code|
157
157
  result << code && next if code.is_a?(Integer)
158
+
158
159
  m = code.match(/(\d{3})(-\d{3})?/)
159
160
  if m.nil? || m[1].nil?
160
161
  ::NewRelic::Agent.logger.warn("Invalid HTTP status code: '#{code}'; ignoring config")
@@ -44,6 +44,7 @@ module NewRelic
44
44
  # floor after logging a warning.
45
45
  def add_to_error_queue(noticed_error)
46
46
  return unless enabled?
47
+
47
48
  @lock.synchronize do
48
49
  if !over_queue_limit?(noticed_error.message) && !@errors.include?(noticed_error)
49
50
  @errors << noticed_error
@@ -136,6 +136,7 @@ module NewRelic
136
136
 
137
137
  def notify_if_full
138
138
  return unless !@notified_full && @buffer.full?
139
+
139
140
  NewRelic::Agent.logger.debug("#{self.class.named} capacity of #{@buffer.capacity} reached, beginning sampling")
140
141
  @notified_full = true
141
142
  end
@@ -34,6 +34,7 @@ module NewRelic
34
34
  def calculate_next_fire_time
35
35
  now = Process.clock_gettime(Process::CLOCK_REALTIME)
36
36
  return now if @interval == 0
37
+
37
38
  fire_time = @last_fired_at || now
38
39
  while fire_time <= now
39
40
  fire_time += @interval
@@ -80,6 +81,7 @@ module NewRelic
80
81
 
81
82
  def next_timeout
82
83
  return nil if @timers.empty?
84
+
83
85
  timeout = @timers.values.map(&:next_fire_time).min - Process.clock_gettime(Process::CLOCK_REALTIME)
84
86
  timeout < 0 ? 0 : timeout
85
87
  end
@@ -47,6 +47,7 @@ module NewRelic
47
47
  if wrapped_response.nil?
48
48
  raise ArgumentError, WHINY_NIL_ERROR % self.class
49
49
  end
50
+
50
51
  @wrapped_response = wrapped_response
51
52
  end
52
53
 
@@ -64,6 +65,7 @@ module NewRelic
64
65
 
65
66
  def get_status_code_using(method_name)
66
67
  return unless @wrapped_response.respond_to?(method_name)
68
+
67
69
  code = @wrapped_response.send(method_name).to_i
68
70
  code == 0 ? nil : code
69
71
  end
@@ -9,7 +9,7 @@ module NewRelic
9
9
  module HTTPClients
10
10
  class HTTPResponse < AbstractResponse
11
11
  def [](key)
12
- _, value = @wrapped_response.headers.find { |k, _| key.casecmp(k).zero? }
12
+ _, value = @wrapped_response.headers.find { |k, _| key.casecmp(k) == 0 }
13
13
  value unless value.nil?
14
14
  end
15
15
 
@@ -10,7 +10,7 @@ module NewRelic
10
10
  class HTTPClientResponse < AbstractResponse
11
11
  def [](key)
12
12
  @wrapped_response.headers.each do |k, v|
13
- if key.casecmp(k).zero?
13
+ if key.casecmp(k) == 0
14
14
  return v
15
15
  end
16
16
  end
@@ -67,6 +67,7 @@ module NewRelic
67
67
 
68
68
  def [](key)
69
69
  return nil unless @request.options && @request.options[:headers]
70
+
70
71
  @request.options[:headers][key]
71
72
  end
72
73
 
@@ -38,6 +38,7 @@ DependencyDetection.defer do
38
38
 
39
39
  executes do
40
40
  next unless Gem::Version.new(ActiveMerchant::VERSION) < Gem::Version.new('1.65.0')
41
+
41
42
  deprecation_msg = 'The Ruby Agent is dropping support for ActiveMerchant versions below 1.65.0 ' \
42
43
  'in version 9.0.0. Please upgrade your ActiveMerchant version to continue receiving full support. ' \
43
44
 
@@ -46,7 +47,5 @@ DependencyDetection.defer do
46
47
  :deprecated_active_merchant_version,
47
48
  deprecation_msg
48
49
  )
49
-
50
- ::NewRelic::Agent.record_metric("Supportability/Deprecated/ActiveMerchant", 1)
51
50
  end
52
51
  end
@@ -10,6 +10,7 @@ module NewRelic
10
10
  class ActiveStorageSubscriber < NotificationsSubscriber
11
11
  def start(name, id, payload)
12
12
  return unless state.is_execution_traced?
13
+
13
14
  start_segment(name, id, payload)
14
15
  rescue => e
15
16
  log_notification_error(e, name, 'start')
@@ -17,6 +18,7 @@ module NewRelic
17
18
 
18
19
  def finish(name, id, payload)
19
20
  return unless state.is_execution_traced?
21
+
20
22
  finish_segment(id, payload)
21
23
  rescue => e
22
24
  log_notification_error(e, name, 'finish')
@@ -14,6 +14,7 @@ module NewRelic
14
14
  parse_query_without_newrelic(*args)
15
15
  ensure
16
16
  return unless txn = ::NewRelic::Agent::Tracer.current_transaction
17
+
17
18
  txn.current_segment.params[:statement] = ::NewRelic::Agent::Database.truncate_query(args.first.inspect) rescue nil
18
19
  end
19
20
  end
@@ -52,8 +53,6 @@ DependencyDetection.defer do
52
53
  :deprecated_acts_as_solr,
53
54
  deprecation_msg
54
55
  )
55
-
56
- ::NewRelic::Agent.record_metric("Supportability/Deprecated/ActsAsSolr", 1)
57
56
  end
58
57
 
59
58
  executes do
@@ -21,8 +21,6 @@ DependencyDetection.defer do
21
21
  :deprecated_authlogic,
22
22
  deprecation_msg
23
23
  )
24
-
25
- ::NewRelic::Agent.record_metric("Supportability/Deprecated/Authlogic", 1)
26
24
  end
27
25
 
28
26
  executes do
@@ -273,6 +273,7 @@ module NewRelic
273
273
 
274
274
  def self.class_name(traced_obj, options = {})
275
275
  return options[:class_name] if options[:class_name]
276
+
276
277
  if traced_obj.is_a?(Class) || traced_obj.is_a?(Module)
277
278
  traced_obj.name
278
279
  else
@@ -26,7 +26,6 @@ DependencyDetection.defer do
26
26
  :deprecated_datamapper,
27
27
  deprecation_msg
28
28
  )
29
- ::NewRelic::Agent.record_metric("Supportability/Deprecated/DataMapper", 1)
30
29
  end
31
30
 
32
31
  executes do
@@ -96,6 +96,7 @@ DependencyDetection.defer do
96
96
 
97
97
  executes do
98
98
  next unless delayed_job_version < Gem::Version.new('4.1.0')
99
+
99
100
  deprecation_msg = 'Instrumentation for DelayedJob versions below 4.1.0 is deprecated.' \
100
101
  'It will stop being monitored in version 9.0.0. ' \
101
102
  'Please upgrade your DelayedJob version to continue receiving full support. ' \
@@ -105,8 +106,6 @@ DependencyDetection.defer do
105
106
  :deprecated_delayed_job_version,
106
107
  deprecation_msg
107
108
  )
108
-
109
- ::NewRelic::Agent.record_metric("Supportability/Deprecated/DelayedJob", 1)
110
109
  end
111
110
 
112
111
  def delayed_job_version
@@ -0,0 +1,29 @@
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::Agent::Instrumentation
6
+ module Elasticsearch
7
+ def self.instrument!
8
+ to_instrument = if ::Gem::Version.create(::Elasticsearch::VERSION) <
9
+ ::Gem::Version.create("8.0.0")
10
+ ::Elasticsearch::Transport::Client
11
+ else
12
+ ::Elastic::Transport::Client
13
+ end
14
+
15
+ to_instrument.class_eval do
16
+ include NewRelic::Agent::Instrumentation::Elasticsearch
17
+
18
+ alias_method(:perform_request_without_tracing, :perform_request)
19
+ alias_method(:perform_request, :perform_request_with_tracing)
20
+
21
+ def perform_request(*args)
22
+ perform_request_with_tracing(*args) do
23
+ perform_request_without_tracing(*args)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,66 @@
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
+ require_relative '../../datastores/nosql_obfuscator'
5
+
6
+ module NewRelic::Agent::Instrumentation
7
+ module Elasticsearch
8
+ PRODUCT_NAME = 'Elasticsearch'
9
+ OPERATION = 'perform_request'
10
+
11
+ def perform_request_with_tracing(method, path, params = {}, body = nil, headers = nil)
12
+ return yield unless NewRelic::Agent::Tracer.tracing_enabled?
13
+
14
+ segment = NewRelic::Agent::Tracer.start_datastore_segment(
15
+ product: PRODUCT_NAME,
16
+ operation: nr_operation || OPERATION,
17
+ host: nr_hosts[:host],
18
+ port_path_or_id: path,
19
+ database_name: nr_cluster_name
20
+ )
21
+ begin
22
+ NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
23
+ ensure
24
+ if segment
25
+ segment.notice_nosql_statement(nr_reported_query(body || params))
26
+ segment.finish
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def nr_operation
34
+ operation_index = caller_locations.index do |line|
35
+ string = line.to_s
36
+ string.include?('lib/elasticsearch/api') && !string.include?(OPERATION)
37
+ end
38
+ return nil unless operation_index
39
+
40
+ caller_locations[operation_index].to_s.split('`')[-1].gsub(/\W/, "")
41
+ end
42
+
43
+ def nr_reported_query(query)
44
+ return unless NewRelic::Agent.config[:'elasticsearch.capture_queries']
45
+ return query unless NewRelic::Agent.config[:'elasticsearch.obfuscate_queries']
46
+
47
+ NewRelic::Agent::Datastores::NosqlObfuscator.obfuscate_statement(query)
48
+ end
49
+
50
+ def nr_cluster_name
51
+ return @nr_cluster_name if @nr_cluster_name
52
+ return if nr_hosts.empty?
53
+
54
+ NewRelic::Agent.disable_all_tracing do
55
+ @nr_cluster_name ||= perform_request('GET', '_cluster/health').body["cluster_name"]
56
+ end
57
+ rescue StandardError => e
58
+ NewRelic::Agent.logger.error("Failed to get cluster name for elasticsearch", e)
59
+ nil
60
+ end
61
+
62
+ def nr_hosts
63
+ @nr_hosts ||= (transport.hosts.first || NewRelic::EMPTY_HASH)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,13 @@
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::Agent::Instrumentation
6
+ module Elasticsearch::Prepend
7
+ include NewRelic::Agent::Instrumentation::Elasticsearch
8
+
9
+ def perform_request(*args)
10
+ perform_request_with_tracing(*args) { super }
11
+ end
12
+ end
13
+ end