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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/.semaphore/semaphore.yml +75 -61
  4. data/CHANGELOG.md +21 -1
  5. data/build_matrix.yml +13 -7
  6. data/ext/agent.yml +19 -19
  7. data/gemfiles/padrino.gemfile +2 -2
  8. data/gemfiles/rails-4.2.gemfile +9 -2
  9. data/gemfiles/rails-5.0.gemfile +1 -0
  10. data/gemfiles/rails-5.1.gemfile +1 -0
  11. data/gemfiles/rails-5.2.gemfile +1 -0
  12. data/gemfiles/rails-6.0.gemfile +1 -0
  13. data/gemfiles/resque-1.gemfile +7 -0
  14. data/gemfiles/{resque.gemfile → resque-2.gemfile} +1 -1
  15. data/lib/appsignal/hooks.rb +2 -0
  16. data/lib/appsignal/hooks/active_job.rb +114 -0
  17. data/lib/appsignal/hooks/puma.rb +2 -58
  18. data/lib/appsignal/hooks/resque.rb +60 -0
  19. data/lib/appsignal/hooks/sidekiq.rb +19 -192
  20. data/lib/appsignal/integrations/delayed_job_plugin.rb +1 -1
  21. data/lib/appsignal/integrations/que.rb +1 -1
  22. data/lib/appsignal/integrations/resque.rb +9 -12
  23. data/lib/appsignal/integrations/resque_active_job.rb +9 -32
  24. data/lib/appsignal/probes/puma.rb +61 -0
  25. data/lib/appsignal/probes/sidekiq.rb +102 -0
  26. data/lib/appsignal/rack/js_exception_catcher.rb +5 -2
  27. data/lib/appsignal/transaction.rb +10 -0
  28. data/lib/appsignal/utils/deprecation_message.rb +5 -1
  29. data/lib/appsignal/version.rb +1 -1
  30. data/lib/puma/plugin/appsignal.rb +2 -1
  31. data/spec/lib/appsignal/hooks/activejob_spec.rb +548 -0
  32. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +3 -14
  33. data/spec/lib/appsignal/hooks/puma_spec.rb +2 -181
  34. data/spec/lib/appsignal/hooks/resque_spec.rb +185 -0
  35. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +297 -549
  36. data/spec/lib/appsignal/integrations/padrino_spec.rb +1 -1
  37. data/spec/lib/appsignal/integrations/que_spec.rb +25 -6
  38. data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +20 -179
  39. data/spec/lib/appsignal/integrations/resque_spec.rb +20 -85
  40. data/spec/lib/appsignal/probes/puma_spec.rb +180 -0
  41. data/spec/lib/appsignal/probes/sidekiq_spec.rb +204 -0
  42. data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +9 -4
  43. data/spec/lib/appsignal/transaction_spec.rb +5 -7
  44. data/spec/lib/puma/appsignal_spec.rb +1 -1
  45. data/spec/support/helpers/action_mailer_helpers.rb +25 -0
  46. data/spec/support/helpers/dependency_helper.rb +9 -2
  47. data/spec/support/helpers/transaction_helpers.rb +6 -0
  48. data/spec/support/stubs/sidekiq/api.rb +2 -2
  49. metadata +18 -3
@@ -0,0 +1,204 @@
1
+ require "appsignal/probes/sidekiq"
2
+
3
+ describe Appsignal::Probes::SidekiqProbe do
4
+ describe "#call" do
5
+ let(:probe) { described_class.new }
6
+ let(:redis_hostname) { "localhost" }
7
+ let(:expected_default_tags) { { :hostname => "localhost" } }
8
+ before do
9
+ Appsignal.config = project_fixture_config
10
+ module SidekiqMock
11
+ def self.redis_info
12
+ {
13
+ "connected_clients" => 2,
14
+ "used_memory" => 1024,
15
+ "used_memory_rss" => 512
16
+ }
17
+ end
18
+
19
+ def self.redis
20
+ yield Client.new
21
+ end
22
+
23
+ class Client
24
+ def connection
25
+ { :host => "localhost" }
26
+ end
27
+ end
28
+
29
+ class Stats
30
+ class << self
31
+ attr_reader :calls
32
+
33
+ def count_call
34
+ @calls ||= -1
35
+ @calls += 1
36
+ end
37
+ end
38
+
39
+ def workers_size
40
+ # First method called, so count it towards a call
41
+ self.class.count_call
42
+ 24
43
+ end
44
+
45
+ def processes_size
46
+ 25
47
+ end
48
+
49
+ # Return two different values for two separate calls.
50
+ # This allows us to test the delta of the value send as a gauge.
51
+ def processed
52
+ [10, 15][self.class.calls]
53
+ end
54
+
55
+ # Return two different values for two separate calls.
56
+ # This allows us to test the delta of the value send as a gauge.
57
+ def failed
58
+ [10, 13][self.class.calls]
59
+ end
60
+
61
+ def retry_size
62
+ 12
63
+ end
64
+
65
+ # Return two different values for two separate calls.
66
+ # This allows us to test the delta of the value send as a gauge.
67
+ def dead_size
68
+ [10, 12][self.class.calls]
69
+ end
70
+
71
+ def scheduled_size
72
+ 14
73
+ end
74
+
75
+ def enqueued
76
+ 15
77
+ end
78
+ end
79
+
80
+ class Queue
81
+ Queue = Struct.new(:name, :size, :latency)
82
+
83
+ def self.all
84
+ [
85
+ Queue.new("default", 10, 12),
86
+ Queue.new("critical", 1, 2)
87
+ ]
88
+ end
89
+ end
90
+ end
91
+ stub_const("Sidekiq", SidekiqMock)
92
+ end
93
+ after { Object.send(:remove_const, :SidekiqMock) }
94
+
95
+ describe ".dependencies_present?" do
96
+ before do
97
+ stub_const("Redis::VERSION", version)
98
+ end
99
+
100
+ context "when Redis version is < 3.3.5" do
101
+ let(:version) { "3.3.4" }
102
+
103
+ it "does not start probe" do
104
+ expect(described_class.dependencies_present?).to be_falsy
105
+ end
106
+ end
107
+
108
+ context "when Redis version is >= 3.3.5" do
109
+ let(:version) { "3.3.5" }
110
+
111
+ it "does not start probe" do
112
+ expect(described_class.dependencies_present?).to be_truthy
113
+ end
114
+ end
115
+ end
116
+
117
+ it "loads Sidekiq::API" do
118
+ # Hide the Sidekiq constant if it was already loaded. It will be
119
+ # redefined by loading "sidekiq/api" in the probe.
120
+ hide_const "Sidekiq::Stats"
121
+
122
+ expect(defined?(Sidekiq::Stats)).to be_falsy
123
+ probe
124
+ expect(defined?(Sidekiq::Stats)).to be_truthy
125
+ end
126
+
127
+ it "logs config on initialize" do
128
+ log = capture_logs { probe }
129
+ expect(log).to contains_log(:debug, "Initializing Sidekiq probe\n")
130
+ end
131
+
132
+ it "logs used hostname on call once" do
133
+ log = capture_logs { probe.call }
134
+ expect(log).to contains_log(
135
+ :debug,
136
+ %(Sidekiq probe: Using Redis server hostname "localhost" as hostname)
137
+ )
138
+ log = capture_logs { probe.call }
139
+ # Match more logs with incompelete message
140
+ expect(log).to_not contains_log(:debug, %(Sidekiq probe: ))
141
+ end
142
+
143
+ it "collects custom metrics" do
144
+ expect_gauge("worker_count", 24).twice
145
+ expect_gauge("process_count", 25).twice
146
+ expect_gauge("connection_count", 2).twice
147
+ expect_gauge("memory_usage", 1024).twice
148
+ expect_gauge("memory_usage_rss", 512).twice
149
+ expect_gauge("job_count", 5, :status => :processed) # Gauge delta
150
+ expect_gauge("job_count", 3, :status => :failed) # Gauge delta
151
+ expect_gauge("job_count", 12, :status => :retry_queue).twice
152
+ expect_gauge("job_count", 2, :status => :died) # Gauge delta
153
+ expect_gauge("job_count", 14, :status => :scheduled).twice
154
+ expect_gauge("job_count", 15, :status => :enqueued).twice
155
+ expect_gauge("queue_length", 10, :queue => "default").twice
156
+ expect_gauge("queue_latency", 12_000, :queue => "default").twice
157
+ expect_gauge("queue_length", 1, :queue => "critical").twice
158
+ expect_gauge("queue_latency", 2_000, :queue => "critical").twice
159
+ # Call probe twice so we can calculate the delta for some gauge values
160
+ probe.call
161
+ probe.call
162
+ end
163
+
164
+ context "when `redis_info` is not defined" do
165
+ before do
166
+ allow(Sidekiq).to receive(:respond_to?).with(:redis_info).and_return(false)
167
+ end
168
+
169
+ it "does not collect redis metrics" do
170
+ expect_gauge("connection_count", 2).never
171
+ expect_gauge("memory_usage", 1024).never
172
+ expect_gauge("memory_usage_rss", 512).never
173
+ probe.call
174
+ end
175
+ end
176
+
177
+ context "when hostname is configured for probe" do
178
+ let(:redis_hostname) { "my_redis_server" }
179
+ let(:probe) { described_class.new(:hostname => redis_hostname) }
180
+
181
+ it "uses the redis hostname for the hostname tag" do
182
+ allow(Appsignal).to receive(:set_gauge).and_call_original
183
+ log = capture_logs { probe }
184
+ expect(log).to contains_log(
185
+ :debug,
186
+ %(Initializing Sidekiq probe with config: {:hostname=>"#{redis_hostname}"})
187
+ )
188
+ log = capture_logs { probe.call }
189
+ expect(log).to contains_log(
190
+ :debug,
191
+ "Sidekiq probe: Using hostname config option #{redis_hostname.inspect} as hostname"
192
+ )
193
+ expect(Appsignal).to have_received(:set_gauge)
194
+ .with(anything, anything, :hostname => redis_hostname).at_least(:once)
195
+ end
196
+ end
197
+
198
+ def expect_gauge(key, value, tags = {})
199
+ expect(Appsignal).to receive(:set_gauge)
200
+ .with("sidekiq_#{key}", value, expected_default_tags.merge(tags))
201
+ .and_call_original
202
+ end
203
+ end
204
+ end
@@ -4,9 +4,12 @@ describe Appsignal::Rack::JSExceptionCatcher do
4
4
  let(:config_options) { { :enable_frontend_error_catching => true } }
5
5
  let(:config) { project_fixture_config("production", config_options) }
6
6
  let(:deprecation_message) do
7
- "The Appsignal::Rack::JSExceptionCatcher is deprecated. " \
8
- "Please use the official AppSignal JavaScript integration instead. " \
9
- "https://docs.appsignal.com/front-end/"
7
+ "The Appsignal::Rack::JSExceptionCatcher is " \
8
+ "deprecated and will be removed in a future version. Please use " \
9
+ "the official AppSignal JavaScript integration by disabling " \
10
+ "`enable_frontend_error_catching` in your configuration and " \
11
+ "installing AppSignal for JavaScript instead. " \
12
+ "(https://docs.appsignal.com/front-end/)"
10
13
  end
11
14
  before { Appsignal.config = config }
12
15
 
@@ -32,7 +35,9 @@ describe Appsignal::Rack::JSExceptionCatcher do
32
35
 
33
36
  describe "#call" do
34
37
  let(:catcher) do
35
- silence { Appsignal::Rack::JSExceptionCatcher.new(app, options) }
38
+ silence :allowed => ["enable_frontend_error_catching"] do
39
+ Appsignal::Rack::JSExceptionCatcher.new(app, options)
40
+ end
36
41
  end
37
42
  after { catcher.call(env) }
38
43
 
@@ -473,22 +473,20 @@ describe Appsignal::Transaction do
473
473
  end
474
474
  end
475
475
 
476
- describe "set_queue_start" do
477
- it "should set the queue start in extension" do
478
- expect(transaction.ext).to receive(:set_queue_start).with(
479
- 10.0
480
- ).once
476
+ describe "#set_queue_start" do
477
+ it "sets the queue start in extension" do
478
+ expect(transaction.ext).to receive(:set_queue_start).with(10.0).once
481
479
 
482
480
  transaction.set_queue_start(10.0)
483
481
  end
484
482
 
485
- it "should not set the queue start in extension when value is nil" do
483
+ it "does not set the queue start in extension when value is nil" do
486
484
  expect(transaction.ext).to_not receive(:set_queue_start)
487
485
 
488
486
  transaction.set_queue_start(nil)
489
487
  end
490
488
 
491
- it "should not raise an error when the queue start is too big" do
489
+ it "does not raise an error when the queue start is too big" do
492
490
  expect(transaction.ext).to receive(:set_queue_start).and_raise(RangeError)
493
491
 
494
492
  expect(Appsignal.logger).to receive(:warn).with("Queue start value 10 is too big")
@@ -62,7 +62,7 @@ RSpec.describe "Puma plugin" do
62
62
  expect(launcher.events.on_booted).to_not be_nil
63
63
 
64
64
  launcher.events.on_booted.call
65
- expect(Appsignal::Minutely.probes[:puma]).to eql(Appsignal::Hooks::PumaProbe)
65
+ expect(Appsignal::Minutely.probes[:puma]).to eql(Appsignal::Probes::PumaProbe)
66
66
 
67
67
  # Minutely probes started and called
68
68
  wait_for("enough probe calls") { probe.calls >= 2 }
@@ -0,0 +1,25 @@
1
+ module ActionMailerHelpers
2
+ def perform_action_mailer(mailer, method, args = nil)
3
+ if DependencyHelper.rails_version >= Gem::Version.new("5.2.0")
4
+ case args
5
+ when Array
6
+ mailer.send(method, *args).deliver_later
7
+ when Hash
8
+ mailer.with(args).send(method).deliver_later
9
+ when NilClass
10
+ mailer.send(method).deliver_later
11
+ else
12
+ raise "Unknown scenario for arguments: #{args}"
13
+ end
14
+ else
15
+ # Rails 5.1 and lower
16
+ mailer_object =
17
+ if args
18
+ mailer.send(method, *args)
19
+ else
20
+ mailer.send(method)
21
+ end
22
+ mailer_object.deliver_later
23
+ end
24
+ end
25
+ end
@@ -1,6 +1,10 @@
1
1
  module DependencyHelper
2
2
  module_function
3
3
 
4
+ def ruby_version
5
+ Gem::Version.new(RUBY_VERSION)
6
+ end
7
+
4
8
  def running_jruby?
5
9
  defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
6
10
  end
@@ -10,8 +14,11 @@ module DependencyHelper
10
14
  end
11
15
 
12
16
  def rails6_present?
13
- rails_present? &&
14
- Gem.loaded_specs["rails"].version >= Gem::Version.new("6.0.0")
17
+ rails_present? && rails_version >= Gem::Version.new("6.0.0")
18
+ end
19
+
20
+ def rails_version
21
+ Gem.loaded_specs["rails"].version
15
22
  end
16
23
 
17
24
  def sequel_present?
@@ -44,6 +44,12 @@ module TransactionHelpers
44
44
  created_transactions.last
45
45
  end
46
46
 
47
+ # Set current transaction manually.
48
+ # Cleared by {clear_current_transaction!}
49
+ def set_current_transaction(transaction) # rubocop:disable Style/AccessorMethodName
50
+ Thread.current[:appsignal_transaction] = transaction
51
+ end
52
+
47
53
  # Use when {Appsignal::Transaction.clear_current_transaction!} is stubbed to
48
54
  # clear the current transaction on the current thread.
49
55
  def clear_current_transaction!
@@ -1,4 +1,4 @@
1
- class Sidekiq
2
- class API
1
+ module Sidekiq
2
+ class Stats
3
3
  end
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appsignal
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.11.0.alpha.1
4
+ version: 2.11.0.beta.4
5
5
  platform: java
6
6
  authors:
7
7
  - Robert Beekman
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-06-29 00:00:00.000000000 Z
13
+ date: 2020-07-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rack
@@ -186,7 +186,8 @@ files:
186
186
  - gemfiles/rails-5.1.gemfile
187
187
  - gemfiles/rails-5.2.gemfile
188
188
  - gemfiles/rails-6.0.gemfile
189
- - gemfiles/resque.gemfile
189
+ - gemfiles/resque-1.gemfile
190
+ - gemfiles/resque-2.gemfile
190
191
  - gemfiles/sequel-435.gemfile
191
192
  - gemfiles/sequel.gemfile
192
193
  - gemfiles/sinatra.gemfile
@@ -220,6 +221,7 @@ files:
220
221
  - lib/appsignal/helpers/metrics.rb
221
222
  - lib/appsignal/hooks.rb
222
223
  - lib/appsignal/hooks/action_cable.rb
224
+ - lib/appsignal/hooks/active_job.rb
223
225
  - lib/appsignal/hooks/active_support_notifications.rb
224
226
  - lib/appsignal/hooks/celluloid.rb
225
227
  - lib/appsignal/hooks/data_mapper.rb
@@ -231,6 +233,7 @@ files:
231
233
  - lib/appsignal/hooks/que.rb
232
234
  - lib/appsignal/hooks/rake.rb
233
235
  - lib/appsignal/hooks/redis.rb
236
+ - lib/appsignal/hooks/resque.rb
234
237
  - lib/appsignal/hooks/sequel.rb
235
238
  - lib/appsignal/hooks/shoryuken.rb
236
239
  - lib/appsignal/hooks/sidekiq.rb
@@ -255,6 +258,8 @@ files:
255
258
  - lib/appsignal/logger.rb
256
259
  - lib/appsignal/marker.rb
257
260
  - lib/appsignal/minutely.rb
261
+ - lib/appsignal/probes/puma.rb
262
+ - lib/appsignal/probes/sidekiq.rb
258
263
  - lib/appsignal/rack/generic_instrumentation.rb
259
264
  - lib/appsignal/rack/js_exception_catcher.rb
260
265
  - lib/appsignal/rack/rails_instrumentation.rb
@@ -303,6 +308,7 @@ files:
303
308
  - spec/lib/appsignal/garbage_collection_profiler_spec.rb
304
309
  - spec/lib/appsignal/hooks/action_cable_spec.rb
305
310
  - spec/lib/appsignal/hooks/active_support_notifications_spec.rb
311
+ - spec/lib/appsignal/hooks/activejob_spec.rb
306
312
  - spec/lib/appsignal/hooks/celluloid_spec.rb
307
313
  - spec/lib/appsignal/hooks/data_mapper_spec.rb
308
314
  - spec/lib/appsignal/hooks/delayed_job_spec.rb
@@ -313,6 +319,7 @@ files:
313
319
  - spec/lib/appsignal/hooks/que_spec.rb
314
320
  - spec/lib/appsignal/hooks/rake_spec.rb
315
321
  - spec/lib/appsignal/hooks/redis_spec.rb
322
+ - spec/lib/appsignal/hooks/resque_spec.rb
316
323
  - spec/lib/appsignal/hooks/sequel_spec.rb
317
324
  - spec/lib/appsignal/hooks/shoryuken_spec.rb
318
325
  - spec/lib/appsignal/hooks/sidekiq_spec.rb
@@ -334,6 +341,8 @@ files:
334
341
  - spec/lib/appsignal/logger_spec.rb
335
342
  - spec/lib/appsignal/marker_spec.rb
336
343
  - spec/lib/appsignal/minutely_spec.rb
344
+ - spec/lib/appsignal/probes/puma_spec.rb
345
+ - spec/lib/appsignal/probes/sidekiq_spec.rb
337
346
  - spec/lib/appsignal/rack/generic_instrumentation_spec.rb
338
347
  - spec/lib/appsignal/rack/js_exception_catcher_spec.rb
339
348
  - spec/lib/appsignal/rack/rails_instrumentation_spec.rb
@@ -358,6 +367,7 @@ files:
358
367
  - spec/support/fixtures/projects/valid/config/environments/test.rb
359
368
  - spec/support/fixtures/projects/valid/log/.gitkeep
360
369
  - spec/support/fixtures/uploaded_file.txt
370
+ - spec/support/helpers/action_mailer_helpers.rb
361
371
  - spec/support/helpers/api_request_helper.rb
362
372
  - spec/support/helpers/cli_helpers.rb
363
373
  - spec/support/helpers/config_helpers.rb
@@ -445,6 +455,7 @@ test_files:
445
455
  - spec/lib/appsignal/garbage_collection_profiler_spec.rb
446
456
  - spec/lib/appsignal/hooks/action_cable_spec.rb
447
457
  - spec/lib/appsignal/hooks/active_support_notifications_spec.rb
458
+ - spec/lib/appsignal/hooks/activejob_spec.rb
448
459
  - spec/lib/appsignal/hooks/celluloid_spec.rb
449
460
  - spec/lib/appsignal/hooks/data_mapper_spec.rb
450
461
  - spec/lib/appsignal/hooks/delayed_job_spec.rb
@@ -455,6 +466,7 @@ test_files:
455
466
  - spec/lib/appsignal/hooks/que_spec.rb
456
467
  - spec/lib/appsignal/hooks/rake_spec.rb
457
468
  - spec/lib/appsignal/hooks/redis_spec.rb
469
+ - spec/lib/appsignal/hooks/resque_spec.rb
458
470
  - spec/lib/appsignal/hooks/sequel_spec.rb
459
471
  - spec/lib/appsignal/hooks/shoryuken_spec.rb
460
472
  - spec/lib/appsignal/hooks/sidekiq_spec.rb
@@ -476,6 +488,8 @@ test_files:
476
488
  - spec/lib/appsignal/logger_spec.rb
477
489
  - spec/lib/appsignal/marker_spec.rb
478
490
  - spec/lib/appsignal/minutely_spec.rb
491
+ - spec/lib/appsignal/probes/puma_spec.rb
492
+ - spec/lib/appsignal/probes/sidekiq_spec.rb
479
493
  - spec/lib/appsignal/rack/generic_instrumentation_spec.rb
480
494
  - spec/lib/appsignal/rack/js_exception_catcher_spec.rb
481
495
  - spec/lib/appsignal/rack/rails_instrumentation_spec.rb
@@ -500,6 +514,7 @@ test_files:
500
514
  - spec/support/fixtures/projects/valid/config/environments/test.rb
501
515
  - spec/support/fixtures/projects/valid/log/.gitkeep
502
516
  - spec/support/fixtures/uploaded_file.txt
517
+ - spec/support/helpers/action_mailer_helpers.rb
503
518
  - spec/support/helpers/api_request_helper.rb
504
519
  - spec/support/helpers/cli_helpers.rb
505
520
  - spec/support/helpers/config_helpers.rb