diff --git a/.changesets/add-delayed-job-enqueue-instrumentation.md b/.changesets/add-delayed-job-enqueue-instrumentation.md deleted file mode 100644 index b6b5a640f..000000000 --- a/.changesets/add-delayed-job-enqueue-instrumentation.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -bump: minor -type: add ---- - -Instrument Delayed Job enqueues. Enqueuing a job now records an -`enqueue.delayed_job` event on the active transaction, so enqueues made from -within a web request or another job show up in the event timeline. diff --git a/.changesets/add-instrument-config-options.md b/.changesets/add-instrument-config-options.md new file mode 100644 index 000000000..bfe2fade8 --- /dev/null +++ b/.changesets/add-instrument-config-options.md @@ -0,0 +1,13 @@ +--- +bump: minor +type: add +--- + +Add config options to turn individual integrations off. Set +`instrument_sidekiq`, `instrument_shoryuken`, `instrument_que`, +`instrument_resque`, `instrument_delayed_job`, `instrument_active_job`, +`instrument_excon` or `instrument_mongo` to `false` to disable that +integration entirely. This turns off both the instrumentation of the jobs or +requests and the enqueue instrumentation for that integration. They all +default to `true`. Each can also be set through its environment variable, such +as `APPSIGNAL_INSTRUMENT_SIDEKIQ`. diff --git a/.changesets/add-shoryuken-enqueue-instrumentation.md b/.changesets/add-shoryuken-enqueue-instrumentation.md deleted file mode 100644 index 1a3ef60ae..000000000 --- a/.changesets/add-shoryuken-enqueue-instrumentation.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -bump: minor -type: add ---- - -Instrument Shoryuken job enqueues. Enqueuing a job now records an -`enqueue.shoryuken` event on the active transaction, so enqueues made from -within a web request or another job show up in the event timeline. diff --git a/.changesets/emit-mongodb-body-as-json-string.md b/.changesets/emit-mongodb-body-as-json-string.md deleted file mode 100644 index c6ce93e9f..000000000 --- a/.changesets/emit-mongodb-body-as-json-string.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -bump: patch -type: change ---- - -Emit the MongoDB query event body as a JSON string instead of a structured data object. The recorded query body is unchanged. diff --git a/.changesets/instrument-active-job-enqueues.md b/.changesets/instrument-active-job-enqueues.md deleted file mode 100644 index bd36d1eac..000000000 --- a/.changesets/instrument-active-job-enqueues.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -bump: patch -type: change ---- - -Record the `enqueue.active_job` event from AppSignal's own Active Job -instrumentation rather than from Rails' native `enqueue.active_job` -notification, which is now suppressed so the enqueue is recorded once. The -event still shows up on the active transaction when enqueuing from within a web -request or another job, and is now titled after the job being enqueued. diff --git a/.changesets/instrument-background-job-enqueues.md b/.changesets/instrument-background-job-enqueues.md new file mode 100644 index 000000000..dcd9c5eb7 --- /dev/null +++ b/.changesets/instrument-background-job-enqueues.md @@ -0,0 +1,24 @@ +--- +bump: minor +type: add +--- + +Instrument background job enqueues. Enqueuing a job now records an enqueue +event on the active transaction, so enqueues made from within a web request or +another job show up in the event timeline. This is recorded for Sidekiq +(`enqueue.sidekiq`), Que (`enqueue.que`, plus `bulk_enqueue.que` for bulk +enqueues on Que 2), Resque (`enqueue.resque`), Shoryuken (`enqueue.shoryuken`) +and Delayed Job (`enqueue.delayed_job`). Each event is titled after the job +being enqueued. + +For Active Job, the `enqueue.active_job` event is now recorded by AppSignal's +own instrumentation rather than by Rails' native `enqueue.active_job` +notification. The native notification is suppressed so the enqueue is recorded +once, and the event is now titled after the job being enqueued. + +These enqueue events can be turned off with the +`enable_job_enqueue_instrumentation` config option. Set it to `false` to stop +recording enqueue events across all integrations, without affecting the +instrumentation of the jobs themselves. It defaults to `true` and can also be +set through the `APPSIGNAL_ENABLE_JOB_ENQUEUE_INSTRUMENTATION` environment +variable. diff --git a/.changesets/instrument-que-enqueues.md b/.changesets/instrument-que-enqueues.md deleted file mode 100644 index 0c342568b..000000000 --- a/.changesets/instrument-que-enqueues.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -bump: minor -type: add ---- - -Instrument Que job enqueues. AppSignal now records an `enqueue.que` event when a Que job is enqueued, and a `bulk_enqueue.que` event for bulk enqueues on Que 2, so the enqueue shows up in the transaction timeline. diff --git a/.changesets/instrument-resque-enqueues.md b/.changesets/instrument-resque-enqueues.md deleted file mode 100644 index 5744a13d7..000000000 --- a/.changesets/instrument-resque-enqueues.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -bump: minor -type: add ---- - -Instrument Resque job enqueues. Enqueuing a job now records an `enqueue.resque` -event on the active transaction, so enqueues made from within a web request or -another job show up in the event timeline. diff --git a/.changesets/instrument-sidekiq-enqueues.md b/.changesets/instrument-sidekiq-enqueues.md deleted file mode 100644 index f56342664..000000000 --- a/.changesets/instrument-sidekiq-enqueues.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -bump: minor -type: add ---- - -Instrument Sidekiq job enqueues. Enqueuing a job now records an -`enqueue.sidekiq` event on the active transaction, so enqueues made from within -a web request or another job show up in the event timeline. diff --git a/.changesets/title-sidekiq-delayed-enqueues-by-target.md b/.changesets/title-sidekiq-delayed-enqueues-by-target.md deleted file mode 100644 index 9a5d086a2..000000000 --- a/.changesets/title-sidekiq-delayed-enqueues-by-target.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -bump: patch -type: change ---- - -Title `enqueue.sidekiq` events for Sidekiq delayed extension jobs after the -delayed target and method, such as `enqueue MyClass.my_method job`, instead of -the internal wrapper class. This matches the name the job is given when it -later performs, so the enqueue and perform of the same job read the same name. diff --git a/lib/appsignal/config.rb b/lib/appsignal/config.rb index b938342d1..f688a3f13 100644 --- a/lib/appsignal/config.rb +++ b/lib/appsignal/config.rb @@ -96,6 +96,7 @@ def dsl_config_file? :enable_at_exit_hook => "on_error", :enable_at_exit_reporter => true, :enable_host_metrics => true, + :enable_job_enqueue_instrumentation => true, :enable_minutely_probes => true, :enable_statsd => true, :enable_nginx_metrics => false, @@ -113,13 +114,21 @@ def dsl_config_file? :ignore_errors => [], :ignore_logs => [], :ignore_namespaces => [], + :instrument_active_job => true, :instrument_code_ownership => true, + :instrument_delayed_job => true, + :instrument_excon => true, :instrument_faraday => true, :instrument_http_rb => true, + :instrument_mongo => true, :instrument_net_http => true, :instrument_ownership => true, + :instrument_que => true, :instrument_redis => true, + :instrument_resque => true, :instrument_sequel => true, + :instrument_shoryuken => true, + :instrument_sidekiq => true, :log => "file", :logging_endpoint => "https://appsignal-endpoint.net", :ownership_set_namespace => false, @@ -181,6 +190,8 @@ def dsl_config_file? :enable_allocation_tracking => "APPSIGNAL_ENABLE_ALLOCATION_TRACKING", :enable_at_exit_reporter => "APPSIGNAL_ENABLE_AT_EXIT_REPORTER", :enable_host_metrics => "APPSIGNAL_ENABLE_HOST_METRICS", + :enable_job_enqueue_instrumentation => + "APPSIGNAL_ENABLE_JOB_ENQUEUE_INSTRUMENTATION", :enable_minutely_probes => "APPSIGNAL_ENABLE_MINUTELY_PROBES", :enable_statsd => "APPSIGNAL_ENABLE_STATSD", :enable_nginx_metrics => "APPSIGNAL_ENABLE_NGINX_METRICS", @@ -192,13 +203,21 @@ def dsl_config_file? :enable_rake_performance_instrumentation => "APPSIGNAL_ENABLE_RAKE_PERFORMANCE_INSTRUMENTATION", :files_world_accessible => "APPSIGNAL_FILES_WORLD_ACCESSIBLE", + :instrument_active_job => "APPSIGNAL_INSTRUMENT_ACTIVE_JOB", :instrument_code_ownership => "APPSIGNAL_INSTRUMENT_CODE_OWNERSHIP", + :instrument_delayed_job => "APPSIGNAL_INSTRUMENT_DELAYED_JOB", + :instrument_excon => "APPSIGNAL_INSTRUMENT_EXCON", :instrument_faraday => "APPSIGNAL_INSTRUMENT_FARADAY", :instrument_http_rb => "APPSIGNAL_INSTRUMENT_HTTP_RB", + :instrument_mongo => "APPSIGNAL_INSTRUMENT_MONGO", :instrument_net_http => "APPSIGNAL_INSTRUMENT_NET_HTTP", :instrument_ownership => "APPSIGNAL_INSTRUMENT_OWNERSHIP", + :instrument_que => "APPSIGNAL_INSTRUMENT_QUE", :instrument_redis => "APPSIGNAL_INSTRUMENT_REDIS", + :instrument_resque => "APPSIGNAL_INSTRUMENT_RESQUE", :instrument_sequel => "APPSIGNAL_INSTRUMENT_SEQUEL", + :instrument_shoryuken => "APPSIGNAL_INSTRUMENT_SHORYUKEN", + :instrument_sidekiq => "APPSIGNAL_INSTRUMENT_SIDEKIQ", :ownership_set_namespace => "APPSIGNAL_OWNERSHIP_SET_NAMESPACE", :running_in_container => "APPSIGNAL_RUNNING_IN_CONTAINER", :send_environment_metadata => "APPSIGNAL_SEND_ENVIRONMENT_METADATA", @@ -828,6 +847,8 @@ def activate_if_environment(*envs) # @return [Boolean] Configure whether the at_exit reporter is enabled # @!attribute [rw] enable_host_metrics # @return [Boolean] Configure whether host metrics collection is enabled + # @!attribute [rw] enable_job_enqueue_instrumentation + # @return [Boolean] Configure whether to record an event when a background job is enqueued # @!attribute [rw] enable_minutely_probes # @return [Boolean] Configure whether minutely probes are enabled # @!attribute [rw] enable_statsd @@ -846,18 +867,34 @@ def activate_if_environment(*envs) # @return [Boolean] Configure whether Rake performance instrumentation is enabled # @!attribute [rw] files_world_accessible # @return [Boolean] Configure whether files created by AppSignal should be world accessible + # @!attribute [rw] instrument_active_job + # @return [Boolean] Configure whether to instrument Active Job + # @!attribute [rw] instrument_delayed_job + # @return [Boolean] Configure whether to instrument Delayed Job + # @!attribute [rw] instrument_excon + # @return [Boolean] Configure whether to instrument requests made with the Excon gem # @!attribute [rw] instrument_faraday # @return [Boolean] Configure whether to instrument requests made with the Faraday gem # @!attribute [rw] instrument_http_rb # @return [Boolean] Configure whether to instrument requests made with the http.rb gem + # @!attribute [rw] instrument_mongo + # @return [Boolean] Configure whether to instrument MongoDB queries # @!attribute [rw] instrument_net_http # @return [Boolean] Configure whether to instrument requests made with Net::HTTP # @!attribute [rw] instrument_ownership # @return [Boolean] Configure whether to instrument the Ownership gem + # @!attribute [rw] instrument_que + # @return [Boolean] Configure whether to instrument Que # @!attribute [rw] instrument_redis # @return [Boolean] Configure whether to instrument Redis queries + # @!attribute [rw] instrument_resque + # @return [Boolean] Configure whether to instrument Resque # @!attribute [rw] instrument_sequel # @return [Boolean] Configure whether to instrument Sequel queries + # @!attribute [rw] instrument_shoryuken + # @return [Boolean] Configure whether to instrument Shoryuken + # @!attribute [rw] instrument_sidekiq + # @return [Boolean] Configure whether to instrument Sidekiq # @!attribute [rw] ownership_set_namespace # @return [Boolean] Configure whether the Ownership gem instrumentation should set namespace # @!attribute [rw] running_in_container diff --git a/lib/appsignal/hooks/active_job.rb b/lib/appsignal/hooks/active_job.rb index 2b6446d0b..b49c8e18d 100644 --- a/lib/appsignal/hooks/active_job.rb +++ b/lib/appsignal/hooks/active_job.rb @@ -22,7 +22,8 @@ def self.dependencies_present? end def dependencies_present? - self.class.dependencies_present? + self.class.dependencies_present? && Appsignal.config && + Appsignal.config[:instrument_active_job] end def install @@ -56,6 +57,15 @@ def install # @!visibility private module ActiveJobEnqueueInstrumentation def enqueue(*, **) + # Skip recording the event when enqueue events are suppressed. That is + # the case when enqueue instrumentation is disabled, and it keeps this + # integration consistent with the standalone adapters (Sidekiq, ...), + # which already gate their own enqueue event on this check. + if Appsignal::Transaction.current? && + Appsignal::Transaction.current.job_enqueue_events_suppressed? + return super + end + Appsignal.instrument("enqueue.active_job", "enqueue #{self.class.name} job") do # Active Job enqueues through an adapter (Sidekiq, Resque, ...) that # has its own enqueue instrumentation. Suppress it so the enqueue is diff --git a/lib/appsignal/hooks/delayed_job.rb b/lib/appsignal/hooks/delayed_job.rb index 8406fbdd9..f70573814 100644 --- a/lib/appsignal/hooks/delayed_job.rb +++ b/lib/appsignal/hooks/delayed_job.rb @@ -7,7 +7,8 @@ class DelayedJobHook < Appsignal::Hooks::Hook register :delayed_job def dependencies_present? - defined?(::Delayed::Plugin) + defined?(::Delayed::Plugin) && Appsignal.config && + Appsignal.config[:instrument_delayed_job] end def install diff --git a/lib/appsignal/hooks/excon.rb b/lib/appsignal/hooks/excon.rb index ff09de8bf..4a3a1216a 100644 --- a/lib/appsignal/hooks/excon.rb +++ b/lib/appsignal/hooks/excon.rb @@ -7,7 +7,7 @@ class ExconHook < Appsignal::Hooks::Hook register :excon def dependencies_present? - Appsignal.config && defined?(::Excon) + Appsignal.config && defined?(::Excon) && Appsignal.config[:instrument_excon] end def install diff --git a/lib/appsignal/hooks/mongo_ruby_driver.rb b/lib/appsignal/hooks/mongo_ruby_driver.rb index 98259ec28..7ca2e5dc7 100644 --- a/lib/appsignal/hooks/mongo_ruby_driver.rb +++ b/lib/appsignal/hooks/mongo_ruby_driver.rb @@ -7,7 +7,8 @@ class MongoRubyDriverHook < Appsignal::Hooks::Hook register :mongo_ruby_driver def dependencies_present? - defined?(::Mongo::Monitoring::Global) + defined?(::Mongo::Monitoring::Global) && Appsignal.config && + Appsignal.config[:instrument_mongo] end def install diff --git a/lib/appsignal/hooks/que.rb b/lib/appsignal/hooks/que.rb index 22b77e5a1..84494b57b 100644 --- a/lib/appsignal/hooks/que.rb +++ b/lib/appsignal/hooks/que.rb @@ -7,7 +7,7 @@ class QueHook < Appsignal::Hooks::Hook register :que def dependencies_present? - defined?(::Que::Job) + defined?(::Que::Job) && Appsignal.config && Appsignal.config[:instrument_que] end def install diff --git a/lib/appsignal/hooks/resque.rb b/lib/appsignal/hooks/resque.rb index 01183fd25..75cc6ad59 100644 --- a/lib/appsignal/hooks/resque.rb +++ b/lib/appsignal/hooks/resque.rb @@ -7,7 +7,7 @@ class ResqueHook < Appsignal::Hooks::Hook register :resque def dependencies_present? - defined?(::Resque) + defined?(::Resque) && Appsignal.config && Appsignal.config[:instrument_resque] end def install diff --git a/lib/appsignal/hooks/shoryuken.rb b/lib/appsignal/hooks/shoryuken.rb index 4ab7cd205..82d9dce88 100644 --- a/lib/appsignal/hooks/shoryuken.rb +++ b/lib/appsignal/hooks/shoryuken.rb @@ -7,7 +7,7 @@ class ShoryukenHook < Appsignal::Hooks::Hook register :shoryuken def dependencies_present? - defined?(::Shoryuken) + defined?(::Shoryuken) && Appsignal.config && Appsignal.config[:instrument_shoryuken] end def install diff --git a/lib/appsignal/hooks/sidekiq.rb b/lib/appsignal/hooks/sidekiq.rb index f78a0839f..62178323e 100644 --- a/lib/appsignal/hooks/sidekiq.rb +++ b/lib/appsignal/hooks/sidekiq.rb @@ -20,7 +20,8 @@ def self.dependencies_present? end def dependencies_present? - self.class.dependencies_present? + self.class.dependencies_present? && Appsignal.config && + Appsignal.config[:instrument_sidekiq] end def install diff --git a/lib/appsignal/transaction.rb b/lib/appsignal/transaction.rb index de328628d..c901c275b 100644 --- a/lib/appsignal/transaction.rb +++ b/lib/appsignal/transaction.rb @@ -329,6 +329,11 @@ def suppress_job_enqueue_events # @!visibility private def job_enqueue_events_suppressed? + # When enqueue instrumentation is disabled, every enqueue integration + # treats its event as suppressed. That is how the config option turns the + # enqueue events off across all integrations at once. + return true if Appsignal.config && !Appsignal.config[:enable_job_enqueue_instrumentation] + store("job_enqueue")[:suppressed] == true end diff --git a/sig/appsignal.rbi b/sig/appsignal.rbi index ac31143d8..35b78c669 100644 --- a/sig/appsignal.rbi +++ b/sig/appsignal.rbi @@ -1182,6 +1182,10 @@ module Appsignal sig { returns(T::Boolean) } attr_accessor :enable_host_metrics + # _@return_ — Configure whether to record an event when a background job is enqueued + sig { returns(T::Boolean) } + attr_accessor :enable_job_enqueue_instrumentation + # _@return_ — Configure whether minutely probes are enabled sig { returns(T::Boolean) } attr_accessor :enable_minutely_probes @@ -1218,6 +1222,18 @@ module Appsignal sig { returns(T::Boolean) } attr_accessor :files_world_accessible + # _@return_ — Configure whether to instrument Active Job + sig { returns(T::Boolean) } + attr_accessor :instrument_active_job + + # _@return_ — Configure whether to instrument Delayed Job + sig { returns(T::Boolean) } + attr_accessor :instrument_delayed_job + + # _@return_ — Configure whether to instrument requests made with the Excon gem + sig { returns(T::Boolean) } + attr_accessor :instrument_excon + # _@return_ — Configure whether to instrument requests made with the Faraday gem sig { returns(T::Boolean) } attr_accessor :instrument_faraday @@ -1226,6 +1242,10 @@ module Appsignal sig { returns(T::Boolean) } attr_accessor :instrument_http_rb + # _@return_ — Configure whether to instrument MongoDB queries + sig { returns(T::Boolean) } + attr_accessor :instrument_mongo + # _@return_ — Configure whether to instrument requests made with Net::HTTP sig { returns(T::Boolean) } attr_accessor :instrument_net_http @@ -1234,14 +1254,30 @@ module Appsignal sig { returns(T::Boolean) } attr_accessor :instrument_ownership + # _@return_ — Configure whether to instrument Que + sig { returns(T::Boolean) } + attr_accessor :instrument_que + # _@return_ — Configure whether to instrument Redis queries sig { returns(T::Boolean) } attr_accessor :instrument_redis + # _@return_ — Configure whether to instrument Resque + sig { returns(T::Boolean) } + attr_accessor :instrument_resque + # _@return_ — Configure whether to instrument Sequel queries sig { returns(T::Boolean) } attr_accessor :instrument_sequel + # _@return_ — Configure whether to instrument Shoryuken + sig { returns(T::Boolean) } + attr_accessor :instrument_shoryuken + + # _@return_ — Configure whether to instrument Sidekiq + sig { returns(T::Boolean) } + attr_accessor :instrument_sidekiq + # _@return_ — Configure whether the Ownership gem instrumentation should set namespace sig { returns(T::Boolean) } attr_accessor :ownership_set_namespace diff --git a/sig/appsignal.rbs b/sig/appsignal.rbs index b2d4a0a91..7e08531b7 100644 --- a/sig/appsignal.rbs +++ b/sig/appsignal.rbs @@ -1105,6 +1105,9 @@ module Appsignal # _@return_ — Configure whether host metrics collection is enabled attr_accessor enable_host_metrics: bool + # _@return_ — Configure whether to record an event when a background job is enqueued + attr_accessor enable_job_enqueue_instrumentation: bool + # _@return_ — Configure whether minutely probes are enabled attr_accessor enable_minutely_probes: bool @@ -1132,24 +1135,48 @@ module Appsignal # _@return_ — Configure whether files created by AppSignal should be world accessible attr_accessor files_world_accessible: bool + # _@return_ — Configure whether to instrument Active Job + attr_accessor instrument_active_job: bool + + # _@return_ — Configure whether to instrument Delayed Job + attr_accessor instrument_delayed_job: bool + + # _@return_ — Configure whether to instrument requests made with the Excon gem + attr_accessor instrument_excon: bool + # _@return_ — Configure whether to instrument requests made with the Faraday gem attr_accessor instrument_faraday: bool # _@return_ — Configure whether to instrument requests made with the http.rb gem attr_accessor instrument_http_rb: bool + # _@return_ — Configure whether to instrument MongoDB queries + attr_accessor instrument_mongo: bool + # _@return_ — Configure whether to instrument requests made with Net::HTTP attr_accessor instrument_net_http: bool # _@return_ — Configure whether to instrument the Ownership gem attr_accessor instrument_ownership: bool + # _@return_ — Configure whether to instrument Que + attr_accessor instrument_que: bool + # _@return_ — Configure whether to instrument Redis queries attr_accessor instrument_redis: bool + # _@return_ — Configure whether to instrument Resque + attr_accessor instrument_resque: bool + # _@return_ — Configure whether to instrument Sequel queries attr_accessor instrument_sequel: bool + # _@return_ — Configure whether to instrument Shoryuken + attr_accessor instrument_shoryuken: bool + + # _@return_ — Configure whether to instrument Sidekiq + attr_accessor instrument_sidekiq: bool + # _@return_ — Configure whether the Ownership gem instrumentation should set namespace attr_accessor ownership_set_namespace: bool diff --git a/spec/integration/diagnose b/spec/integration/diagnose index 1e98e7d5e..8a4bcb7f7 160000 --- a/spec/integration/diagnose +++ b/spec/integration/diagnose @@ -1 +1 @@ -Subproject commit 1e98e7d5ef86f0bf3631d1b45fdfdc86f9ced736 +Subproject commit 8a4bcb7f70090cf8439ad204d366389b88593350 diff --git a/spec/lib/appsignal/config_spec.rb b/spec/lib/appsignal/config_spec.rb index c5a2fb8c7..27d3fa446 100644 --- a/spec/lib/appsignal/config_spec.rb +++ b/spec/lib/appsignal/config_spec.rb @@ -717,6 +717,7 @@ def on_load :enable_gvl_global_timer => false, :enable_gvl_waiting_threads => false, :enable_host_metrics => false, + :enable_job_enqueue_instrumentation => false, :enable_minutely_probes => false, :enable_nginx_metrics => false, :enable_rails_error_reporter => false, @@ -735,13 +736,21 @@ def on_load :ignore_errors => ["ExampleStandardError", "AnotherError"], :ignore_logs => ["^start$", "^Completed 2.* in .*ms (.*)"], :ignore_namespaces => ["admin", "private_namespace"], + :instrument_active_job => false, :instrument_code_ownership => false, + :instrument_delayed_job => false, + :instrument_excon => false, :instrument_faraday => false, :instrument_http_rb => false, + :instrument_mongo => false, :instrument_net_http => false, :instrument_ownership => false, + :instrument_que => false, :instrument_redis => false, + :instrument_resque => false, :instrument_sequel => false, + :instrument_shoryuken => false, + :instrument_sidekiq => false, :log => "file", :log_level => "debug", :log_path => "/tmp/something", @@ -791,6 +800,7 @@ def on_load "APPSIGNAL_ENABLE_GVL_GLOBAL_TIMER" => "false", "APPSIGNAL_ENABLE_GVL_WAITING_THREADS" => "false", "APPSIGNAL_ENABLE_HOST_METRICS" => "false", + "APPSIGNAL_ENABLE_JOB_ENQUEUE_INSTRUMENTATION" => "false", "APPSIGNAL_ENABLE_MINUTELY_PROBES" => "false", "APPSIGNAL_ENABLE_NGINX_METRICS" => "false", "APPSIGNAL_ENABLE_RAILS_ERROR_REPORTER" => "false", @@ -798,13 +808,21 @@ def on_load "APPSIGNAL_ENABLE_RAKE_PERFORMANCE_INSTRUMENTATION" => "false", "APPSIGNAL_ENABLE_STATSD" => "false", "APPSIGNAL_FILES_WORLD_ACCESSIBLE" => "false", + "APPSIGNAL_INSTRUMENT_ACTIVE_JOB" => "false", "APPSIGNAL_INSTRUMENT_CODE_OWNERSHIP" => "false", + "APPSIGNAL_INSTRUMENT_DELAYED_JOB" => "false", + "APPSIGNAL_INSTRUMENT_EXCON" => "false", "APPSIGNAL_INSTRUMENT_FARADAY" => "false", "APPSIGNAL_INSTRUMENT_HTTP_RB" => "false", + "APPSIGNAL_INSTRUMENT_MONGO" => "false", "APPSIGNAL_INSTRUMENT_NET_HTTP" => "false", "APPSIGNAL_INSTRUMENT_OWNERSHIP" => "false", + "APPSIGNAL_INSTRUMENT_QUE" => "false", "APPSIGNAL_INSTRUMENT_REDIS" => "false", + "APPSIGNAL_INSTRUMENT_RESQUE" => "false", "APPSIGNAL_INSTRUMENT_SEQUEL" => "false", + "APPSIGNAL_INSTRUMENT_SHORYUKEN" => "false", + "APPSIGNAL_INSTRUMENT_SIDEKIQ" => "false", "APPSIGNAL_OWNERSHIP_SET_NAMESPACE" => "true", "APPSIGNAL_RUNNING_IN_CONTAINER" => "true", "APPSIGNAL_SEND_ENVIRONMENT_METADATA" => "false", @@ -926,6 +944,7 @@ def on_load :enable_gvl_global_timer => true, :enable_gvl_waiting_threads => true, :enable_host_metrics => true, + :enable_job_enqueue_instrumentation => true, :enable_minutely_probes => true, :enable_statsd => true, :enable_nginx_metrics => false, @@ -941,13 +960,21 @@ def on_load :ignore_errors => [], :ignore_logs => [], :ignore_namespaces => [], + :instrument_active_job => true, :instrument_code_ownership => true, + :instrument_delayed_job => true, + :instrument_excon => true, :instrument_faraday => true, :instrument_http_rb => true, + :instrument_mongo => true, :instrument_net_http => true, :instrument_ownership => true, + :instrument_que => true, :instrument_redis => true, + :instrument_resque => true, :instrument_sequel => true, + :instrument_shoryuken => true, + :instrument_sidekiq => true, :log => "file", :logging_endpoint => "https://appsignal-endpoint.net", :name => "TestApp", diff --git a/spec/lib/appsignal/hooks/activejob_spec.rb b/spec/lib/appsignal/hooks/activejob_spec.rb index 9d2a8e8ff..6a092ac87 100644 --- a/spec/lib/appsignal/hooks/activejob_spec.rb +++ b/spec/lib/appsignal/hooks/activejob_spec.rb @@ -9,7 +9,17 @@ context "when ActiveJob constant is found" do before { stub_const "ActiveJob", Class.new } - it { is_expected.to be_truthy } + context "when Active Job instrumentation is enabled" do + before { configure } + + it { is_expected.to be_truthy } + end + + context "when Active Job instrumentation is disabled" do + before { configure(:options => { :instrument_active_job => false }) } + + it { is_expected.to be_falsy } + end end context "when ActiveJob constant is not found" do @@ -385,6 +395,22 @@ def perform(*_args) expect(suppressed_during_enqueue).to be(true) end end + + context "when enqueue instrumentation is disabled" do + let(:options) { { :enable_job_enqueue_instrumentation => false } } + + it "does not record an enqueue event but still enqueues the job" do + transaction = http_request_transaction + set_current_transaction(transaction) + + ActiveJobTestJob.perform_later + + enqueue_events = + transaction.to_h["events"].select { |event| event["name"] == "enqueue.active_job" } + expect(enqueue_events).to be_empty + expect(ActiveJob::Base.queue_adapter.enqueued_jobs.count).to eq(1) + end + end end context "with params" do diff --git a/spec/lib/appsignal/hooks/delayed_job_spec.rb b/spec/lib/appsignal/hooks/delayed_job_spec.rb index fd448be29..ae6e5e084 100644 --- a/spec/lib/appsignal/hooks/delayed_job_spec.rb +++ b/spec/lib/appsignal/hooks/delayed_job_spec.rb @@ -1,5 +1,6 @@ describe Appsignal::Hooks::DelayedJobHook do context "with delayed job" do + let(:options) { {} } before do stub_const("Delayed::Plugin", Class.new do def self.callbacks @@ -10,6 +11,7 @@ def self.plugins @plugins ||= [] end end) + configure(:options => options) # Install the hook directly rather than through `start_agent`. Hooks # install once per process and are never reset, so relying on # `start_agent` made "adds the plugin" pass only when this spec was the @@ -23,6 +25,12 @@ def self.plugins subject { described_class.new.dependencies_present? } it { is_expected.to be_truthy } + + context "when Delayed Job instrumentation is disabled" do + let(:options) { { :instrument_delayed_job => false } } + + it { is_expected.to be_falsy } + end end it "adds the plugin" do diff --git a/spec/lib/appsignal/hooks/excon_spec.rb b/spec/lib/appsignal/hooks/excon_spec.rb index bf18e522a..4052faf3f 100644 --- a/spec/lib/appsignal/hooks/excon_spec.rb +++ b/spec/lib/appsignal/hooks/excon_spec.rb @@ -1,5 +1,6 @@ describe Appsignal::Hooks::ExconHook do - before { start_agent } + let(:options) { {} } + before { start_agent(:options => options) } context "with Excon" do before do @@ -15,6 +16,12 @@ def self.defaults subject { described_class.new.dependencies_present? } it { is_expected.to be_truthy } + + context "when Excon instrumentation is disabled" do + let(:options) { { :instrument_excon => false } } + + it { is_expected.to be_falsy } + end end describe "#install" do diff --git a/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb b/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb index 9c9a78df8..32e3f75a4 100644 --- a/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +++ b/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb @@ -2,6 +2,7 @@ require "appsignal/integrations/mongo_ruby_driver" context "with mongo ruby driver" do + let(:options) { {} } let(:subscriber) { Appsignal::Hooks::MongoMonitorSubscriber.new } before do allow(Appsignal::Hooks::MongoMonitorSubscriber).to receive(:new).and_return(subscriber) @@ -14,12 +15,19 @@ def subscribe end end) + configure(:options => options) end describe "#dependencies_present?" do subject { described_class.new.dependencies_present? } it { is_expected.to be_truthy } + + context "when MongoDB instrumentation is disabled" do + let(:options) { { :instrument_mongo => false } } + + it { is_expected.to be_falsy } + end end it "adds a subscriber to Mongo::Monitoring" do diff --git a/spec/lib/appsignal/hooks/que_spec.rb b/spec/lib/appsignal/hooks/que_spec.rb index 503c71c4b..8bd1647ea 100644 --- a/spec/lib/appsignal/hooks/que_spec.rb +++ b/spec/lib/appsignal/hooks/que_spec.rb @@ -3,7 +3,17 @@ describe "#dependencies_present?" do subject { described_class.new.dependencies_present? } - it { is_expected.to be_truthy } + context "when Que instrumentation is enabled" do + before { configure } + + it { is_expected.to be_truthy } + end + + context "when Que instrumentation is disabled" do + before { configure(:options => { :instrument_que => false }) } + + it { is_expected.to be_falsy } + end end it "installs the QuePlugin" do diff --git a/spec/lib/appsignal/hooks/resque_spec.rb b/spec/lib/appsignal/hooks/resque_spec.rb index 9ca5badb6..5cac30875 100644 --- a/spec/lib/appsignal/hooks/resque_spec.rb +++ b/spec/lib/appsignal/hooks/resque_spec.rb @@ -5,7 +5,17 @@ context "when Resque is loaded" do before { stub_const "Resque", 1 } - it { is_expected.to be_truthy } + context "when Resque instrumentation is enabled" do + before { configure } + + it { is_expected.to be_truthy } + end + + context "when Resque instrumentation is disabled" do + before { configure(:options => { :instrument_resque => false }) } + + it { is_expected.to be_falsy } + end end context "when Resque is not loaded" do diff --git a/spec/lib/appsignal/hooks/shoryuken_spec.rb b/spec/lib/appsignal/hooks/shoryuken_spec.rb index 3ccf6ff20..bcefc89e7 100644 --- a/spec/lib/appsignal/hooks/shoryuken_spec.rb +++ b/spec/lib/appsignal/hooks/shoryuken_spec.rb @@ -1,5 +1,6 @@ describe Appsignal::Hooks::ShoryukenHook do context "with shoryuken" do + let(:options) { {} } before do stub_const("Shoryuken", Module.new do def self.configure_server @@ -8,6 +9,7 @@ def self.configure_server def self.configure_client end end) + configure(:options => options) Appsignal::Hooks::ShoryukenHook.new.install end @@ -15,6 +17,12 @@ def self.configure_client subject { described_class.new.dependencies_present? } it { is_expected.to be_truthy } + + context "when Shoryuken instrumentation is disabled" do + let(:options) { { :instrument_shoryuken => false } } + + it { is_expected.to be_falsy } + end end end diff --git a/spec/lib/appsignal/hooks/sidekiq_spec.rb b/spec/lib/appsignal/hooks/sidekiq_spec.rb index 7a2ab9c27..c374aca33 100644 --- a/spec/lib/appsignal/hooks/sidekiq_spec.rb +++ b/spec/lib/appsignal/hooks/sidekiq_spec.rb @@ -5,7 +5,17 @@ context "when Sidekiq constant is found" do before { stub_const "Sidekiq", Class.new } - it { is_expected.to be_truthy } + context "when Sidekiq instrumentation is enabled" do + before { configure } + + it { is_expected.to be_truthy } + end + + context "when Sidekiq instrumentation is disabled" do + before { configure(:options => { :instrument_sidekiq => false }) } + + it { is_expected.to be_falsy } + end end context "when Sidekiq constant is not found" do diff --git a/spec/lib/appsignal/transaction_spec.rb b/spec/lib/appsignal/transaction_spec.rb index d3ab930dd..eae3aed2d 100644 --- a/spec/lib/appsignal/transaction_spec.rb +++ b/spec/lib/appsignal/transaction_spec.rb @@ -716,6 +716,22 @@ end end + describe "#job_enqueue_events_suppressed?" do + let(:transaction) { new_transaction } + + it "is not suppressed by default" do + expect(transaction.job_enqueue_events_suppressed?).to be(false) + end + + context "when enqueue instrumentation is disabled" do + let(:options) { { :enable_job_enqueue_instrumentation => false } } + + it "reports enqueue events as suppressed" do + expect(transaction.job_enqueue_events_suppressed?).to be(true) + end + end + end + describe "#add_params" do let(:transaction) { new_transaction }