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
@@ -54,7 +54,7 @@ module Sequel
54
54
  super(*args, &blk)
55
55
  ensure
56
56
  notice_sql(sql)
57
- segment.finish if segment
57
+ ::NewRelic::Agent::Transaction::Segment.finish(segment)
58
58
  end
59
59
  end
60
60
 
@@ -30,7 +30,7 @@ module Sequel
30
30
  begin
31
31
  NewRelic::Agent.disable_all_tracing { super(*args, &block) }
32
32
  ensure
33
- segment.finish if segment
33
+ ::NewRelic::Agent::Transaction::Segment.finish(segment)
34
34
  end
35
35
  end
36
36
  end
data/newrelic.yml CHANGED
@@ -26,6 +26,13 @@ common: &default_settings
26
26
  # All of the following configuration options are optional. Review them, and
27
27
  # uncomment or edit them if they appear relevant to your application needs.
28
28
 
29
+ # An array of ActiveSupport custom events names to subscribe to and provide
30
+ # instrumentation for. For example,
31
+ # - my.custom.event
32
+ # - another.event
33
+ # - a.third.event
34
+ # active_support_custom_events_names: ""
35
+
29
36
  # If `true`, all logging-related features for the agent can be enabled or disabled
30
37
  # independently. If `false`, all logging-related features are disabled.
31
38
  # application_logging.enabled: true
@@ -155,6 +162,10 @@ common: &default_settings
155
162
  # or port_path_or_id parameters to transaction or slow SQL traces.
156
163
  # datastore_tracer.instance_reporting.enabled: true
157
164
 
165
+ # If true, when the agent is in an application using Ruby on Rails, it will start after
166
+ # config/initializers have run.
167
+ # defer_rails_initialization: false
168
+
158
169
  # If true, disables Action Cable instrumentation.
159
170
  # disable_action_cable_instrumentation: false
160
171
 
@@ -173,6 +184,9 @@ common: &default_settings
173
184
  # If true, the agent won't sample the CPU usage of the host process.
174
185
  # disable_cpu_sampler: false
175
186
 
187
+ # If true, disables ActiveSupport custom events instrumentation.
188
+ # disable_custom_events_instrumentation: false
189
+
176
190
  # If true, disables DataMapper instrumentation.
177
191
  # disable_data_mapper: false
178
192
 
@@ -303,17 +317,21 @@ common: &default_settings
303
317
 
304
318
  # Configure the compression level for data sent to the Trace Observer
305
319
  # May be one of [none|low|medium|high]
306
- # By default, compression is not used (level = none)
307
- # infinite_tracing.compression_level: none
320
+ # 'high' is the default. Set the level to 'none' to disable compression
321
+ # infinite_tracing.compression_level: high
308
322
 
309
- # If true, data sent to the Trace Observer will be batched instead of
310
- # the default of each span being sent individually
311
- # infinite_tracing.batching: false
323
+ # If true (the default), data sent to the Trace Observer will be batched
324
+ # instead of each span being sent individually
325
+ # infinite_tracing.batching: true
312
326
 
313
327
  # Controls auto-instrumentation of bunny at start up.
314
328
  # May be one of [auto|prepend|chain|disabled].
315
329
  # instrumentation.bunny: auto
316
330
 
331
+ # Controls auto-instrumentation of concurrent_ruby at start up.
332
+ # May be one of [auto|prepend|chain|disabled]
333
+ # instrumentation.concurrent_ruby: auto
334
+
317
335
  # Controls auto-instrumentation of Curb at start up.
318
336
  # May be one of [auto|prepend|chain|disabled].
319
337
  # instrumentation.curb: auto
data/test/agent_helper.rb CHANGED
@@ -31,7 +31,7 @@ def fake_guid(length = 16)
31
31
  end
32
32
 
33
33
  def assert_between(floor, ceiling, value, message = "expected #{floor} <= #{value} <= #{ceiling}")
34
- assert((floor <= value && value <= ceiling), message) # rubocop:disable Minitest/AssertWithExpectedArgument
34
+ assert((floor <= value && value <= ceiling), message)
35
35
  end
36
36
 
37
37
  def assert_in_delta(expected, actual, delta)
@@ -236,7 +236,7 @@ def assert_metrics_recorded(expected)
236
236
  msg += "\nDid find specs: [\n#{matches.join(",\n")}\n]" unless matches.empty?
237
237
  msg += "\nAll specs in there were: #{format_metric_spec_list(all_specs)}"
238
238
 
239
- assert(actual_stats, msg) # rubocop:disable Minitest/AssertWithExpectedArgument
239
+ assert(actual_stats, msg)
240
240
  end
241
241
 
242
242
  assert_stats_has_values(actual_stats, expected_spec, expected_attrs)
@@ -844,7 +844,7 @@ ensure
844
844
  end
845
845
 
846
846
  def json_dump_and_encode(object)
847
- Base64.encode64(::JSON.dump(object))
847
+ Base64.encode64(JSON.dump(object))
848
848
  end
849
849
 
850
850
  def get_last_analytics_event
@@ -870,7 +870,7 @@ def load_cross_agent_test(name)
870
870
  test_file_path = File.join(cross_agent_tests_dir, "#{name}.json")
871
871
  data = File.read(test_file_path)
872
872
  data.gsub!('callCount', 'call_count')
873
- data = ::JSON.load(data)
873
+ data = JSON.load(data)
874
874
  data.each { |testcase| testcase['testname'].tr!(' ', '_') if String === testcase['testname'] }
875
875
  data
876
876
  end
@@ -1014,9 +1014,9 @@ def assert_implements(instance, method, *args)
1014
1014
  end
1015
1015
 
1016
1016
  def defer_testing_to_min_supported_rails(test_file, min_rails_version, supports_jruby = true)
1017
- if defined?(::Rails) &&
1018
- defined?(::Rails::VERSION::STRING) &&
1019
- (::Rails::VERSION::STRING.to_f >= min_rails_version) &&
1017
+ if defined?(Rails) &&
1018
+ defined?(Rails::VERSION::STRING) &&
1019
+ (Rails::VERSION::STRING.to_f >= min_rails_version) &&
1020
1020
  (supports_jruby || !NewRelic::LanguageSupport.jruby?)
1021
1021
 
1022
1022
  yield
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newrelic_rpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.13.1
4
+ version: 8.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanna McClure
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2022-11-21 00:00:00.000000000 Z
14
+ date: 2023-01-09 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -162,10 +162,13 @@ files:
162
162
  - lib/new_relic/agent.rb
163
163
  - lib/new_relic/agent/adaptive_sampler.rb
164
164
  - lib/new_relic/agent/agent.rb
165
- - lib/new_relic/agent/agent/shutdown.rb
166
- - lib/new_relic/agent/agent/special_startup.rb
167
- - lib/new_relic/agent/agent/start_worker_thread.rb
168
- - lib/new_relic/agent/agent/startup.rb
165
+ - lib/new_relic/agent/agent_helpers/connect.rb
166
+ - lib/new_relic/agent/agent_helpers/harvest.rb
167
+ - lib/new_relic/agent/agent_helpers/shutdown.rb
168
+ - lib/new_relic/agent/agent_helpers/special_startup.rb
169
+ - lib/new_relic/agent/agent_helpers/start_worker_thread.rb
170
+ - lib/new_relic/agent/agent_helpers/startup.rb
171
+ - lib/new_relic/agent/agent_helpers/transmit.rb
169
172
  - lib/new_relic/agent/agent_logger.rb
170
173
  - lib/new_relic/agent/attribute_filter.rb
171
174
  - lib/new_relic/agent/attribute_processing.rb
@@ -249,6 +252,7 @@ files:
249
252
  - lib/new_relic/agent/instrumentation/active_record_subscriber.rb
250
253
  - lib/new_relic/agent/instrumentation/active_storage.rb
251
254
  - lib/new_relic/agent/instrumentation/active_storage_subscriber.rb
255
+ - lib/new_relic/agent/instrumentation/active_support.rb
252
256
  - lib/new_relic/agent/instrumentation/active_support_logger.rb
253
257
  - lib/new_relic/agent/instrumentation/active_support_logger/chain.rb
254
258
  - lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb
@@ -259,11 +263,16 @@ files:
259
263
  - lib/new_relic/agent/instrumentation/bunny/chain.rb
260
264
  - lib/new_relic/agent/instrumentation/bunny/instrumentation.rb
261
265
  - lib/new_relic/agent/instrumentation/bunny/prepend.rb
266
+ - lib/new_relic/agent/instrumentation/concurrent_ruby.rb
267
+ - lib/new_relic/agent/instrumentation/concurrent_ruby/chain.rb
268
+ - lib/new_relic/agent/instrumentation/concurrent_ruby/instrumentation.rb
269
+ - lib/new_relic/agent/instrumentation/concurrent_ruby/prepend.rb
262
270
  - lib/new_relic/agent/instrumentation/controller_instrumentation.rb
263
271
  - lib/new_relic/agent/instrumentation/curb.rb
264
272
  - lib/new_relic/agent/instrumentation/curb/chain.rb
265
273
  - lib/new_relic/agent/instrumentation/curb/instrumentation.rb
266
274
  - lib/new_relic/agent/instrumentation/curb/prepend.rb
275
+ - lib/new_relic/agent/instrumentation/custom_events_subscriber.rb
267
276
  - lib/new_relic/agent/instrumentation/data_mapper.rb
268
277
  - lib/new_relic/agent/instrumentation/delayed_job/chain.rb
269
278
  - lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb
@@ -334,6 +343,7 @@ files:
334
343
  - lib/new_relic/agent/instrumentation/rails_notifications/action_cable.rb
335
344
  - lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb
336
345
  - lib/new_relic/agent/instrumentation/rails_notifications/action_view.rb
346
+ - lib/new_relic/agent/instrumentation/rails_notifications/custom_events.rb
337
347
  - lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb
338
348
  - lib/new_relic/agent/instrumentation/rake.rb
339
349
  - lib/new_relic/agent/instrumentation/rake/chain.rb
@@ -1,35 +0,0 @@
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 Shutdown
8
- # Attempt a graceful shutdown of the agent, flushing any remaining
9
- # data.
10
- def shutdown
11
- return unless started?
12
-
13
- ::NewRelic::Agent.logger.info("Starting Agent shutdown")
14
-
15
- stop_event_loop
16
- trap_signals_for_litespeed
17
- untraced_graceful_disconnect
18
- revert_to_default_configuration
19
-
20
- @started = nil
21
- Control.reset
22
- end
23
-
24
- def untraced_graceful_disconnect
25
- begin
26
- NewRelic::Agent.disable_all_tracing do
27
- graceful_disconnect
28
- end
29
- rescue => e
30
- ::NewRelic::Agent.logger.error(e)
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,72 +0,0 @@
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 SpecialStartup
8
- # If we're using a dispatcher that forks before serving
9
- # requests, we need to wait until the children are forked
10
- # before connecting, otherwise the parent process sends useless data
11
- def using_forking_dispatcher?
12
- # TODO: MAJOR VERSION - remove :rainbows
13
- if [:puma, :passenger, :rainbows, :unicorn].include?(Agent.config[:dispatcher])
14
- ::NewRelic::Agent.logger.info("Deferring startup of agent reporting thread because #{Agent.config[:dispatcher]} may fork.")
15
- true
16
- else
17
- false
18
- end
19
- end
20
-
21
- # Return true if we're using resque and it hasn't had a chance to (potentially)
22
- # daemonize itself. This avoids hanging when there's a Thread started
23
- # before Resque calls Process.daemon (Jira RUBY-857)
24
- def defer_for_resque?
25
- NewRelic::Agent.config[:dispatcher] == :resque &&
26
- NewRelic::Agent::Instrumentation::Resque::Helper.resque_fork_per_job? &&
27
- !PipeChannelManager.listener.started?
28
- end
29
-
30
- def in_resque_child_process?
31
- defined?(@service) && @service.is_a?(PipeService)
32
- end
33
-
34
- def defer_for_delayed_job?
35
- NewRelic::Agent.config[:dispatcher] == :delayed_job &&
36
- !NewRelic::DelayedJobInjection.worker_name
37
- end
38
-
39
- # This matters when the following three criteria are met:
40
- #
41
- # 1. A Sinatra 'classic' application is being run
42
- # 2. The app is being run by executing the main file directly, rather
43
- # than via a config.ru file.
44
- # 3. newrelic_rpm is required *after* sinatra
45
- #
46
- # In this case, the entire application runs from an at_exit handler in
47
- # Sinatra, and if we were to install ours, it would be executed before
48
- # the one in Sinatra, meaning that we'd shutdown the agent too early
49
- # and never collect any data.
50
- def sinatra_classic_app?
51
- (
52
- defined?(Sinatra::Application) &&
53
- Sinatra::Application.respond_to?(:run) &&
54
- Sinatra::Application.run?
55
- )
56
- end
57
-
58
- def should_install_exit_handler?
59
- return false unless Agent.config[:send_data_on_exit]
60
-
61
- !sinatra_classic_app? || Agent.config[:force_install_exit_handler]
62
- end
63
-
64
- def install_exit_handler
65
- return unless should_install_exit_handler?
66
-
67
- NewRelic::Agent.logger.debug("Installing at_exit handler")
68
- at_exit { shutdown }
69
- end
70
- end
71
- end
72
- end
@@ -1,163 +0,0 @@
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 StartWorkerThread
8
- LOG_ONCE_KEYS_RESET_PERIOD = 60.0
9
-
10
- TRANSACTION_EVENT_DATA = "transaction_event_data".freeze
11
- CUSTOM_EVENT_DATA = "custom_event_data".freeze
12
- ERROR_EVENT_DATA = "error_event_data".freeze
13
- SPAN_EVENT_DATA = "span_event_data".freeze
14
- LOG_EVENT_DATA = "log_event_data".freeze
15
-
16
- # Try to launch the worker thread and connect to the server.
17
- #
18
- # See #connect for a description of connection_options.
19
- def start_worker_thread(connection_options = {})
20
- if disable = NewRelic::Agent.config[:disable_harvest_thread]
21
- NewRelic::Agent.logger.info("Not starting Ruby Agent worker thread because :disable_harvest_thread is #{disable}")
22
- return
23
- end
24
-
25
- ::NewRelic::Agent.logger.debug("Creating Ruby Agent worker thread.")
26
- @worker_thread = Threading::AgentThread.create('Worker Loop') do
27
- deferred_work!(connection_options)
28
- end
29
- end
30
-
31
- def create_event_loop
32
- EventLoop.new
33
- end
34
-
35
- # If the @worker_thread encounters an error during the attempt to connect to the collector
36
- # then the connect attempts enter an exponential backoff retry loop. To avoid potential
37
- # race conditions with shutting down while also attempting to reconnect, we join the
38
- # @worker_thread with a timeout threshold. This allows potentially connecting and flushing
39
- # pending data to the server, but without waiting indefinitely for a reconnect to succeed.
40
- # The use-case where this typically arises is in cronjob scheduled rake tasks where there's
41
- # also some network stability/latency issues happening.
42
- def stop_event_loop
43
- @event_loop.stop if @event_loop
44
- # Wait the end of the event loop thread.
45
- if @worker_thread
46
- unless @worker_thread.join(3)
47
- ::NewRelic::Agent.logger.debug("Event loop thread did not stop within 3 seconds")
48
- end
49
- end
50
- end
51
-
52
- # Certain event types may sometimes need to be on the same interval as metrics,
53
- # so we will check config assigned in EventHarvestConfig to determine the interval
54
- # on which to report them
55
- def interval_for(event_type)
56
- interval = Agent.config[:"event_report_period.#{event_type}"]
57
- :"#{interval}_second_harvest"
58
- end
59
-
60
- def create_and_run_event_loop
61
- data_harvest = :"#{Agent.config[:data_report_period]}_second_harvest"
62
- event_harvest = :"#{Agent.config[:event_report_period]}_second_harvest"
63
-
64
- @event_loop = create_event_loop
65
- @event_loop.on(data_harvest) do
66
- transmit_data
67
- end
68
-
69
- @event_loop.on(interval_for(TRANSACTION_EVENT_DATA)) do
70
- transmit_analytic_event_data
71
- end
72
- @event_loop.on(interval_for(CUSTOM_EVENT_DATA)) do
73
- transmit_custom_event_data
74
- end
75
- @event_loop.on(interval_for(ERROR_EVENT_DATA)) do
76
- transmit_error_event_data
77
- end
78
- @event_loop.on(interval_for(SPAN_EVENT_DATA)) do
79
- transmit_span_event_data
80
- end
81
- @event_loop.on(interval_for(LOG_EVENT_DATA)) do
82
- transmit_log_event_data
83
- end
84
-
85
- @event_loop.on(:reset_log_once_keys) do
86
- ::NewRelic::Agent.logger.clear_already_logged
87
- end
88
- @event_loop.fire_every(Agent.config[:data_report_period], data_harvest)
89
- @event_loop.fire_every(Agent.config[:event_report_period], event_harvest)
90
- @event_loop.fire_every(LOG_ONCE_KEYS_RESET_PERIOD, :reset_log_once_keys)
91
-
92
- @event_loop.run
93
- end
94
-
95
- # Handles the case where the server tells us to restart -
96
- # this clears the data, clears connection attempts, and
97
- # waits a while to reconnect.
98
- def handle_force_restart(error)
99
- ::NewRelic::Agent.logger.debug(error.message)
100
- drop_buffered_data
101
- @service.force_restart if @service
102
- @connect_state = :pending
103
- sleep(30)
104
- end
105
-
106
- # when a disconnect is requested, stop the current thread, which
107
- # is the worker thread that gathers data and talks to the
108
- # server.
109
- def handle_force_disconnect(error)
110
- ::NewRelic::Agent.logger.warn("Agent received a ForceDisconnectException from the server, disconnecting. (#{error.message})")
111
- disconnect
112
- end
113
-
114
- # Handles an unknown error in the worker thread by logging
115
- # it and disconnecting the agent, since we are now in an
116
- # unknown state.
117
- def handle_other_error(error)
118
- ::NewRelic::Agent.logger.error("Unhandled error in worker thread, disconnecting.")
119
- # These errors are fatal (that is, they will prevent the agent from
120
- # reporting entirely), so we really want backtraces when they happen
121
- ::NewRelic::Agent.logger.log_exception(:error, error)
122
- disconnect
123
- end
124
-
125
- # a wrapper method to handle all the errors that can happen
126
- # in the connection and worker thread system. This
127
- # guarantees a no-throw from the background thread.
128
- def catch_errors
129
- yield
130
- rescue NewRelic::Agent::ForceRestartException => e
131
- handle_force_restart(e)
132
- retry
133
- rescue NewRelic::Agent::ForceDisconnectException => e
134
- handle_force_disconnect(e)
135
- rescue => e
136
- handle_other_error(e)
137
- end
138
-
139
- # This is the method that is run in a new thread in order to
140
- # background the harvesting and sending of data during the
141
- # normal operation of the agent.
142
- #
143
- # Takes connection options that determine how we should
144
- # connect to the server, and loops endlessly - typically we
145
- # never return from this method unless we're shutting down
146
- # the agent
147
- def deferred_work!(connection_options)
148
- catch_errors do
149
- NewRelic::Agent.disable_all_tracing do
150
- connect(connection_options)
151
- if connected?
152
- create_and_run_event_loop
153
- # never reaches here unless there is a problem or
154
- # the agent is exiting
155
- else
156
- ::NewRelic::Agent.logger.debug("No connection. Worker thread ending.")
157
- end
158
- end
159
- end
160
- end
161
- end
162
- end
163
- end
@@ -1,197 +0,0 @@
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 Startup
8
- # True if we have initialized and completed 'start'
9
- def started?
10
- @started
11
- end
12
-
13
- # Check whether we have already started, which is an error condition
14
- def already_started?
15
- if started?
16
- ::NewRelic::Agent.logger.error("Agent Started Already!")
17
- true
18
- end
19
- end
20
-
21
- # Logs a bunch of data and starts the agent, if needed
22
- def start
23
- return unless agent_should_start?
24
-
25
- log_startup
26
- check_config_and_start_agent
27
- log_version_and_pid
28
-
29
- events.subscribe(:initial_configuration_complete) do
30
- log_ignore_url_regexes
31
- end
32
- end
33
-
34
- # Sanity-check the agent configuration and start the agent,
35
- # setting up the worker thread and the exit handler to shut
36
- # down the agent
37
- def check_config_and_start_agent
38
- return unless monitoring? && has_correct_license_key?
39
- return if using_forking_dispatcher?
40
-
41
- setup_and_start_agent
42
- end
43
-
44
- # This is the shared method between the main agent startup and the
45
- # after_fork call restarting the thread in deferred dispatchers.
46
- #
47
- # Treatment of @started and env report is important to get right.
48
- def setup_and_start_agent(options = {})
49
- @started = true
50
- @harvester.mark_started
51
-
52
- unless in_resque_child_process?
53
- install_exit_handler
54
- environment_for_connect
55
- @harvest_samplers.load_samplers unless Agent.config[:disable_samplers]
56
- end
57
-
58
- connect_in_foreground if Agent.config[:sync_startup]
59
- start_worker_thread(options)
60
- end
61
-
62
- # Log startup information that we almost always want to know
63
- def log_startup
64
- log_environment
65
- log_dispatcher
66
- log_app_name
67
- end
68
-
69
- # Log the environment the app thinks it's running in.
70
- # Useful in debugging, as this is the key for config YAML lookups.
71
- def log_environment
72
- ::NewRelic::Agent.logger.info("Environment: #{NewRelic::Control.instance.env}")
73
- end
74
-
75
- # Logs the dispatcher to the log file to assist with
76
- # debugging. When no debugger is present, logs this fact to
77
- # assist with proper dispatcher detection
78
- def log_dispatcher
79
- dispatcher_name = Agent.config[:dispatcher].to_s
80
-
81
- if dispatcher_name.empty?
82
- ::NewRelic::Agent.logger.info('No known dispatcher detected.')
83
- else
84
- ::NewRelic::Agent.logger.info("Dispatcher: #{dispatcher_name}")
85
- end
86
- end
87
-
88
- def log_app_name
89
- ::NewRelic::Agent.logger.info("Application: #{Agent.config[:app_name].join(", ")}")
90
- end
91
-
92
- def log_ignore_url_regexes
93
- regexes = NewRelic::Agent.config[:'rules.ignore_url_regexes']
94
-
95
- unless regexes.empty?
96
- ::NewRelic::Agent.logger.info("Ignoring URLs that match the following regexes: #{regexes.map(&:inspect).join(", ")}.")
97
- end
98
- end
99
-
100
- # Classy logging of the agent version and the current pid,
101
- # so we can disambiguate processes in the log file and make
102
- # sure they're running a reasonable version
103
- def log_version_and_pid
104
- ::NewRelic::Agent.logger.debug("New Relic Ruby Agent #{NewRelic::VERSION::STRING} Initialized: pid = #{$$}")
105
- end
106
-
107
- # Logs the configured application names
108
- def app_name_configured?
109
- names = Agent.config[:app_name]
110
- return names.respond_to?(:any?) && names.any?
111
- end
112
-
113
- # Connecting in the foreground blocks further startup of the
114
- # agent until we have a connection - useful in cases where
115
- # you're trying to log a very-short-running process and want
116
- # to get statistics from before a server connection
117
- # (typically 20 seconds) exists
118
- def connect_in_foreground
119
- NewRelic::Agent.disable_all_tracing { connect(:keep_retrying => false) }
120
- end
121
-
122
- # Warn the user if they have configured their agent not to
123
- # send data, that way we can see this clearly in the log file
124
- def monitoring?
125
- if Agent.config[:monitor_mode]
126
- true
127
- else
128
- ::NewRelic::Agent.logger.warn('Agent configured not to send data in this environment.')
129
- false
130
- end
131
- end
132
-
133
- # Tell the user when the license key is missing so they can
134
- # fix it by adding it to the file
135
- def has_license_key?
136
- if Agent.config[:license_key] && Agent.config[:license_key].length > 0
137
- true
138
- else
139
- ::NewRelic::Agent.logger.warn("No license key found. " +
140
- "This often means your newrelic.yml file was not found, or it lacks a section for the running environment, '#{NewRelic::Control.instance.env}'. You may also want to try linting your newrelic.yml to ensure it is valid YML.")
141
- false
142
- end
143
- end
144
-
145
- # A correct license key exists and is of the proper length
146
- def has_correct_license_key?
147
- has_license_key? && correct_license_length
148
- end
149
-
150
- # A license key is an arbitrary 40 character string,
151
- # usually looks something like a SHA1 hash
152
- def correct_license_length
153
- key = Agent.config[:license_key]
154
-
155
- if key.length == 40
156
- true
157
- else
158
- ::NewRelic::Agent.logger.error("Invalid license key: #{key}")
159
- false
160
- end
161
- end
162
-
163
- # Check to see if the agent should start, returning +true+ if it should.
164
- def agent_should_start?
165
- return false if already_started? || disabled?
166
-
167
- if defer_for_delayed_job?
168
- ::NewRelic::Agent.logger.debug("Deferring startup for DelayedJob")
169
- return false
170
- end
171
-
172
- if defer_for_resque?
173
- ::NewRelic::Agent.logger.debug("Deferring startup for Resque in case it daemonizes")
174
- return false
175
- end
176
-
177
- unless app_name_configured?
178
- NewRelic::Agent.logger.error("No application name configured.",
179
- "The Agent cannot start without at least one. Please check your ",
180
- "newrelic.yml and ensure that it is valid and has at least one ",
181
- "value set for app_name in the #{NewRelic::Control.instance.env} ",
182
- "environment.")
183
- return false
184
- end
185
-
186
- return true
187
- end
188
-
189
- # The agent is disabled when it is not force enabled by the
190
- # 'agent_enabled' option (e.g. in a manual start), or
191
- # enabled normally through the configuration file
192
- def disabled?
193
- !Agent.config[:agent_enabled]
194
- end
195
- end
196
- end
197
- end