newrelic_rpm 9.14.0 → 9.18.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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.build_ignore +1 -0
  3. data/CHANGELOG.md +139 -5
  4. data/CONTRIBUTING.md +2 -2
  5. data/lib/boot/strap.rb +4 -3
  6. data/lib/new_relic/agent/agent.rb +4 -0
  7. data/lib/new_relic/agent/agent_helpers/connect.rb +3 -0
  8. data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
  9. data/lib/new_relic/agent/agent_helpers/shutdown.rb +3 -0
  10. data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +1 -0
  11. data/lib/new_relic/agent/agent_helpers/startup.rb +7 -0
  12. data/lib/new_relic/agent/aws.rb +6 -0
  13. data/lib/new_relic/agent/configuration/default_source.rb +336 -115
  14. data/lib/new_relic/agent/configuration/manager.rb +1 -1
  15. data/lib/new_relic/agent/configuration/yaml_source.rb +6 -1
  16. data/lib/new_relic/agent/database.rb +41 -1
  17. data/lib/new_relic/agent/distributed_tracing.rb +2 -2
  18. data/lib/new_relic/agent/health_check.rb +136 -0
  19. data/lib/new_relic/agent/http_clients/uri_util.rb +1 -1
  20. data/lib/new_relic/agent/instrumentation/active_record.rb +1 -8
  21. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +5 -1
  22. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +9 -16
  23. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +0 -2
  24. data/lib/new_relic/agent/instrumentation/active_support_logger.rb +0 -2
  25. data/lib/new_relic/agent/instrumentation/async_http.rb +1 -2
  26. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb +21 -0
  27. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb +66 -0
  28. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb +15 -0
  29. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb +22 -0
  30. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb +21 -0
  31. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +91 -0
  32. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb +15 -0
  33. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb +22 -0
  34. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/chain.rb +33 -0
  35. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/instrumentation.rb +93 -0
  36. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/prepend.rb +23 -0
  37. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda.rb +23 -0
  38. data/lib/new_relic/agent/instrumentation/aws_sqs.rb +0 -2
  39. data/lib/new_relic/agent/instrumentation/bunny.rb +3 -4
  40. data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +0 -2
  41. data/lib/new_relic/agent/instrumentation/curb.rb +3 -4
  42. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +0 -4
  43. data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +3 -4
  44. data/lib/new_relic/agent/instrumentation/dynamodb.rb +0 -2
  45. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +1 -0
  46. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +0 -2
  47. data/lib/new_relic/agent/instrumentation/ethon.rb +0 -4
  48. data/lib/new_relic/agent/instrumentation/fiber.rb +0 -2
  49. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +0 -3
  50. data/lib/new_relic/agent/instrumentation/grape.rb +1 -3
  51. data/lib/new_relic/agent/instrumentation/httpclient.rb +0 -1
  52. data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
  53. data/lib/new_relic/agent/instrumentation/httpx.rb +0 -4
  54. data/lib/new_relic/agent/instrumentation/logger.rb +1 -3
  55. data/lib/new_relic/agent/instrumentation/logstasher.rb +0 -2
  56. data/lib/new_relic/agent/instrumentation/memcache.rb +0 -1
  57. data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +3 -3
  58. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +0 -2
  59. data/lib/new_relic/agent/instrumentation/opensearch.rb +0 -2
  60. data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
  61. data/lib/new_relic/agent/instrumentation/rake.rb +0 -1
  62. data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +2 -1
  63. data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +2 -1
  64. data/lib/new_relic/agent/instrumentation/rdkafka.rb +0 -2
  65. data/lib/new_relic/agent/instrumentation/redis.rb +0 -1
  66. data/lib/new_relic/agent/instrumentation/resque.rb +7 -5
  67. data/lib/new_relic/agent/instrumentation/roda.rb +4 -4
  68. data/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb +14 -4
  69. data/lib/new_relic/agent/instrumentation/ruby_kafka.rb +0 -2
  70. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delay_extensions.rb +24 -0
  71. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +1 -1
  72. data/lib/new_relic/agent/instrumentation/sidekiq.rb +9 -1
  73. data/lib/new_relic/agent/instrumentation/sinatra.rb +3 -6
  74. data/lib/new_relic/agent/instrumentation/thread.rb +0 -2
  75. data/lib/new_relic/agent/instrumentation/tilt.rb +0 -4
  76. data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
  77. data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +11 -8
  78. data/lib/new_relic/agent/instrumentation/view_component.rb +0 -2
  79. data/lib/new_relic/agent/local_log_decorator.rb +12 -2
  80. data/lib/new_relic/agent/log_event_aggregator.rb +28 -2
  81. data/lib/new_relic/agent/new_relic_service.rb +8 -2
  82. data/lib/new_relic/agent/span_event_primitive.rb +4 -2
  83. data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
  84. data/lib/new_relic/agent/transaction/message_broker_segment.rb +3 -0
  85. data/lib/new_relic/agent/transaction/tracing.rb +4 -5
  86. data/lib/new_relic/agent/transaction.rb +2 -1
  87. data/lib/new_relic/agent/utilization_data.rb +15 -5
  88. data/lib/new_relic/agent.rb +2 -2
  89. data/lib/new_relic/control/frameworks/rails4.rb +1 -5
  90. data/lib/new_relic/control/instance_methods.rb +5 -0
  91. data/lib/new_relic/dependency_detection.rb +11 -13
  92. data/lib/new_relic/environment_report.rb +1 -5
  93. data/lib/new_relic/helper.rb +15 -0
  94. data/lib/new_relic/language_support.rb +1 -5
  95. data/lib/new_relic/version.rb +1 -1
  96. data/lib/sequel/extensions/new_relic_instrumentation.rb +1 -1
  97. data/lib/tasks/helpers/newrelicyml.rb +4 -2
  98. data/newrelic.yml +174 -66
  99. data/test/agent_helper.rb +8 -1
  100. metadata +17 -19
  101. data/lib/tasks/instrumentation_generator/README.md +0 -63
  102. data/lib/tasks/instrumentation_generator/TODO.md +0 -33
  103. data/lib/tasks/instrumentation_generator/instrumentation.thor +0 -130
  104. data/lib/tasks/instrumentation_generator/templates/Envfile.tt +0 -9
  105. data/lib/tasks/instrumentation_generator/templates/chain.tt +0 -21
  106. data/lib/tasks/instrumentation_generator/templates/chain_method.tt +0 -7
  107. data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +0 -29
  108. data/lib/tasks/instrumentation_generator/templates/instrumentation.tt +0 -13
  109. data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +0 -3
  110. data/lib/tasks/instrumentation_generator/templates/newrelic.yml.tt +0 -19
  111. data/lib/tasks/instrumentation_generator/templates/prepend.tt +0 -13
  112. data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +0 -3
  113. data/lib/tasks/instrumentation_generator/templates/test.tt +0 -15
@@ -5,6 +5,7 @@
5
5
  require_relative 'sidekiq/client'
6
6
  require_relative 'sidekiq/server'
7
7
  require_relative 'sidekiq/extensions/delayed_class'
8
+ require_relative 'sidekiq/extensions/delay_extensions'
8
9
 
9
10
  DependencyDetection.defer do
10
11
  @name = :sidekiq
@@ -29,7 +30,14 @@ DependencyDetection.defer do
29
30
  chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Client)
30
31
  end
31
32
  config.server_middleware do |chain|
32
- chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Server)
33
+ # We started prepending v chaining NR middleware in 9.18.0 in response to:
34
+ # https://github.com/newrelic/newrelic-ruby-agent/issues/3037
35
+ # This way, exceptions resolved by Sidekiq's own middleware are not reported in the agent
36
+ if chain.respond_to?(:prepend)
37
+ chain.prepend(NewRelic::Agent::Instrumentation::Sidekiq::Server)
38
+ else
39
+ chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Server)
40
+ end
33
41
  end
34
42
 
35
43
  if config.respond_to?(:error_handlers)
@@ -16,10 +16,6 @@ DependencyDetection.defer do
16
16
  depends_on { Sinatra::Base.private_method_defined?(:process_route) }
17
17
  depends_on { Sinatra::Base.private_method_defined?(:route_eval) }
18
18
 
19
- executes do
20
- NewRelic::Agent.logger.info('Installing Sinatra instrumentation')
21
- end
22
-
23
19
  executes do
24
20
  if use_prepend?
25
21
  prepend_instrument Sinatra::Base, NewRelic::Agent::Instrumentation::Sinatra::Prepend
@@ -32,14 +28,15 @@ DependencyDetection.defer do
32
28
  end
33
29
 
34
30
  executes do
31
+ supportability_name = NewRelic::Agent::Instrumentation::Sinatra::Tracer::INSTRUMENTATION_NAME
35
32
  # These requires are inside an executes block because they require rack, and
36
33
  # we can't be sure that rack is available when this file is first required.
37
34
  require 'new_relic/rack/agent_hooks'
38
35
  require 'new_relic/rack/browser_monitoring'
39
36
  if use_prepend?
40
- prepend_instrument Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend
37
+ prepend_instrument Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend, supportability_name
41
38
  else
42
- chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain
39
+ chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain, supportability_name
43
40
  end
44
41
  end
45
42
  end
@@ -9,8 +9,6 @@ DependencyDetection.defer do
9
9
  named :thread
10
10
 
11
11
  executes do
12
- NewRelic::Agent.logger.info('Installing Thread Instrumentation')
13
-
14
12
  if use_prepend?
15
13
  prepend_instrument Thread, NewRelic::Agent::Instrumentation::MonitoredThread::Prepend
16
14
  else
@@ -11,10 +11,6 @@ DependencyDetection.defer do
11
11
 
12
12
  depends_on { defined?(Tilt) }
13
13
 
14
- executes do
15
- NewRelic::Agent.logger.info('Installing Tilt instrumentation')
16
- end
17
-
18
14
  executes do
19
15
  if use_prepend?
20
16
  prepend_instrument Tilt::Template, NewRelic::Agent::Instrumentation::Tilt::Prepend
@@ -18,7 +18,6 @@ DependencyDetection.defer do
18
18
  end
19
19
 
20
20
  executes do
21
- NewRelic::Agent.logger.info('Installing Typhoeus instrumentation')
22
21
  require 'new_relic/agent/distributed_tracing/cross_app_tracing'
23
22
  require 'new_relic/agent/http_clients/typhoeus_wrappers'
24
23
  end
@@ -10,12 +10,7 @@ module NewRelic::Agent::Instrumentation
10
10
  NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
11
11
 
12
12
  begin
13
- segment = NewRelic::Agent::Tracer.start_segment(
14
- name: metric_name(
15
- self.class.respond_to?(:identifier) ? self.class.identifier : nil,
16
- self.class.name
17
- )
18
- )
13
+ segment = NewRelic::Agent::Tracer.start_segment(name: metric_name)
19
14
  yield
20
15
  rescue => e
21
16
  NewRelic::Agent.notice_error(e)
@@ -25,8 +20,16 @@ module NewRelic::Agent::Instrumentation
25
20
  end
26
21
  end
27
22
 
28
- def metric_name(identifier, component)
29
- "View/#{metric_path(identifier)}/#{component}"
23
+ def metric_name
24
+ # ViewComponent determines a component's identifier differently depending on the version
25
+ # https://github.com/ViewComponent/view_component/pull/2153
26
+ component_identifier = defined?(self.class.source_location) ? self.class.source_location : self.class.identifier
27
+
28
+ "View/#{metric_path(component_identifier)}/#{self.class.name}"
29
+ rescue => e
30
+ NewRelic::Agent.logger.error('Error identifying View Component metric name', e)
31
+
32
+ 'View/component'
30
33
  end
31
34
 
32
35
  def metric_path(identifier)
@@ -15,8 +15,6 @@ DependencyDetection.defer do
15
15
  end
16
16
 
17
17
  executes do
18
- NewRelic::Agent.logger.info('Installing ViewComponent instrumentation')
19
-
20
18
  if use_prepend?
21
19
  prepend_instrument ViewComponent::Base, NewRelic::Agent::Instrumentation::ViewComponent::Prepend
22
20
  else
@@ -9,7 +9,7 @@ module NewRelic
9
9
  extend self
10
10
 
11
11
  def decorate(message)
12
- return message unless decorating_enabled?
12
+ return message if !decorating_enabled? || message.nil?
13
13
 
14
14
  metadata = NewRelic::Agent.linking_metadata
15
15
 
@@ -37,7 +37,17 @@ module NewRelic
37
37
  def escape_entity_name(entity_name)
38
38
  return unless entity_name
39
39
 
40
- URI::DEFAULT_PARSER.escape(entity_name)
40
+ # TODO: OLD RUBIES 3.3
41
+ # URI version 1.0 marked URI::RFC3986_PARSER.escape as obsolete,
42
+ # which URI::DEFAULT_PARSER is an alias for.
43
+ # URI version 1.0+ will ship with Ruby 3.4
44
+ # Once we drop support for Rubies below 3.4, we can use the
45
+ # URI::RFC2396 parser exclusively.
46
+ if Gem::Version.new(URI::VERSION) >= Gem::Version.new('1.0')
47
+ URI::RFC2396_PARSER.escape(entity_name)
48
+ else
49
+ URI::DEFAULT_PARSER.escape(entity_name)
50
+ end
41
51
  end
42
52
  end
43
53
  end
@@ -25,6 +25,7 @@ module NewRelic
25
25
  METRICS_SUPPORTABILITY_FORMAT = 'Supportability/Logging/Metrics/Ruby/%s'.freeze
26
26
  FORWARDING_SUPPORTABILITY_FORMAT = 'Supportability/Logging/Forwarding/Ruby/%s'.freeze
27
27
  DECORATING_SUPPORTABILITY_FORMAT = 'Supportability/Logging/LocalDecorating/Ruby/%s'.freeze
28
+ LABELS_SUPPORTABILITY_FORMAT = 'Supportability/Logging/Labels/Ruby/%s'.freeze
28
29
  MAX_BYTES = 32768 # 32 * 1024 bytes (32 kibibytes)
29
30
 
30
31
  named :LogEventAggregator
@@ -38,6 +39,7 @@ module NewRelic
38
39
  METRICS_ENABLED_KEY = :'application_logging.metrics.enabled'
39
40
  FORWARDING_ENABLED_KEY = :'application_logging.forwarding.enabled'
40
41
  DECORATING_ENABLED_KEY = :'application_logging.local_decorating.enabled'
42
+ LABELS_ENABLED_KEY = :'application_logging.forwarding.labels.enabled'
41
43
  LOG_LEVEL_KEY = :'application_logging.forwarding.log_level'
42
44
  CUSTOM_ATTRIBUTES_KEY = :'application_logging.forwarding.custom_attributes'
43
45
 
@@ -51,6 +53,7 @@ module NewRelic
51
53
  @high_security = NewRelic::Agent.config[:high_security]
52
54
  @instrumentation_logger_enabled = NewRelic::Agent::Instrumentation::Logger.enabled?
53
55
  @attributes = NewRelic::Agent::LogEventAttributes.new
56
+
54
57
  register_for_done_configuring(events)
55
58
  end
56
59
 
@@ -186,6 +189,10 @@ module NewRelic
186
189
  attributes.add_custom_attributes(custom_attributes)
187
190
  end
188
191
 
192
+ def labels
193
+ @labels ||= create_labels
194
+ end
195
+
189
196
  # Because our transmission format (MELT) is different than historical
190
197
  # agent payloads, extract the munging here to keep the service focused
191
198
  # on the general harvest + transmit instead of the format.
@@ -201,8 +208,9 @@ module NewRelic
201
208
  # To save on unnecessary data transmission, trim the entity.type
202
209
  # sent by classic logs-in-context
203
210
  common_attributes.delete(ENTITY_TYPE_KEY)
204
-
205
- common_attributes.merge!(NewRelic::Agent.agent.log_event_aggregator.attributes.custom_attributes)
211
+ aggregator = NewRelic::Agent.agent.log_event_aggregator
212
+ common_attributes.merge!(aggregator.attributes.custom_attributes)
213
+ common_attributes.merge!(aggregator.labels)
206
214
 
207
215
  _, items = data
208
216
  payload = [{
@@ -247,6 +255,7 @@ module NewRelic
247
255
  record_configuration_metric(METRICS_SUPPORTABILITY_FORMAT, METRICS_ENABLED_KEY)
248
256
  record_configuration_metric(FORWARDING_SUPPORTABILITY_FORMAT, FORWARDING_ENABLED_KEY)
249
257
  record_configuration_metric(DECORATING_SUPPORTABILITY_FORMAT, DECORATING_ENABLED_KEY)
258
+ record_configuration_metric(LABELS_SUPPORTABILITY_FORMAT, LABELS_ENABLED_KEY)
250
259
 
251
260
  add_custom_attributes(NewRelic::Agent.config[CUSTOM_ATTRIBUTES_KEY])
252
261
  end
@@ -327,6 +336,23 @@ module NewRelic
327
336
 
328
337
  Logger::Severity.const_get(severity_constant) < Logger::Severity.const_get(configured_log_level_constant)
329
338
  end
339
+
340
+ def create_labels
341
+ return NewRelic::EMPTY_HASH unless NewRelic::Agent.config[LABELS_ENABLED_KEY]
342
+
343
+ downcased_exclusions = NewRelic::Agent.config[:'application_logging.forwarding.labels.exclude'].map(&:downcase)
344
+ log_labels = {}
345
+
346
+ NewRelic::Agent.config.parsed_labels.each do |parsed_label|
347
+ next if downcased_exclusions.include?(parsed_label['label_type'].downcase)
348
+
349
+ # labels are referred to as tags in the UI, so prefix the
350
+ # label-related attributes with 'tags.*'
351
+ log_labels["tags.#{parsed_label['label_type']}"] = parsed_label['label_value']
352
+ end
353
+
354
+ log_labels
355
+ end
330
356
  end
331
357
  end
332
358
  end
@@ -455,6 +455,8 @@ module NewRelic
455
455
  end
456
456
 
457
457
  def handle_error_response(response, endpoint)
458
+ NewRelic::Agent.agent&.health_check&.update_status(NewRelic::Agent::HealthCheck::HTTP_ERROR, [response.code, endpoint])
459
+
458
460
  case response
459
461
  when Net::HTTPRequestTimeOut,
460
462
  Net::HTTPTooManyRequests,
@@ -637,9 +639,13 @@ module NewRelic
637
639
  def send_request(opts)
638
640
  request = prep_request(opts)
639
641
  response = relay_request(request, opts)
640
- return response if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPAccepted)
641
642
 
642
- handle_error_response(response, opts[:endpoint])
643
+ if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPAccepted)
644
+ NewRelic::Agent.agent&.health_check&.update_status(NewRelic::Agent::HealthCheck::HEALTHY)
645
+ response
646
+ else
647
+ handle_error_response(response, opts[:endpoint])
648
+ end
643
649
  end
644
650
 
645
651
  def log_response(response)
@@ -52,6 +52,8 @@ module NewRelic
52
52
  DATASTORE_CATEGORY = 'datastore'
53
53
  CLIENT = 'client'
54
54
 
55
+ DB_STATEMENT_MAX_BYTES = 4096
56
+
55
57
  # Builds a Hash of error attributes as well as the Span ID when
56
58
  # an error is present. Otherwise, returns nil when no error present.
57
59
  def error_attributes(segment)
@@ -114,9 +116,9 @@ module NewRelic
114
116
  agent_attributes[DB_SYSTEM_KEY] = segment.product if allowed?(DB_SYSTEM_KEY)
115
117
 
116
118
  if segment.sql_statement && allowed?(DB_STATEMENT_KEY)
117
- agent_attributes[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql, 2000)
119
+ agent_attributes[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql, DB_STATEMENT_MAX_BYTES)
118
120
  elsif segment.nosql_statement && allowed?(DB_STATEMENT_KEY)
119
- agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, 2000)
121
+ agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, DB_STATEMENT_MAX_BYTES)
120
122
  end
121
123
 
122
124
  [intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
@@ -125,7 +125,16 @@ module NewRelic
125
125
 
126
126
  # Returns [filename, method, line number]
127
127
  def parse_backtrace_frame(frame)
128
- frame =~ /([^:]*)(\:(\d+))?\:in `(.*)'/
128
+ # TODO: OLD RUBIES - Ruby 3.3
129
+ # The (?:`|') non-capturing group can be removed when the agent
130
+ # drops support for Ruby 3.3
131
+ # This group is used to capture the pre-Ruby 3.4.0 backtrace syntax.
132
+ # Example frame:
133
+ # Ruby 3.3.0 and below
134
+ # "irb.rb:69:in `catch'"
135
+ # Ruby 3.4.0+
136
+ # "irb.rb:69:in 'Kernel#catch'"
137
+ frame =~ /([^:]*)(\:(\d+))?\:in (?:`|')(.*)'/
129
138
  [$1, $4, $3] # sic
130
139
  end
131
140
  end
@@ -15,6 +15,7 @@ module NewRelic
15
15
  PRODUCE = 'Produce'.freeze
16
16
  QUEUE = 'Queue'.freeze
17
17
  PURGE = 'Purge'.freeze
18
+ STREAM = 'Stream'.freeze
18
19
  TEMP = 'Temp'.freeze
19
20
  TOPIC = 'Topic'.freeze
20
21
  UNKNOWN = 'Unknown'.freeze
@@ -22,6 +23,7 @@ module NewRelic
22
23
  DESTINATION_TYPES = [
23
24
  :exchange,
24
25
  :queue,
26
+ :stream,
25
27
  :topic,
26
28
  :temporary_queue,
27
29
  :temporary_topic,
@@ -37,6 +39,7 @@ module NewRelic
37
39
  TYPES = {
38
40
  exchange: EXCHANGE,
39
41
  temporary_queue: QUEUE,
42
+ stream: STREAM,
40
43
  queue: QUEUE,
41
44
  temporary_topic: TOPIC,
42
45
  topic: TOPIC,
@@ -25,7 +25,7 @@ module NewRelic
25
25
  segment.parent = parent || thread_starting_span || current_segment
26
26
  set_current_segment(segment)
27
27
  if @segments.length < segment_limit
28
- @segments << segment
28
+ @segment_lock.synchronize { @segments << segment }
29
29
  else
30
30
  segment.record_on_finish = true
31
31
  ::NewRelic::Agent.logger.debug("Segment limit of #{segment_limit} reached, ceasing collection.")
@@ -42,8 +42,7 @@ module NewRelic
42
42
  def thread_starting_span
43
43
  # if the previous current segment was in another thread, use the thread local parent
44
44
  if ThreadLocalStorage[:newrelic_thread_span_parent] &&
45
- current_segment &&
46
- current_segment.starting_segment_key != NewRelic::Agent::Tracer.current_segment_key
45
+ current_segment&.starting_segment_key != NewRelic::Agent::Tracer.current_segment_key
47
46
 
48
47
  ThreadLocalStorage[:newrelic_thread_span_parent]
49
48
  end
@@ -51,7 +50,7 @@ module NewRelic
51
50
 
52
51
  def segment_complete(segment)
53
52
  # if parent was in another thread, remove the current_segment entry for this thread
54
- if segment.parent && segment.parent.starting_segment_key != NewRelic::Agent::Tracer.current_segment_key
53
+ if segment.parent&.starting_segment_key != NewRelic::Agent::Tracer.current_segment_key
55
54
  remove_current_segment_by_thread_id(NewRelic::Agent::Tracer.current_segment_key)
56
55
  else
57
56
  set_current_segment(segment.parent)
@@ -65,7 +64,7 @@ module NewRelic
65
64
  private
66
65
 
67
66
  def finalize_segments
68
- segments.each { |s| s.finalize }
67
+ @segment_lock.synchronize { segments.each { |s| s&.finalize } }
69
68
  end
70
69
 
71
70
  WEB_TRANSACTION_TOTAL_TIME = 'WebTransactionTotalTime'.freeze
@@ -215,6 +215,7 @@ module NewRelic
215
215
  @nesting_max_depth = 0
216
216
  @current_segment_by_thread = {}
217
217
  @current_segment_lock = Mutex.new
218
+ @segment_lock = Mutex.new
218
219
  @segments = []
219
220
 
220
221
  self.default_name = options[:transaction_name]
@@ -437,7 +438,7 @@ module NewRelic
437
438
  end
438
439
 
439
440
  def initial_segment
440
- segments.first
441
+ segments&.first
441
442
  end
442
443
 
443
444
  def finished?
@@ -85,17 +85,27 @@ module NewRelic
85
85
  end
86
86
 
87
87
  def append_vendor_info(collector_hash)
88
+ threads = []
89
+ complete = false
90
+
88
91
  VENDORS.each_pair do |klass, config_option|
89
92
  next unless Agent.config[config_option]
90
93
 
91
- vendor = klass.new
94
+ threads << Thread.new do
95
+ vendor = klass.new
96
+
97
+ if vendor.detect
98
+ collector_hash[:vendors] ||= {}
99
+ collector_hash[:vendors][vendor.vendor_name.to_sym] = vendor.metadata
92
100
 
93
- if vendor.detect
94
- collector_hash[:vendors] ||= {}
95
- collector_hash[:vendors][vendor.vendor_name.to_sym] = vendor.metadata
96
- break
101
+ complete = true
102
+ end
97
103
  end
98
104
  end
105
+
106
+ while complete == false && threads.any?(&:alive?)
107
+ sleep 0.01
108
+ end
99
109
  end
100
110
 
101
111
  def append_docker_info(collector_hash)
@@ -132,8 +132,8 @@ module NewRelic
132
132
  def agent # :nodoc:
133
133
  return @agent if @agent
134
134
 
135
- NewRelic::Agent.logger.warn("Agent unavailable as it hasn't been started.")
136
- NewRelic::Agent.logger.warn(caller.join("\n"))
135
+ NewRelic::Agent.logger.debug("Agent unavailable as it hasn't been started.")
136
+ NewRelic::Agent.logger.debug(caller.join("\n"))
137
137
  nil
138
138
  end
139
139
 
@@ -9,11 +9,7 @@ module NewRelic
9
9
  module Frameworks
10
10
  class Rails4 < NewRelic::Control::Frameworks::Rails3
11
11
  def rails_gem_list
12
- if Bundler.rubygems.respond_to?(:installed_specs)
13
- Bundler.rubygems.installed_specs.map { |gem| "#{gem.name} (#{gem.version})" }
14
- else
15
- Bundler.rubygems.all_specs.map { |gem| "#{gem.name} (#{gem.version})" }
16
- end
12
+ NewRelic::Helper.rubygems_specs.map { |gem| "#{gem.name} (#{gem.version})" }
17
13
  end
18
14
 
19
15
  def append_plugin_list
@@ -74,6 +74,7 @@ module NewRelic
74
74
  NewRelic::Agent.agent = NewRelic::Agent::Agent.instance
75
75
  init_instrumentation
76
76
  init_security_agent
77
+ report_agent_version_metric
77
78
  end
78
79
 
79
80
  def determine_env(options)
@@ -171,6 +172,10 @@ module NewRelic
171
172
  def stdout
172
173
  STDOUT
173
174
  end
175
+
176
+ def report_agent_version_metric
177
+ NewRelic::Agent.record_metric_once("Supportability/AgentVersion/newrelic_rpm/#{NewRelic::VERSION::STRING}")
178
+ end
174
179
  end
175
180
  include InstanceMethods
176
181
  end
@@ -25,11 +25,9 @@ module DependencyDetection
25
25
 
26
26
  def detect!
27
27
  @items.each do |item|
28
- if item.dependencies_satisfied?
29
- item.execute
30
- else
31
- item.configure_as_unsatisfied unless item.disabled_configured?
32
- end
28
+ next if item.executed || item.disabled_configured?
29
+
30
+ item.dependencies_satisfied? ? item.execute : item.configure_as_unsatisfied
33
31
  end
34
32
  end
35
33
 
@@ -65,6 +63,13 @@ module DependencyDetection
65
63
  end
66
64
 
67
65
  def configure_as_unsatisfied
66
+ # TODO: currently using :unsatisfied for Padrino will clobber the value
67
+ # already set for Sinatra, so skip Padrino and circle back with a
68
+ # new Padrino specific solution in the future.
69
+ #
70
+ # https://github.com/newrelic/newrelic-ruby-agent/issues/2912
71
+ return if name == :padrino
72
+
68
73
  NewRelic::Agent.config.instance_variable_get(:@cache)[config_key] = :unsatisfied
69
74
  end
70
75
 
@@ -139,8 +144,6 @@ module DependencyDetection
139
144
  !(disabled_configured? || deprecated_disabled_configured?)
140
145
  end
141
146
 
142
- # TODO: MAJOR VERSION
143
- # will only return true if a disabled key is found and is truthy
144
147
  def deprecated_disabled_configured?
145
148
  return false if self.name.nil?
146
149
 
@@ -148,12 +151,7 @@ module DependencyDetection
148
151
  return false unless ::NewRelic::Agent.config[key] == true
149
152
 
150
153
  ::NewRelic::Agent.logger.debug("Not installing #{self.name} instrumentation because of configuration #{key}")
151
- ::NewRelic::Agent.logger.debug( \
152
- "[DEPRECATED] configuration #{key} for #{self.name} will be removed in the next major release. " \
153
- "Use `#{config_key}` with one of `#{VALID_CONFIG_VALUES.map(&:to_s).inspect}`"
154
- )
155
-
156
- return true
154
+ true
157
155
  end
158
156
 
159
157
  def config_key
@@ -44,11 +44,7 @@ module NewRelic
44
44
  ####################################
45
45
  report_on('Gems') do
46
46
  begin
47
- if Bundler.rubygems.respond_to?(:installed_specs)
48
- Bundler.rubygems.installed_specs.map { |gem| "#{gem.name}(#{gem.version})" }
49
- else
50
- Bundler.rubygems.all_specs.map { |gem| "#{gem.name}(#{gem.version})" }
51
- end
47
+ NewRelic::Helper.rubygems_specs.map { |gem| "#{gem.name}(#{gem.version})" }
52
48
  rescue
53
49
  # There are certain rubygem, bundler, rails combinations (e.g. gem
54
50
  # 1.6.2, rails 2.3, bundler 1.2.3) where the code above throws an error
@@ -82,5 +82,20 @@ module NewRelic
82
82
  File.exist?(executable_path) && File.file?(executable_path) && File.executable?(executable_path)
83
83
  end
84
84
  end
85
+
86
+ # Bundler version 2.5.12 deprecated all_specs and added installed_specs.
87
+ # To support newer Bundler versions, try to use installed_specs first,
88
+ # then fall back to all_specs.
89
+ # All callers expect this to be an array, so return an array if Bundler isn't defined
90
+ # @api private
91
+ def rubygems_specs
92
+ return [] unless defined?(Bundler)
93
+
94
+ if Bundler.rubygems.respond_to?(:installed_specs)
95
+ Bundler.rubygems.installed_specs
96
+ else
97
+ Bundler.rubygems.all_specs
98
+ end
99
+ end
85
100
  end
86
101
  end
@@ -90,11 +90,7 @@ module NewRelic
90
90
  def bundled_gem?(gem_name)
91
91
  return false unless defined?(Bundler)
92
92
 
93
- if Bundler.rubygems.respond_to?(:installed_specs)
94
- Bundler.rubygems.installed_specs.map(&:name).include?(gem_name)
95
- else
96
- Bundler.rubygems.all_specs.map(&:name).include?(gem_name)
97
- end
93
+ NewRelic::Helper.rubygems_specs.map(&:name).include?(gem_name)
98
94
  rescue => e
99
95
  ::NewRelic::Agent.logger.info("Could not determine if third party #{gem_name} gem is installed", e)
100
96
  false
@@ -6,7 +6,7 @@
6
6
  module NewRelic
7
7
  module VERSION # :nodoc:
8
8
  MAJOR = 9
9
- MINOR = 14
9
+ MINOR = 18
10
10
  TINY = 0
11
11
 
12
12
  STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
@@ -79,7 +79,7 @@ module Sequel
79
79
 
80
80
  THREAD_SAFE_CONNECTION_POOL_CLASSES = [
81
81
  (defined?(::Sequel::ThreadedConnectionPool) && ::Sequel::ThreadedConnectionPool),
82
- (defined?(::Sequel::TimedQueueConnectionPool) && RUBY_VERSION >= '3.4' && ::Sequel::TimedQueueConnectionPool)
82
+ (defined?(::Sequel::TimedQueueConnectionPool) && RUBY_VERSION >= '3.2' && ::Sequel::TimedQueueConnectionPool)
83
83
  ].compact.freeze
84
84
 
85
85
  def explainer_for(sql)
@@ -141,6 +141,8 @@ module NewRelicYML
141
141
  description.gsub!(/<InlinePopover type="(.*)" \/>/, '\1')
142
142
  # remove hyperlinks
143
143
  description.gsub!(/\[([^\]]+)\]\([^\)]+\)/, '\1')
144
+ # delete lines with code fences including the language
145
+ description.gsub!(/```[a-zA-Z0-9_]*\n(.*?)```/m, '\1')
144
146
  # remove single pairs of backticks
145
147
  description.gsub!(/`([^`]+)`/, '\1')
146
148
  # removed href links
@@ -153,8 +155,8 @@ module NewRelicYML
153
155
  # remove leading and trailing whitespace
154
156
  description.strip!
155
157
  # wrap text after 80 characters, assuming we're at one tabstop's (two
156
- # spaces') level of indentation already
157
- description.gsub!(/(.{1,78})(\s+|\Z)/, "\\1\n")
158
+ # spaces') level of indentation already, keep leading whitespace
159
+ description.gsub!(/(.{1,78})(\s|\Z)/, "\\1\n")
158
160
  # add hashtags to lines
159
161
  description = description.split("\n").map { |line| " # #{line}" }.join("\n")
160
162