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.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.rubocop.yml +130 -1
- data/.rubocop_todo.yml +3 -0
- data/CHANGELOG.md +3284 -3148
- data/CONTRIBUTING.md +1 -2
- data/README.md +2 -1
- data/init.rb +1 -1
- data/lib/new_relic/agent/agent.rb +14 -466
- data/lib/new_relic/agent/agent_helpers/connect.rb +227 -0
- data/lib/new_relic/agent/agent_helpers/harvest.rb +153 -0
- data/lib/new_relic/agent/agent_helpers/shutdown.rb +72 -0
- data/lib/new_relic/agent/agent_helpers/special_startup.rb +75 -0
- data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +167 -0
- data/lib/new_relic/agent/agent_helpers/startup.rb +202 -0
- data/lib/new_relic/agent/agent_helpers/transmit.rb +76 -0
- data/lib/new_relic/agent/configuration/default_source.rb +47 -9
- data/lib/new_relic/agent/datastores.rb +2 -2
- data/lib/new_relic/agent/event_loop.rb +1 -1
- data/lib/new_relic/agent/guid_generator.rb +11 -2
- data/lib/new_relic/agent/heap.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_job.rb +7 -7
- data/lib/new_relic/agent/instrumentation/active_merchant.rb +2 -2
- data/lib/new_relic/agent/instrumentation/active_record.rb +9 -9
- data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +24 -24
- data/lib/new_relic/agent/instrumentation/active_storage.rb +2 -2
- data/lib/new_relic/agent/instrumentation/active_support.rb +12 -0
- data/lib/new_relic/agent/instrumentation/active_support_logger.rb +3 -3
- data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +2 -2
- data/lib/new_relic/agent/instrumentation/authlogic.rb +2 -2
- data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +3 -3
- data/lib/new_relic/agent/instrumentation/bunny.rb +4 -4
- data/lib/new_relic/agent/instrumentation/concurrent_ruby/chain.rb +36 -0
- data/lib/new_relic/agent/instrumentation/concurrent_ruby/instrumentation.rb +21 -0
- data/lib/new_relic/agent/instrumentation/concurrent_ruby/prepend.rb +27 -0
- data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +31 -0
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -1
- data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +1 -1
- data/lib/new_relic/agent/instrumentation/curb.rb +6 -6
- data/lib/new_relic/agent/instrumentation/custom_events_subscriber.rb +37 -0
- data/lib/new_relic/agent/instrumentation/data_mapper.rb +50 -50
- data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +5 -5
- data/lib/new_relic/agent/instrumentation/elasticsearch.rb +5 -5
- data/lib/new_relic/agent/instrumentation/excon/middleware.rb +1 -1
- data/lib/new_relic/agent/instrumentation/excon.rb +9 -9
- data/lib/new_relic/agent/instrumentation/grape.rb +8 -8
- data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +1 -1
- data/lib/new_relic/agent/instrumentation/grpc_client.rb +3 -3
- data/lib/new_relic/agent/instrumentation/grpc_server.rb +4 -4
- data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +1 -1
- data/lib/new_relic/agent/instrumentation/httpclient.rb +2 -2
- data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +1 -1
- data/lib/new_relic/agent/instrumentation/httprb.rb +3 -3
- data/lib/new_relic/agent/instrumentation/logger.rb +3 -3
- data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +3 -3
- data/lib/new_relic/agent/instrumentation/memcache.rb +16 -16
- data/lib/new_relic/agent/instrumentation/mongo.rb +1 -1
- data/lib/new_relic/agent/instrumentation/net_http.rb +6 -6
- data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
- data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +5 -5
- data/lib/new_relic/agent/instrumentation/rack.rb +14 -14
- data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +5 -5
- data/lib/new_relic/agent/instrumentation/rails_middleware.rb +3 -3
- data/lib/new_relic/agent/instrumentation/rails_notifications/action_cable.rb +6 -6
- data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +2 -2
- data/lib/new_relic/agent/instrumentation/rails_notifications/action_view.rb +5 -3
- data/lib/new_relic/agent/instrumentation/rails_notifications/custom_events.rb +30 -0
- data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +4 -4
- data/lib/new_relic/agent/instrumentation/rake.rb +7 -7
- data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +29 -8
- data/lib/new_relic/agent/instrumentation/redis.rb +4 -4
- data/lib/new_relic/agent/instrumentation/resque.rb +9 -9
- data/lib/new_relic/agent/instrumentation/sequel.rb +2 -2
- data/lib/new_relic/agent/instrumentation/sidekiq.rb +3 -3
- data/lib/new_relic/agent/instrumentation/sinatra.rb +7 -7
- data/lib/new_relic/agent/instrumentation/sunspot.rb +4 -4
- data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +5 -1
- data/lib/new_relic/agent/instrumentation/thread.rb +3 -3
- data/lib/new_relic/agent/instrumentation/tilt.rb +3 -3
- data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +2 -2
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +1 -1
- data/lib/new_relic/agent/javascript_instrumentor.rb +2 -2
- data/lib/new_relic/agent/method_tracer_helpers.rb +6 -11
- data/lib/new_relic/agent/range_extensions.rb +2 -2
- data/lib/new_relic/agent/tracer.rb +8 -4
- data/lib/new_relic/agent/transaction/abstract_segment.rb +2 -2
- data/lib/new_relic/agent/transaction/segment.rb +6 -0
- data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +1 -1
- data/lib/new_relic/agent/transaction.rb +3 -3
- data/lib/new_relic/agent.rb +7 -0
- data/lib/new_relic/control/instance_methods.rb +6 -2
- data/lib/new_relic/helper.rb +1 -1
- data/lib/new_relic/recipes/helpers/send_deployment.rb +2 -1
- data/lib/new_relic/traced_thread.rb +5 -1
- data/lib/new_relic/version.rb +2 -2
- data/lib/newrelic_rpm.rb +13 -2
- data/lib/sequel/extensions/newrelic_instrumentation.rb +1 -1
- data/lib/sequel/plugins/newrelic_instrumentation.rb +1 -1
- data/newrelic.yml +23 -5
- data/test/agent_helper.rb +7 -7
- metadata +16 -6
- data/lib/new_relic/agent/agent/shutdown.rb +0 -35
- data/lib/new_relic/agent/agent/special_startup.rb +0 -72
- data/lib/new_relic/agent/agent/start_worker_thread.rb +0 -163
- data/lib/new_relic/agent/agent/startup.rb +0 -197
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
|
-
#
|
307
|
-
# infinite_tracing.compression_level:
|
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
|
310
|
-
#
|
311
|
-
# infinite_tracing.batching:
|
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)
|
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)
|
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(
|
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 =
|
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?(
|
1018
|
-
defined?(
|
1019
|
-
(
|
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.
|
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:
|
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/
|
166
|
-
- lib/new_relic/agent/
|
167
|
-
- lib/new_relic/agent/
|
168
|
-
- lib/new_relic/agent/
|
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
|