newrelic_rpm 8.13.1 → 8.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.rubocop.yml +130 -1
  4. data/.rubocop_todo.yml +3 -0
  5. data/CHANGELOG.md +3284 -3148
  6. data/CONTRIBUTING.md +1 -2
  7. data/README.md +2 -1
  8. data/init.rb +1 -1
  9. data/lib/new_relic/agent/agent.rb +14 -466
  10. data/lib/new_relic/agent/agent_helpers/connect.rb +227 -0
  11. data/lib/new_relic/agent/agent_helpers/harvest.rb +153 -0
  12. data/lib/new_relic/agent/agent_helpers/shutdown.rb +72 -0
  13. data/lib/new_relic/agent/agent_helpers/special_startup.rb +75 -0
  14. data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +167 -0
  15. data/lib/new_relic/agent/agent_helpers/startup.rb +202 -0
  16. data/lib/new_relic/agent/agent_helpers/transmit.rb +76 -0
  17. data/lib/new_relic/agent/configuration/default_source.rb +47 -9
  18. data/lib/new_relic/agent/datastores.rb +2 -2
  19. data/lib/new_relic/agent/event_loop.rb +1 -1
  20. data/lib/new_relic/agent/guid_generator.rb +11 -2
  21. data/lib/new_relic/agent/heap.rb +1 -1
  22. data/lib/new_relic/agent/instrumentation/active_job.rb +7 -7
  23. data/lib/new_relic/agent/instrumentation/active_merchant.rb +2 -2
  24. data/lib/new_relic/agent/instrumentation/active_record.rb +9 -9
  25. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +24 -24
  26. data/lib/new_relic/agent/instrumentation/active_storage.rb +2 -2
  27. data/lib/new_relic/agent/instrumentation/active_support.rb +12 -0
  28. data/lib/new_relic/agent/instrumentation/active_support_logger.rb +3 -3
  29. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +2 -2
  30. data/lib/new_relic/agent/instrumentation/authlogic.rb +2 -2
  31. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +3 -3
  32. data/lib/new_relic/agent/instrumentation/bunny.rb +4 -4
  33. data/lib/new_relic/agent/instrumentation/concurrent_ruby/chain.rb +36 -0
  34. data/lib/new_relic/agent/instrumentation/concurrent_ruby/instrumentation.rb +21 -0
  35. data/lib/new_relic/agent/instrumentation/concurrent_ruby/prepend.rb +27 -0
  36. data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +31 -0
  37. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -1
  38. data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +1 -1
  39. data/lib/new_relic/agent/instrumentation/curb.rb +6 -6
  40. data/lib/new_relic/agent/instrumentation/custom_events_subscriber.rb +37 -0
  41. data/lib/new_relic/agent/instrumentation/data_mapper.rb +50 -50
  42. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +5 -5
  43. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +5 -5
  44. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +1 -1
  45. data/lib/new_relic/agent/instrumentation/excon.rb +9 -9
  46. data/lib/new_relic/agent/instrumentation/grape.rb +8 -8
  47. data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +1 -1
  48. data/lib/new_relic/agent/instrumentation/grpc_client.rb +3 -3
  49. data/lib/new_relic/agent/instrumentation/grpc_server.rb +4 -4
  50. data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +1 -1
  51. data/lib/new_relic/agent/instrumentation/httpclient.rb +2 -2
  52. data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +1 -1
  53. data/lib/new_relic/agent/instrumentation/httprb.rb +3 -3
  54. data/lib/new_relic/agent/instrumentation/logger.rb +3 -3
  55. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +3 -3
  56. data/lib/new_relic/agent/instrumentation/memcache.rb +16 -16
  57. data/lib/new_relic/agent/instrumentation/mongo.rb +1 -1
  58. data/lib/new_relic/agent/instrumentation/net_http.rb +6 -6
  59. data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
  60. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +5 -5
  61. data/lib/new_relic/agent/instrumentation/rack.rb +14 -14
  62. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +5 -5
  63. data/lib/new_relic/agent/instrumentation/rails_middleware.rb +3 -3
  64. data/lib/new_relic/agent/instrumentation/rails_notifications/action_cable.rb +6 -6
  65. data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +2 -2
  66. data/lib/new_relic/agent/instrumentation/rails_notifications/action_view.rb +5 -3
  67. data/lib/new_relic/agent/instrumentation/rails_notifications/custom_events.rb +30 -0
  68. data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +4 -4
  69. data/lib/new_relic/agent/instrumentation/rake.rb +7 -7
  70. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +29 -8
  71. data/lib/new_relic/agent/instrumentation/redis.rb +4 -4
  72. data/lib/new_relic/agent/instrumentation/resque.rb +9 -9
  73. data/lib/new_relic/agent/instrumentation/sequel.rb +2 -2
  74. data/lib/new_relic/agent/instrumentation/sidekiq.rb +3 -3
  75. data/lib/new_relic/agent/instrumentation/sinatra.rb +7 -7
  76. data/lib/new_relic/agent/instrumentation/sunspot.rb +4 -4
  77. data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +5 -1
  78. data/lib/new_relic/agent/instrumentation/thread.rb +3 -3
  79. data/lib/new_relic/agent/instrumentation/tilt.rb +3 -3
  80. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +2 -2
  81. data/lib/new_relic/agent/instrumentation/typhoeus.rb +1 -1
  82. data/lib/new_relic/agent/javascript_instrumentor.rb +2 -2
  83. data/lib/new_relic/agent/method_tracer_helpers.rb +6 -11
  84. data/lib/new_relic/agent/range_extensions.rb +2 -2
  85. data/lib/new_relic/agent/tracer.rb +8 -4
  86. data/lib/new_relic/agent/transaction/abstract_segment.rb +2 -2
  87. data/lib/new_relic/agent/transaction/segment.rb +6 -0
  88. data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +1 -1
  89. data/lib/new_relic/agent/transaction.rb +3 -3
  90. data/lib/new_relic/agent.rb +7 -0
  91. data/lib/new_relic/control/instance_methods.rb +6 -2
  92. data/lib/new_relic/helper.rb +1 -1
  93. data/lib/new_relic/recipes/helpers/send_deployment.rb +2 -1
  94. data/lib/new_relic/traced_thread.rb +5 -1
  95. data/lib/new_relic/version.rb +2 -2
  96. data/lib/newrelic_rpm.rb +13 -2
  97. data/lib/sequel/extensions/newrelic_instrumentation.rb +1 -1
  98. data/lib/sequel/plugins/newrelic_instrumentation.rb +1 -1
  99. data/newrelic.yml +23 -5
  100. data/test/agent_helper.rb +7 -7
  101. metadata +16 -6
  102. data/lib/new_relic/agent/agent/shutdown.rb +0 -35
  103. data/lib/new_relic/agent/agent/special_startup.rb +0 -72
  104. data/lib/new_relic/agent/agent/start_worker_thread.rb +0 -163
  105. data/lib/new_relic/agent/agent/startup.rb +0 -197
@@ -11,19 +11,19 @@ DependencyDetection.defer do
11
11
  named :rake_instrumentation
12
12
  configure_with :rake
13
13
 
14
- depends_on { defined?(::Rake) && defined?(::Rake::VERSION) }
15
- depends_on { Gem::Version.new(::Rake::VERSION) >= Gem::Version.new("10.0.0") }
16
- depends_on { ::NewRelic::Agent.config[:'rake.tasks'].any? }
17
- depends_on { ::NewRelic::Agent::Instrumentation::Rake.safe_from_third_party_gem? }
14
+ depends_on { defined?(Rake) && defined?(Rake::VERSION) }
15
+ depends_on { Gem::Version.new(Rake::VERSION) >= Gem::Version.new("10.0.0") }
16
+ depends_on { NewRelic::Agent.config[:'rake.tasks'].any? }
17
+ depends_on { NewRelic::Agent::Instrumentation::Rake.safe_from_third_party_gem? }
18
18
 
19
19
  executes do
20
- ::NewRelic::Agent.logger.info("Installing Rake instrumentation")
21
- ::NewRelic::Agent.logger.debug("Instrumenting Rake tasks: #{::NewRelic::Agent.config[:'rake.tasks']}")
20
+ NewRelic::Agent.logger.info("Installing Rake instrumentation")
21
+ NewRelic::Agent.logger.debug("Instrumenting Rake tasks: #{NewRelic::Agent.config[:'rake.tasks']}")
22
22
  end
23
23
 
24
24
  executes do
25
25
  if use_prepend?
26
- prepend_instrument ::Rake::Task, NewRelic::Agent::Instrumentation::Rake::Prepend
26
+ prepend_instrument Rake::Task, NewRelic::Agent::Instrumentation::Rake::Prepend
27
27
  else
28
28
  chain_instrument NewRelic::Agent::Instrumentation::Rake::Chain
29
29
  end
@@ -27,10 +27,17 @@ module NewRelic::Agent::Instrumentation
27
27
 
28
28
  # Used for Redis 5.x+
29
29
  def call_pipelined_with_tracing(pipeline)
30
+ db = begin
31
+ _nr_redis_client_config.db
32
+ rescue StandardError => e
33
+ NewRelic::Agent.logger.error("Failed to determine configured Redis db value: #{e.class} - #{e.message}")
34
+ nil
35
+ end
36
+
30
37
  operation = pipeline.flatten.include?('MULTI') ? Constants::MULTI_OPERATION : Constants::PIPELINE_OPERATION
31
38
  statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline)
32
39
 
33
- with_tracing(operation, statement: statement, database: client.config.db) { yield }
40
+ with_tracing(operation, statement: statement, database: db) { yield }
34
41
  end
35
42
 
36
43
  private
@@ -47,26 +54,40 @@ module NewRelic::Agent::Instrumentation
47
54
  segment.notice_nosql_statement(statement) if statement
48
55
  NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
49
56
  ensure
50
- segment.finish if segment
57
+ ::NewRelic::Agent::Transaction::Segment.finish(segment)
51
58
  end
52
59
  end
53
60
 
54
61
  def _nr_hostname
55
- _nr_client.path ? Constants::LOCALHOST : _nr_client.host
62
+ _nr_redis_client_config.path ? Constants::LOCALHOST : _nr_redis_client_config.host
56
63
  rescue => e
57
- NewRelic::Agent.logger.debug("Failed to retrieve Redis host: #{e}")
64
+ NewRelic::Agent.logger.debug("Failed to retrieve Redis host: #{e.class} - #{e.message}")
58
65
  Constants::UNKNOWN
59
66
  end
60
67
 
61
68
  def _nr_port_path_or_id
62
- _nr_client.path || _nr_client.port
69
+ _nr_redis_client_config.path || _nr_redis_client_config.port
63
70
  rescue => e
64
- NewRelic::Agent.logger.debug("Failed to retrieve Redis port_path_or_id: #{e}")
71
+ NewRelic::Agent.logger.debug("Failed to retrieve Redis port_path_or_id: #{e.class} - #{e.message}")
65
72
  Constants::UNKNOWN
66
73
  end
67
74
 
68
- def _nr_client
69
- @nr_client ||= self.is_a?(::Redis::Client) ? self : client.config
75
+ def _nr_redis_client_config
76
+ @nr_config ||= begin
77
+ # redis gem
78
+ config = if defined?(::Redis::Client) && self.is_a?(::Redis::Client)
79
+ self
80
+ # redis-client gem v0.11+ (self is a RedisClient::Middlewares)
81
+ elsif respond_to?(:client)
82
+ client && client.config
83
+ # redis-client gem <0.11 (self is a RedisClient::Middlewares)
84
+ elsif defined?(::RedisClient)
85
+ ::RedisClient.config if ::RedisClient.respond_to?(:config)
86
+ end
87
+ raise 'Unable to locate the underlying Redis client configuration.' unless config
88
+
89
+ config
90
+ end
70
91
  end
71
92
  end
72
93
  end
@@ -17,11 +17,11 @@ DependencyDetection.defer do
17
17
  configure_with :redis
18
18
 
19
19
  depends_on do
20
- defined?(::Redis) && defined?(::Redis::VERSION)
20
+ defined?(Redis) && defined?(Redis::VERSION)
21
21
  end
22
22
 
23
23
  conflicts_with_prepend do
24
- defined?(::PrometheusExporter)
24
+ defined?(PrometheusExporter)
25
25
  end
26
26
 
27
27
  depends_on do
@@ -32,11 +32,11 @@ DependencyDetection.defer do
32
32
  executes do
33
33
  NewRelic::Agent.logger.info('Installing Redis Instrumentation')
34
34
  if NewRelic::Agent::Instrumentation::Redis::Constants::HAS_REDIS_CLIENT
35
- ::RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware)
35
+ RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware)
36
36
  end
37
37
 
38
38
  if use_prepend?
39
- prepend_instrument ::Redis::Client, NewRelic::Agent::Instrumentation::Redis::Prepend
39
+ prepend_instrument Redis::Client, NewRelic::Agent::Instrumentation::Redis::Prepend
40
40
  else
41
41
  chain_instrument NewRelic::Agent::Instrumentation::Redis::Chain
42
42
  end
@@ -10,21 +10,21 @@ DependencyDetection.defer do
10
10
  @name = :resque
11
11
 
12
12
  depends_on do
13
- defined?(::Resque::Job) && !NewRelic::Agent.config[:disable_resque]
13
+ defined?(Resque::Job) && !NewRelic::Agent.config[:disable_resque]
14
14
  end
15
15
 
16
16
  # Airbrake uses method chaining on Resque::Job on versions < 11.0.3
17
17
  conflicts_with_prepend do
18
- defined?(::Airbrake) && defined?(::Airbrake::AIRBRAKE_VERSION) && ::Gem::Version.create(::Airbrake::AIRBRAKE_VERSION) < ::Gem::Version.create('11.0.3')
18
+ defined?(Airbrake) && defined?(Airbrake::AIRBRAKE_VERSION) && Gem::Version.create(Airbrake::AIRBRAKE_VERSION) < Gem::Version.create('11.0.3')
19
19
  end
20
20
 
21
21
  executes do
22
- ::NewRelic::Agent.logger.info('Installing Resque instrumentation')
22
+ NewRelic::Agent.logger.info('Installing Resque instrumentation')
23
23
  end
24
24
 
25
25
  executes do
26
26
  if NewRelic::Agent.config[:'resque.use_ruby_dns'] && NewRelic::Agent.config[:dispatcher] == :resque
27
- ::NewRelic::Agent.logger.info('Requiring resolv-replace')
27
+ NewRelic::Agent.logger.info('Requiring resolv-replace')
28
28
  require 'resolv'
29
29
  require 'resolv-replace'
30
30
  end
@@ -32,30 +32,30 @@ DependencyDetection.defer do
32
32
 
33
33
  executes do
34
34
  if use_prepend?
35
- prepend_instrument ::Resque::Job, NewRelic::Agent::Instrumentation::Resque::Prepend
35
+ prepend_instrument Resque::Job, NewRelic::Agent::Instrumentation::Resque::Prepend
36
36
  else
37
37
  chain_instrument NewRelic::Agent::Instrumentation::Resque::Chain
38
38
  end
39
39
 
40
40
  if NewRelic::Agent::Instrumentation::Resque::Helper.resque_fork_per_job?
41
- ::Resque.before_first_fork do
41
+ Resque.before_first_fork do
42
42
  NewRelic::Agent.manual_start(:dispatcher => :resque,
43
43
  :sync_startup => true,
44
44
  :start_channel_listener => true)
45
45
  end
46
46
 
47
- ::Resque.before_fork do |job|
47
+ Resque.before_fork do |job|
48
48
  NewRelic::Agent.register_report_channel(job.object_id)
49
49
  end
50
50
 
51
- ::Resque.after_fork do |job|
51
+ Resque.after_fork do |job|
52
52
  # Only suppress reporting Instance/Busy for forked children
53
53
  # Traced errors UI relies on having the parent process report that metric
54
54
  NewRelic::Agent.after_fork(:report_to_channel => job.object_id,
55
55
  :report_instance_busy => false)
56
56
  end
57
57
  else
58
- ::Resque.before_first_fork do
58
+ Resque.before_first_fork do
59
59
  NewRelic::Agent.manual_start(:dispatcher => :resque,
60
60
  :sync_startup => true,
61
61
  :start_channel_listener => false)
@@ -7,7 +7,7 @@ DependencyDetection.defer do
7
7
  @name = :sequel
8
8
 
9
9
  depends_on do
10
- defined?(::Sequel)
10
+ defined?(Sequel)
11
11
  end
12
12
 
13
13
  depends_on do
@@ -24,7 +24,7 @@ DependencyDetection.defer do
24
24
  executes do
25
25
  if supported_sequel_version?
26
26
 
27
- ::NewRelic::Agent.logger.info('Installing Sequel instrumentation')
27
+ NewRelic::Agent.logger.info('Installing Sequel instrumentation')
28
28
 
29
29
  if Sequel::Database.respond_to?(:extension)
30
30
  Sequel::Database.extension(:newrelic_instrumentation)
@@ -9,11 +9,11 @@ DependencyDetection.defer do
9
9
  @name = :sidekiq
10
10
 
11
11
  depends_on do
12
- defined?(::Sidekiq) && !NewRelic::Agent.config[:disable_sidekiq]
12
+ defined?(Sidekiq) && !NewRelic::Agent.config[:disable_sidekiq]
13
13
  end
14
14
 
15
15
  executes do
16
- ::NewRelic::Agent.logger.info('Installing Sidekiq instrumentation')
16
+ NewRelic::Agent.logger.info('Installing Sidekiq instrumentation')
17
17
  end
18
18
 
19
19
  executes do
@@ -46,7 +46,7 @@ DependencyDetection.defer do
46
46
  'They will stop being monitored in version 9.0.0. ' \
47
47
  'Please upgrade your Sidekiq version to continue receiving full support. '
48
48
 
49
- ::NewRelic::Agent.logger.log_once(
49
+ NewRelic::Agent.logger.log_once(
50
50
  :warn,
51
51
  :deprecated_sidekiq_version,
52
52
  deprecation_msg
@@ -11,24 +11,24 @@ require_relative 'sinatra/prepend'
11
11
  DependencyDetection.defer do
12
12
  named :sinatra
13
13
 
14
- depends_on { defined?(::Sinatra) && defined?(::Sinatra::Base) }
14
+ depends_on { defined?(Sinatra) && defined?(Sinatra::Base) }
15
15
  depends_on { Sinatra::Base.private_method_defined?(:dispatch!) }
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
19
  executes do
20
- ::NewRelic::Agent.logger.info('Installing Sinatra instrumentation')
20
+ NewRelic::Agent.logger.info('Installing Sinatra instrumentation')
21
21
  end
22
22
 
23
23
  executes do
24
24
  if use_prepend?
25
- prepend_instrument ::Sinatra::Base, NewRelic::Agent::Instrumentation::Sinatra::Prepend
25
+ prepend_instrument Sinatra::Base, NewRelic::Agent::Instrumentation::Sinatra::Prepend
26
26
  else
27
27
  chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Chain
28
28
  end
29
29
 
30
- ::Sinatra::Base.class_eval { register ::NewRelic::Agent::Instrumentation::Sinatra::Ignorer }
31
- ::Sinatra.module_eval { register NewRelic::Agent::Instrumentation::Sinatra::Ignorer }
30
+ Sinatra::Base.class_eval { register NewRelic::Agent::Instrumentation::Sinatra::Ignorer }
31
+ Sinatra.module_eval { register NewRelic::Agent::Instrumentation::Sinatra::Ignorer }
32
32
  end
33
33
 
34
34
  executes do
@@ -37,7 +37,7 @@ DependencyDetection.defer do
37
37
  require 'new_relic/rack/agent_hooks'
38
38
  require 'new_relic/rack/browser_monitoring'
39
39
  if use_prepend?
40
- prepend_instrument ::Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend
40
+ prepend_instrument Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend
41
41
  else
42
42
  chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain
43
43
  end
@@ -49,7 +49,7 @@ DependencyDetection.defer do
49
49
  deprecation_msg = 'The Ruby Agent is dropping support for Sinatra versions below 2.0.0 ' \
50
50
  'in version 9.0.0. Please upgrade your Sinatra version to continue receiving full compatibility. ' \
51
51
 
52
- ::NewRelic::Agent.logger.log_once(
52
+ NewRelic::Agent.logger.log_once(
53
53
  :warn,
54
54
  :deprecated_sinatra_version,
55
55
  deprecation_msg
@@ -6,15 +6,15 @@ DependencyDetection.defer do
6
6
  @name = :sunspot
7
7
 
8
8
  depends_on do
9
- defined?(::Sunspot)
9
+ defined?(Sunspot)
10
10
  end
11
11
 
12
12
  executes do
13
- ::NewRelic::Agent.logger.info('Installing Rails Sunspot instrumentation')
13
+ NewRelic::Agent.logger.info('Installing Rails Sunspot instrumentation')
14
14
  deprecation_msg = 'The instrumentation for Sunspot is deprecated. ' \
15
15
  'It will be removed in version 9.0.0.'
16
16
 
17
- ::NewRelic::Agent.logger.log_once(
17
+ NewRelic::Agent.logger.log_once(
18
18
  :warn,
19
19
  :deprecated_sunspot,
20
20
  deprecation_msg
@@ -22,7 +22,7 @@ DependencyDetection.defer do
22
22
  end
23
23
 
24
24
  executes do
25
- ::Sunspot.module_eval do
25
+ Sunspot.module_eval do
26
26
  class << self
27
27
  %w[index index!].each do |method|
28
28
  add_method_tracer method, 'SolrClient/Sunspot/index'
@@ -16,7 +16,11 @@ module NewRelic
16
16
  def add_thread_tracing(*args, &block)
17
17
  return block if skip_tracing?
18
18
 
19
- NewRelic::Agent::Tracer.thread_block_with_current_transaction(*args, &block)
19
+ NewRelic::Agent::Tracer.thread_block_with_current_transaction(
20
+ *args,
21
+ segment_name: 'Ruby/Thread',
22
+ &block
23
+ )
20
24
  end
21
25
 
22
26
  def skip_tracing?
@@ -9,12 +9,12 @@ DependencyDetection.defer do
9
9
  named :thread
10
10
 
11
11
  executes do
12
- ::NewRelic::Agent.logger.info('Installing Thread Instrumentation')
12
+ NewRelic::Agent.logger.info('Installing Thread Instrumentation')
13
13
 
14
14
  if use_prepend?
15
- prepend_instrument ::Thread, ::NewRelic::Agent::Instrumentation::MonitoredThread::Prepend
15
+ prepend_instrument Thread, NewRelic::Agent::Instrumentation::MonitoredThread::Prepend
16
16
  else
17
- chain_instrument ::NewRelic::Agent::Instrumentation::MonitoredThread::Chain
17
+ chain_instrument NewRelic::Agent::Instrumentation::MonitoredThread::Chain
18
18
  end
19
19
  end
20
20
  end
@@ -9,15 +9,15 @@ require_relative 'tilt/prepend'
9
9
  DependencyDetection.defer do
10
10
  named :tilt
11
11
 
12
- depends_on { defined?(::Tilt) }
12
+ depends_on { defined?(Tilt) }
13
13
 
14
14
  executes do
15
- ::NewRelic::Agent.logger.info('Installing Tilt instrumentation')
15
+ NewRelic::Agent.logger.info('Installing Tilt instrumentation')
16
16
  end
17
17
 
18
18
  executes do
19
19
  if use_prepend?
20
- prepend_instrument ::Tilt::Template, NewRelic::Agent::Instrumentation::Tilt::Prepend
20
+ prepend_instrument Tilt::Template, NewRelic::Agent::Instrumentation::Tilt::Prepend
21
21
  else
22
22
  chain_instrument NewRelic::Agent::Instrumentation::Tilt::Chain
23
23
  end
@@ -36,7 +36,7 @@ module NewRelic
36
36
  begin
37
37
  yield
38
38
  ensure
39
- segment.finish if segment
39
+ ::NewRelic::Agent::Transaction::Segment.finish(segment)
40
40
  end
41
41
  end
42
42
 
@@ -68,7 +68,7 @@ module NewRelic
68
68
  segment.notice_error(NoticeableError.new(NOTICEABLE_ERROR_CLASS, response_message(request.response)))
69
69
  end
70
70
 
71
- segment.finish if segment
71
+ ::NewRelic::Agent::Transaction::Segment.finish(segment)
72
72
  end
73
73
  request.on_complete.unshift(callback)
74
74
  rescue => e
@@ -18,7 +18,7 @@ DependencyDetection.defer do
18
18
  end
19
19
 
20
20
  executes do
21
- ::NewRelic::Agent.logger.info('Installing Typhoeus instrumentation')
21
+ NewRelic::Agent.logger.info('Installing Typhoeus instrumentation')
22
22
  require 'new_relic/agent/distributed_tracing/cross_app_tracing'
23
23
  require 'new_relic/agent/http_clients/typhoeus_wrappers'
24
24
  end
@@ -141,8 +141,8 @@ module NewRelic
141
141
  start_time_in_seconds = [transaction.start_time, 0.0].max
142
142
  app_time_in_seconds = Process.clock_gettime(Process::CLOCK_REALTIME) - start_time_in_seconds
143
143
 
144
- queue_time_in_millis = (1000.0 * queue_time_in_seconds).round
145
- app_time_in_millis = (1000.0 * app_time_in_seconds).round
144
+ queue_time_in_millis = (queue_time_in_seconds * 1000.0).round
145
+ app_time_in_millis = (app_time_in_seconds * 1000.0).round
146
146
 
147
147
  transaction_name = transaction.best_name || ::NewRelic::Agent::UNKNOWN_METRIC
148
148
 
@@ -17,8 +17,7 @@ module NewRelic
17
17
  extend self
18
18
 
19
19
  def trace_execution_scoped(metric_names, options = NewRelic::EMPTY_HASH) # THREAD_LOCAL_ACCESS
20
- state = NewRelic::Agent::Tracer.state
21
- return yield unless state.is_execution_traced?
20
+ return yield unless NewRelic::Agent::Tracer.state.is_execution_traced?
22
21
 
23
22
  metric_names = Array(metric_names)
24
23
  first_name = metric_names.shift
@@ -29,19 +28,15 @@ module NewRelic
29
28
  unscoped_metrics: metric_names
30
29
  )
31
30
 
32
- if options[:metric] == false
33
- segment.record_metrics = false
34
- end
31
+ segment.record_metrics = false if options[:metric] == false
35
32
 
36
33
  unless !options.key?(:code_information) || options[:code_information].nil? || options[:code_information].empty?
37
34
  segment.code_information = options[:code_information]
38
35
  end
39
36
 
40
- begin
41
- Tracer.capture_segment_error(segment) { yield }
42
- ensure
43
- segment.finish if segment
44
- end
37
+ Tracer.capture_segment_error(segment) { yield }
38
+ ensure
39
+ ::NewRelic::Agent::Transaction::Segment.finish(segment)
45
40
  end
46
41
 
47
42
  def code_information(object, method_name)
@@ -77,7 +72,7 @@ module NewRelic
77
72
  name = Regexp.last_match(1) if object.to_s =~ /^#<Class:(.*)>$/
78
73
  return name if name
79
74
 
80
- raise "Unable to glean a class name from string '#{object}'" unless name
75
+ raise "Unable to glean a class name from string '#{object}'"
81
76
  end
82
77
 
83
78
  # get at the underlying class from the singleton class
@@ -18,8 +18,8 @@ module NewRelic
18
18
  ranges.inject(0) do |memo, other|
19
19
  next memo unless intersects?(range, other)
20
20
 
21
- memo += (range.end < other.end ? range.end : other.end) -
22
- (range.begin > other.begin ? range.begin : other.begin)
21
+ memo += ([range.end, other.end].min) -
22
+ ([range.begin, other.begin].max)
23
23
  end
24
24
  end
25
25
  end
@@ -2,6 +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 'fiber'
5
6
  require 'new_relic/agent/transaction'
6
7
  require 'new_relic/agent/transaction/segment'
7
8
  require 'new_relic/agent/transaction/datastore_segment'
@@ -409,17 +410,20 @@ module NewRelic
409
410
 
410
411
  alias_method :tl_clear, :clear_state
411
412
 
412
- def thread_block_with_current_transaction(*args, &block)
413
+ def thread_block_with_current_transaction(*args, segment_name:, parent: nil, &block)
413
414
  current_txn = ::Thread.current[:newrelic_tracer_state].current_transaction if ::Thread.current[:newrelic_tracer_state] && ::Thread.current[:newrelic_tracer_state].is_execution_traced?
414
415
  proc do
415
416
  begin
416
417
  if current_txn
417
418
  NewRelic::Agent::Tracer.state.current_transaction = current_txn
418
- segment = NewRelic::Agent::Tracer.start_segment(name: "Ruby/Thread/#{::Thread.current.object_id}")
419
+ segment_name += "/Thread#{::Thread.current.object_id}/Fiber#{::Fiber.current.object_id}" if NewRelic::Agent.config[:'thread_ids_enabled']
420
+ segment = NewRelic::Agent::Tracer.start_segment(name: segment_name, parent: parent)
421
+ end
422
+ NewRelic::Agent::Tracer.capture_segment_error(segment) do
423
+ yield(*args)
419
424
  end
420
- yield(*args) if block.respond_to?(:call)
421
425
  ensure
422
- segment.finish if segment
426
+ ::NewRelic::Agent::Transaction::Segment.finish(segment)
423
427
  end
424
428
  end
425
429
  end
@@ -111,8 +111,8 @@ module NewRelic
111
111
  end
112
112
 
113
113
  def merge_timings(timing1, timing2)
114
- [(timing1.first < timing2.first ? timing1.first : timing2.first),
115
- (timing1.last > timing2.last ? timing1.last : timing2.last)]
114
+ [([timing1.first, timing2.first].min),
115
+ ([timing1.last, timing2.last].max)]
116
116
  end
117
117
 
118
118
  # @children_timings is an array of array, with each inner array
@@ -46,6 +46,12 @@ module NewRelic
46
46
  attributes.merge_custom_attributes(p)
47
47
  end
48
48
 
49
+ def self.finish(segment)
50
+ return unless segment
51
+
52
+ segment.finish
53
+ end
54
+
49
55
  private
50
56
 
51
57
  def record_metrics
@@ -72,7 +72,7 @@ module NewRelic
72
72
  # A typical buffer should NOT override this method (although we do for
73
73
  # odd things like dev-mode)
74
74
  def max_capacity
75
- capacity > SINGLE_BUFFER_MAX ? SINGLE_BUFFER_MAX : capacity
75
+ [capacity, SINGLE_BUFFER_MAX].min
76
76
  end
77
77
 
78
78
  # Our default truncation strategy is to keep max_capacity
@@ -168,7 +168,7 @@ module NewRelic
168
168
  :apdex_f
169
169
  when duration <= apdex_t
170
170
  :apdex_s
171
- when duration <= 4 * apdex_t
171
+ when duration <= apdex_t * 4
172
172
  :apdex_t
173
173
  else
174
174
  :apdex_f
@@ -302,7 +302,7 @@ module NewRelic
302
302
  end
303
303
 
304
304
  def priority
305
- @priority ||= (sampled? ? 1.0 + rand : rand).round(NewRelic::PRIORITY_PRECISION)
305
+ @priority ||= (sampled? ? rand + 1.0 : rand).round(NewRelic::PRIORITY_PRECISION)
306
306
  end
307
307
 
308
308
  def referer
@@ -635,7 +635,7 @@ module NewRelic
635
635
  return unless distributed_trace_payload
636
636
 
637
637
  duration = start_time - (distributed_trace_payload.timestamp / 1000.0)
638
- duration < 0 ? 0 : duration
638
+ [duration, 0].max
639
639
  end
640
640
 
641
641
  # The summary metrics recorded by this method all end up with a duration
@@ -109,6 +109,7 @@ module NewRelic
109
109
  @logger = nil
110
110
  @tracer_lock = Mutex.new
111
111
  @tracer_queue = []
112
+ @metrics_already_recorded = Set.new
112
113
 
113
114
  # The singleton Agent instance. Used internally.
114
115
  def agent # :nodoc:
@@ -203,6 +204,12 @@ module NewRelic
203
204
  agent.stats_engine.tl_record_unscoped_metrics(metric_name, value)
204
205
  end
205
206
 
207
+ def record_metric_once(metric_name, value = 0.0)
208
+ return unless @metrics_already_recorded.add?(metric_name)
209
+
210
+ record_metric(metric_name, value)
211
+ end
212
+
206
213
  # Increment a simple counter metric.
207
214
  #
208
215
  # +metric_name+ should follow a slash separated path convention. Application
@@ -64,8 +64,12 @@ module NewRelic
64
64
 
65
65
  # An artifact of earlier implementation, we put both #add_method_tracer and #trace_execution
66
66
  # methods in the module methods.
67
- Module.send(:include, NewRelic::Agent::MethodTracer::ClassMethods)
68
- Module.send(:include, NewRelic::Agent::MethodTracer)
67
+ # Rails applications load the next two lines before any other initializers are run
68
+ unless defined?(Rails::VERSION) && NewRelic::Agent.config[:defer_rails_initialization]
69
+ Module.send(:include, NewRelic::Agent::MethodTracer::ClassMethods)
70
+ Module.send(:include, NewRelic::Agent::MethodTracer)
71
+ end
72
+
69
73
  init_config(options)
70
74
  NewRelic::Agent.agent = NewRelic::Agent::Agent.instance
71
75
  init_instrumentation
@@ -63,7 +63,7 @@ module NewRelic
63
63
  raise NewRelic::CommandRunFailedError.new("Failed to run command '#{command}': #{message}")
64
64
  end
65
65
 
66
- output.chomp
66
+ output.chomp if output
67
67
  end
68
68
 
69
69
  # TODO: Open3 defers the actual execution of a binary to Process.spawn,
@@ -29,7 +29,8 @@ module SendDeployment
29
29
  end
30
30
 
31
31
  def fetch_changelog
32
- has_scm? ? fetch(:newrelic_changelog) : lookup_changelog
32
+ newrelic_changelog = fetch(:newrelic_changelog)
33
+ has_scm? && !newrelic_changelog ? lookup_changelog : newrelic_changelog
33
34
  end
34
35
 
35
36
  def fetch_environment
@@ -29,7 +29,11 @@ module NewRelic
29
29
  def create_traced_block(*args, &block)
30
30
  return block if NewRelic::Agent.config[:'instrumentation.thread.tracing'] # if this is on, don't double trace
31
31
 
32
- NewRelic::Agent::Tracer.thread_block_with_current_transaction(*args, &block)
32
+ NewRelic::Agent::Tracer.thread_block_with_current_transaction(
33
+ *args,
34
+ segment_name: 'Ruby/TracedThread',
35
+ &block
36
+ )
33
37
  end
34
38
  end
35
39
  end
@@ -6,8 +6,8 @@
6
6
  module NewRelic
7
7
  module VERSION # :nodoc:
8
8
  MAJOR = 8
9
- MINOR = 13
10
- TINY = 1
9
+ MINOR = 15
10
+ TINY = 0
11
11
 
12
12
  STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
13
13
  end
data/lib/newrelic_rpm.rb CHANGED
@@ -20,8 +20,19 @@ require 'new_relic/control'
20
20
  if defined?(Rails::VERSION)
21
21
  module NewRelic
22
22
  class Railtie < Rails::Railtie
23
- initializer "newrelic_rpm.start_plugin", before: :load_config_initializers do |app|
24
- NewRelic::Control.instance.init_plugin(config: app.config)
23
+ if NewRelic::Agent.config[:defer_rails_initialization]
24
+ initializer "newrelic_rpm.include_method_tracers", before: :load_config_initializers do |app|
25
+ Module.send(:include, NewRelic::Agent::MethodTracer::ClassMethods)
26
+ Module.send(:include, NewRelic::Agent::MethodTracer)
27
+ end
28
+
29
+ initializer "newrelic_rpm.start_plugin", after: :load_config_initializers do |app|
30
+ NewRelic::Control.instance.init_plugin(config: app.config)
31
+ end
32
+ else
33
+ initializer "newrelic_rpm.start_plugin", before: :load_config_initializers do |app|
34
+ NewRelic::Control.instance.init_plugin(config: app.config)
35
+ end
25
36
  end
26
37
  end
27
38
  end