appsignal 2.11.0.alpha.2-java → 2.11.0.beta.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/.semaphore/semaphore.yml +37 -9
  4. data/CHANGELOG.md +10 -1
  5. data/build_matrix.yml +5 -1
  6. data/gemfiles/rails-4.2.gemfile +9 -2
  7. data/gemfiles/rails-5.0.gemfile +1 -0
  8. data/gemfiles/rails-5.1.gemfile +1 -0
  9. data/gemfiles/rails-5.2.gemfile +1 -0
  10. data/gemfiles/rails-6.0.gemfile +1 -0
  11. data/gemfiles/resque-1.gemfile +7 -0
  12. data/gemfiles/{resque.gemfile → resque-2.gemfile} +1 -1
  13. data/lib/appsignal/hooks.rb +2 -0
  14. data/lib/appsignal/hooks/active_job.rb +89 -0
  15. data/lib/appsignal/hooks/resque.rb +60 -0
  16. data/lib/appsignal/hooks/sidekiq.rb +16 -92
  17. data/lib/appsignal/integrations/que.rb +1 -1
  18. data/lib/appsignal/integrations/resque.rb +9 -12
  19. data/lib/appsignal/integrations/resque_active_job.rb +9 -32
  20. data/lib/appsignal/transaction.rb +10 -0
  21. data/lib/appsignal/utils/deprecation_message.rb +5 -1
  22. data/lib/appsignal/version.rb +1 -1
  23. data/spec/lib/appsignal/hooks/activejob_spec.rb +458 -0
  24. data/spec/lib/appsignal/hooks/resque_spec.rb +185 -0
  25. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +215 -263
  26. data/spec/lib/appsignal/integrations/que_spec.rb +25 -6
  27. data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +20 -179
  28. data/spec/lib/appsignal/integrations/resque_spec.rb +20 -85
  29. data/spec/lib/appsignal/probes/sidekiq_spec.rb +10 -7
  30. data/spec/lib/appsignal/transaction_spec.rb +5 -7
  31. data/spec/support/helpers/action_mailer_helpers.rb +25 -0
  32. data/spec/support/helpers/dependency_helper.rb +9 -2
  33. data/spec/support/helpers/transaction_helpers.rb +6 -0
  34. data/spec/support/stubs/sidekiq/api.rb +1 -1
  35. metadata +12 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a510cdd0af6ef1f3780e5d559a41762d7d2b094fb5309d0e10d143b223e76fb
4
- data.tar.gz: d7195e855b5a2ea44db9cfdd9c132dfb2afda1994bc4c7c8aba08181f47081d8
3
+ metadata.gz: e3403327daac577742fc279cc704c58cc766e64e71995d2206cdefa104512993
4
+ data.tar.gz: 638b4104fc2ac814a28b98ff9de32a675531fed3e6d451adb3dc996551e52458
5
5
  SHA512:
6
- metadata.gz: bcf0aa5c31a43142fb264dab678ae2b19896d2b1618ae3caf6fbacfff67c3fd46c62c87f062968a92ca93abfc88f159d7c849ca03862c661fd5540112b2a5b9a
7
- data.tar.gz: 9eb9618c8cb83f87db2b183573e64313a6fe01651bf2f5e93b748347de38e64716053ba7dcf42ce9a2954caa1c3e2096153acb37543a49cfe4c069afe7e8c705
6
+ metadata.gz: 2c51e569187ea8f8fa5d99b237c22d4ad14472527329d78463ef2c12d59cb4abce350398ead4a22e8358378eb0d12ee67fd84808c5e91c30c1e0464368b42990
7
+ data.tar.gz: 4c822a8d331d632f2fc47c06e0823092b29605e1b1f4070a978edd78f5feb4896bedc17d59437fe8b382757d93cf676fa40af0775a98ec53df6227a659cc5282
@@ -64,6 +64,9 @@ Style/Encoding: # For Ruby 1.9 as it doesn't default to UTF-8
64
64
  Style/Lambda:
65
65
  EnforcedStyle: lambda
66
66
 
67
+ Style/WordArray:
68
+ Enabled: false
69
+
67
70
  Naming/FileName:
68
71
  Exclude:
69
72
  - "ext/Rakefile"
@@ -214,14 +214,14 @@ blocks:
214
214
  value: 1.17.3
215
215
  commands:
216
216
  - "./support/bundler_wrapper exec rake test"
217
- - name: Ruby 2.0.0-p648 for resque
217
+ - name: Ruby 2.0.0-p648 for resque-1
218
218
  env_vars:
219
219
  - name: RUBY_VERSION
220
220
  value: 2.0.0-p648
221
221
  - name: GEMSET
222
- value: resque
222
+ value: resque-1
223
223
  - name: BUNDLE_GEMFILE
224
- value: gemfiles/resque.gemfile
224
+ value: gemfiles/resque-1.gemfile
225
225
  - name: _RUBYGEMS_VERSION
226
226
  value: 2.7.8
227
227
  - name: _BUNDLER_VERSION
@@ -600,20 +600,34 @@ blocks:
600
600
  value: latest
601
601
  commands:
602
602
  - "./support/bundler_wrapper exec rake test"
603
- - name: Ruby 2.6.5 for resque
603
+ - name: Ruby 2.6.5 for resque-1
604
604
  env_vars:
605
605
  - name: RUBY_VERSION
606
606
  value: 2.6.5
607
607
  - name: GEMSET
608
- value: resque
608
+ value: resque-1
609
609
  - name: BUNDLE_GEMFILE
610
- value: gemfiles/resque.gemfile
610
+ value: gemfiles/resque-1.gemfile
611
611
  - name: _RUBYGEMS_VERSION
612
612
  value: latest
613
613
  - name: _BUNDLER_VERSION
614
614
  value: 1.17.3
615
615
  commands:
616
616
  - "./support/bundler_wrapper exec rake test"
617
+ - name: Ruby 2.6.5 for resque-2
618
+ env_vars:
619
+ - name: RUBY_VERSION
620
+ value: 2.6.5
621
+ - name: GEMSET
622
+ value: resque-2
623
+ - name: BUNDLE_GEMFILE
624
+ value: gemfiles/resque-2.gemfile
625
+ - name: _RUBYGEMS_VERSION
626
+ value: latest
627
+ - name: _BUNDLER_VERSION
628
+ value: latest
629
+ commands:
630
+ - "./support/bundler_wrapper exec rake test"
617
631
  - name: Ruby 2.6.5 for sequel
618
632
  env_vars:
619
633
  - name: RUBY_VERSION
@@ -840,20 +854,34 @@ blocks:
840
854
  value: latest
841
855
  commands:
842
856
  - "./support/bundler_wrapper exec rake test"
843
- - name: Ruby 2.7.1 for resque
857
+ - name: Ruby 2.7.1 for resque-1
844
858
  env_vars:
845
859
  - name: RUBY_VERSION
846
860
  value: 2.7.1
847
861
  - name: GEMSET
848
- value: resque
862
+ value: resque-1
849
863
  - name: BUNDLE_GEMFILE
850
- value: gemfiles/resque.gemfile
864
+ value: gemfiles/resque-1.gemfile
851
865
  - name: _RUBYGEMS_VERSION
852
866
  value: latest
853
867
  - name: _BUNDLER_VERSION
854
868
  value: 1.17.3
855
869
  commands:
856
870
  - "./support/bundler_wrapper exec rake test"
871
+ - name: Ruby 2.7.1 for resque-2
872
+ env_vars:
873
+ - name: RUBY_VERSION
874
+ value: 2.7.1
875
+ - name: GEMSET
876
+ value: resque-2
877
+ - name: BUNDLE_GEMFILE
878
+ value: gemfiles/resque-2.gemfile
879
+ - name: _RUBYGEMS_VERSION
880
+ value: latest
881
+ - name: _BUNDLER_VERSION
882
+ value: latest
883
+ commands:
884
+ - "./support/bundler_wrapper exec rake test"
857
885
  - name: Ruby 2.7.1 for sequel
858
886
  env_vars:
859
887
  - name: RUBY_VERSION
@@ -3,8 +3,17 @@
3
3
  # 2.11.0
4
4
  - Track queue time regardless of namespace. Support custom namespaces. PR #602
5
5
  - Improve deprecation message from frontend error middleware. PR #620
6
- - Report Ruby environment metadata. PR #621, #627
6
+ - Report Ruby environment metadata. PR #621, #627, #619, #618
7
7
  - Refactor: Move minutely probes to their own files and modules. PR #623
8
+ - Allow custom action names in Que integration. Needed for Active Job
9
+ integration. PR #628
10
+ - Add Active Job support. Support Active Job without separate AppSignal
11
+ integration of the background job library. Add support for previously
12
+ unsupported Active Job adapters. Adapters that were previously already
13
+ supported (Sidekiq, DelayedJob and Resque) still work in this new setup.
14
+ PR #629
15
+ - Add automatic Resque integration. Remove manual Resque and Resque Active Job
16
+ integrations. PR #630
8
17
 
9
18
  # 2.10.9
10
19
  - Use http proxy if configured when downloading agent. PR #606
@@ -165,8 +165,12 @@ matrix:
165
165
  - "2.3.8"
166
166
  - "2.4.9"
167
167
  - "jruby-9.1.17.0"
168
- - gem: "resque"
168
+ - gem: "resque-1"
169
169
  bundler: "1.17.3"
170
+ - gem: "resque-2"
171
+ exclude:
172
+ ruby:
173
+ - "2.0.0-p648"
170
174
  - gem: "sequel"
171
175
  - gem: "sequel-435"
172
176
  - gem: "sinatra"
@@ -3,8 +3,15 @@ source 'https://rubygems.org'
3
3
  gem 'rails', '~> 4.2.0'
4
4
  gem 'mime-types', '~> 2.6'
5
5
 
6
- gemspec :path => '../'
6
+ ruby_version = Gem::Version.new(RUBY_VERSION)
7
+ if ruby_version < Gem::Version.new("2.3.0")
8
+ gem "sidekiq", "~> 4.0"
9
+ else
10
+ gem "sidekiq"
11
+ end
7
12
 
8
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.1.0")
13
+ if ruby_version < Gem::Version.new("2.1.0")
9
14
  gem 'nokogiri', '~> 1.6.0'
10
15
  end
16
+
17
+ gemspec :path => '../'
@@ -1,5 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'rails', '~> 5.0.0'
4
+ gem "sidekiq"
4
5
 
5
6
  gemspec :path => '../'
@@ -1,5 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'rails', '~> 5.1.0'
4
+ gem "sidekiq"
4
5
 
5
6
  gemspec :path => '../'
@@ -1,5 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'rails', '~> 5.2.0'
4
+ gem "sidekiq"
4
5
 
5
6
  gemspec :path => '../'
@@ -1,5 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'rails', '~> 6.0.0'
4
+ gem "sidekiq"
4
5
 
5
6
  gemspec :path => '../'
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'resque', "~> 1.27.0"
4
+ gem 'sinatra'
5
+ gem 'mime-types', '~> 2.6'
6
+
7
+ gemspec :path => '../'
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'resque'
3
+ gem 'resque', "~> 2.0"
4
4
  gem 'sinatra'
5
5
  gem 'mime-types', '~> 2.6'
6
6
 
@@ -73,6 +73,7 @@ module Appsignal
73
73
  end
74
74
 
75
75
  require "appsignal/hooks/action_cable"
76
+ require "appsignal/hooks/active_job"
76
77
  require "appsignal/hooks/active_support_notifications"
77
78
  require "appsignal/hooks/celluloid"
78
79
  require "appsignal/hooks/delayed_job"
@@ -81,6 +82,7 @@ require "appsignal/hooks/passenger"
81
82
  require "appsignal/hooks/puma"
82
83
  require "appsignal/hooks/rake"
83
84
  require "appsignal/hooks/redis"
85
+ require "appsignal/hooks/resque"
84
86
  require "appsignal/hooks/sequel"
85
87
  require "appsignal/hooks/shoryuken"
86
88
  require "appsignal/hooks/sidekiq"
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ class Hooks
5
+ # @api private
6
+ class ActiveJobHook < Appsignal::Hooks::Hook
7
+ register :active_job
8
+
9
+ def dependencies_present?
10
+ defined?(::ActiveJob)
11
+ end
12
+
13
+ def install
14
+ ::ActiveJob::Base
15
+ .extend ::Appsignal::Hooks::ActiveJobHook::ActiveJobClassInstrumentation
16
+ end
17
+
18
+ # @todo Add queue time support for Rails 6's enqueued_at. For both
19
+ # existing and new transactions.
20
+ module ActiveJobClassInstrumentation
21
+ def execute(job)
22
+ current_transaction = Appsignal::Transaction.current
23
+ transaction =
24
+ if current_transaction.nil_transaction?
25
+ # No standalone integration started before ActiveJob integration.
26
+ # We don't have a separate integration for this QueueAdapter like
27
+ # we do for Sidekiq.
28
+ #
29
+ # Prefer job_id from provider, instead of ActiveJob's internal ID.
30
+ Appsignal::Transaction.create(
31
+ job["provider_job_id"] || job["job_id"],
32
+ Appsignal::Transaction::BACKGROUND_JOB,
33
+ Appsignal::Transaction::GenericRequest.new({})
34
+ )
35
+ else
36
+ current_transaction
37
+ end
38
+
39
+ super
40
+ rescue Exception => exception # rubocop:disable Lint/RescueException
41
+ transaction.set_error(exception)
42
+ raise exception
43
+ ensure
44
+ if transaction
45
+ transaction.params =
46
+ Appsignal::Utils::HashSanitizer.sanitize(
47
+ job["arguments"],
48
+ Appsignal.config[:filter_parameters]
49
+ )
50
+
51
+ tags = { :queue => job["queue_name"] }
52
+ provider_job_id = job["provider_job_id"]
53
+ tags[:provider_job_id] = provider_job_id if provider_job_id
54
+ transaction.set_tags(tags)
55
+
56
+ transaction.set_action_if_nil(ActiveJobHelpers.action_name(job))
57
+ enqueued_at = job["enqueued_at"]
58
+ if enqueued_at # Present in Rails 6 and up
59
+ transaction.set_queue_start((Time.parse(enqueued_at).to_f * 1_000).to_i)
60
+ end
61
+
62
+ if current_transaction.nil_transaction?
63
+ # Only complete transaction if ActiveJob is not wrapped in
64
+ # another supported integration, such as Sidekiq.
65
+ Appsignal::Transaction.complete_current!
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ module ActiveJobHelpers
72
+ ACTION_MAILER_CLASSES = [
73
+ "ActionMailer::DeliveryJob",
74
+ "ActionMailer::Parameterized::DeliveryJob",
75
+ "ActionMailer::MailDeliveryJob"
76
+ ].freeze
77
+
78
+ def self.action_name(job)
79
+ case job["job_class"]
80
+ when *ACTION_MAILER_CLASSES
81
+ job["arguments"][0..1].join("#")
82
+ else
83
+ "#{job["job_class"]}#perform"
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ class Hooks
5
+ # @api private
6
+ class ResqueHook < Appsignal::Hooks::Hook
7
+ register :resque
8
+
9
+ def dependencies_present?
10
+ defined?(::Resque)
11
+ end
12
+
13
+ def install
14
+ Resque::Job.class_eval do
15
+ alias_method :perform_without_appsignal, :perform
16
+
17
+ def perform
18
+ transaction = Appsignal::Transaction.create(
19
+ SecureRandom.uuid,
20
+ Appsignal::Transaction::BACKGROUND_JOB,
21
+ Appsignal::Transaction::GenericRequest.new({})
22
+ )
23
+
24
+ Appsignal.instrument "perform.resque" do
25
+ perform_without_appsignal
26
+ end
27
+ rescue Exception => exception # rubocop:disable Lint/RescueException
28
+ transaction.set_error(exception)
29
+ raise exception
30
+ ensure
31
+ if transaction
32
+ transaction.set_action_if_nil("#{payload["class"]}#perform")
33
+ args =
34
+ Appsignal::Utils::HashSanitizer.sanitize(
35
+ ResqueHelpers.arguments(payload),
36
+ Appsignal.config[:filter_parameters]
37
+ )
38
+ transaction.params = args if args
39
+ transaction.set_tags("queue" => queue)
40
+
41
+ Appsignal::Transaction.complete_current!
42
+ end
43
+ Appsignal.stop("resque")
44
+ end
45
+ end
46
+ end
47
+
48
+ class ResqueHelpers
49
+ def self.arguments(payload)
50
+ case payload["class"]
51
+ when "ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper"
52
+ nil # Set in the ActiveJob integration
53
+ else
54
+ payload["args"]
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -27,8 +27,7 @@ module Appsignal
27
27
  class SidekiqPlugin # rubocop:disable Metrics/ClassLength
28
28
  include Appsignal::Hooks::Helpers
29
29
 
30
- UNKNOWN_ACTION_NAME = "unknown".freeze
31
- JOB_KEYS = %w[
30
+ EXCLUDED_JOB_KEYS = %w[
32
31
  args backtrace class created_at enqueued_at error_backtrace error_class
33
32
  error_message failed_at jid retried_at retry wrapped
34
33
  ].freeze
@@ -55,7 +54,10 @@ module Appsignal
55
54
  ensure
56
55
  if transaction
57
56
  transaction.set_action_if_nil(formatted_action_name(item))
58
- transaction.params = filtered_arguments(item)
57
+
58
+ params = filtered_arguments(item)
59
+ transaction.params = params if params
60
+
59
61
  formatted_metadata(item).each do |key, value|
60
62
  transaction.set_metadata key, value
61
63
  end
@@ -81,16 +83,20 @@ module Appsignal
81
83
 
82
84
  def formatted_action_name(job)
83
85
  sidekiq_action_name = parse_action_name(job)
86
+ return unless sidekiq_action_name
87
+
84
88
  complete_action = sidekiq_action_name =~ /\.|#/
85
- if complete_action || sidekiq_action_name == UNKNOWN_ACTION_NAME
86
- return sidekiq_action_name
87
- end
89
+ return sidekiq_action_name if complete_action
90
+
88
91
  "#{sidekiq_action_name}#perform"
89
92
  end
90
93
 
91
94
  def filtered_arguments(job)
95
+ arguments = parse_arguments(job)
96
+ return unless arguments
97
+
92
98
  Appsignal::Utils::HashSanitizer.sanitize(
93
- parse_arguments(job),
99
+ arguments,
94
100
  Appsignal.config[:filter_parameters]
95
101
  )
96
102
  end
@@ -98,7 +104,8 @@ module Appsignal
98
104
  def formatted_metadata(item)
99
105
  {}.tap do |hash|
100
106
  (item || {}).each do |key, value|
101
- next if JOB_KEYS.include?(key)
107
+ next if EXCLUDED_JOB_KEYS.include?(key)
108
+
102
109
  hash[key] = truncate(string_or_inspect(value))
103
110
  end
104
111
  end
@@ -117,81 +124,11 @@ module Appsignal
117
124
  safe_load(args[0], job_class) do |target, method, _|
118
125
  "#{target}.#{method}"
119
126
  end
120
- when "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
121
- wrapped_job = job["wrapped"]
122
- if wrapped_job
123
- parse_active_job_action_name_from_wrapped job
124
- else
125
- parse_active_job_action_name_from_arguments job
126
- end
127
127
  else
128
128
  job_class
129
129
  end
130
130
  end
131
131
 
132
- # Return the ActiveJob wrapped job name.
133
- #
134
- # Returns "unknown" if no acceptable job class name could be found.
135
- #
136
- # @example Payload with "wrapped" value
137
- # {
138
- # "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
139
- # "wrapped" => "MyWrappedJob",
140
- # # ...
141
- # }
142
- def parse_active_job_action_name_from_wrapped(job)
143
- job_class = job["wrapped"]
144
- case job_class
145
- when "ActionMailer::DeliveryJob"
146
- extract_action_mailer_name job["args"]
147
- when String
148
- job_class
149
- else
150
- unknown_action_name_for job
151
- end
152
- end
153
-
154
- # Return the ActiveJob job name based on the job's arguments.
155
- #
156
- # Returns "unknown" if no acceptable job class name could be found.
157
- #
158
- # @example Payload without "wrapped" value
159
- # {
160
- # "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
161
- # "args" => [{
162
- # "job_class" => "MyWrappedJob",
163
- # # ...
164
- # }]
165
- # # ...
166
- # }
167
- def parse_active_job_action_name_from_arguments(job)
168
- args = job.fetch("args", [])
169
- first_arg = args[0]
170
- if first_arg == "ActionMailer::DeliveryJob"
171
- extract_action_mailer_name args
172
- elsif active_job_payload?(first_arg)
173
- first_arg["job_class"]
174
- else
175
- unknown_action_name_for job
176
- end
177
- end
178
-
179
- # Checks if the first argument in the job payload is an ActiveJob payload.
180
- def active_job_payload?(arg)
181
- arg.is_a?(Hash) && arg["job_class"].is_a?(String)
182
- end
183
-
184
- def unknown_action_name_for(job)
185
- Appsignal.logger.debug \
186
- "Unable to determine an action name from Sidekiq payload: #{job}"
187
- UNKNOWN_ACTION_NAME
188
- end
189
-
190
- def extract_action_mailer_name(args)
191
- # Returns in format: MailerClass#mailer_method
192
- args[0]["arguments"][0..1].join("#")
193
- end
194
-
195
132
  # Based on: https://github.com/mperham/sidekiq/blob/63ee43353bd3b753beb0233f64865e658abeb1c3/lib/sidekiq/api.rb#L336-L358
196
133
  def parse_arguments(job)
197
134
  args = job.fetch("args", [])
@@ -201,20 +138,7 @@ module Appsignal
201
138
  arg
202
139
  end
203
140
  when "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
204
- is_wrapped = job["wrapped"]
205
- first_arg = args[0]
206
- job_args =
207
- if is_wrapped || active_job_payload?(first_arg)
208
- first_arg["arguments"]
209
- else
210
- []
211
- end
212
- if (is_wrapped || first_arg) == "ActionMailer::DeliveryJob"
213
- # Remove MailerClass, mailer_method and "deliver_now"
214
- job_args.drop(3)
215
- else
216
- job_args
217
- end
141
+ nil # Set in the ActiveJob integration
218
142
  else
219
143
  # Sidekiq Enterprise argument encryption.
220
144
  # More information: https://github.com/mperham/sidekiq/wiki/Ent-Encryption