appsignal 2.10.8-java → 2.11.0.beta.1-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) 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 -0
  5. data/build_matrix.yml +13 -7
  6. data/ext/agent.yml +19 -19
  7. data/ext/appsignal_extension.c +10 -1
  8. data/ext/base.rb +11 -2
  9. data/gemfiles/padrino.gemfile +2 -2
  10. data/gemfiles/rails-4.2.gemfile +9 -2
  11. data/gemfiles/rails-5.0.gemfile +1 -0
  12. data/gemfiles/rails-5.1.gemfile +1 -0
  13. data/gemfiles/rails-5.2.gemfile +1 -0
  14. data/gemfiles/rails-6.0.gemfile +1 -0
  15. data/gemfiles/resque-1.gemfile +7 -0
  16. data/gemfiles/{resque.gemfile → resque-2.gemfile} +1 -1
  17. data/lib/appsignal.rb +21 -1
  18. data/lib/appsignal/capistrano.rb +2 -0
  19. data/lib/appsignal/config.rb +6 -2
  20. data/lib/appsignal/environment.rb +126 -0
  21. data/lib/appsignal/extension/jruby.rb +10 -0
  22. data/lib/appsignal/hooks.rb +2 -0
  23. data/lib/appsignal/hooks/active_job.rb +89 -0
  24. data/lib/appsignal/hooks/net_http.rb +2 -0
  25. data/lib/appsignal/hooks/puma.rb +2 -58
  26. data/lib/appsignal/hooks/redis.rb +2 -0
  27. data/lib/appsignal/hooks/resque.rb +60 -0
  28. data/lib/appsignal/hooks/sequel.rb +2 -0
  29. data/lib/appsignal/hooks/sidekiq.rb +18 -191
  30. data/lib/appsignal/integrations/object.rb +4 -0
  31. data/lib/appsignal/integrations/que.rb +1 -1
  32. data/lib/appsignal/integrations/resque.rb +9 -12
  33. data/lib/appsignal/integrations/resque_active_job.rb +9 -24
  34. data/lib/appsignal/probes/puma.rb +61 -0
  35. data/lib/appsignal/probes/sidekiq.rb +102 -0
  36. data/lib/appsignal/rack/js_exception_catcher.rb +5 -2
  37. data/lib/appsignal/transaction.rb +32 -7
  38. data/lib/appsignal/utils/deprecation_message.rb +5 -1
  39. data/lib/appsignal/version.rb +1 -1
  40. data/lib/puma/plugin/appsignal.rb +2 -1
  41. data/spec/lib/appsignal/cli/diagnose_spec.rb +2 -1
  42. data/spec/lib/appsignal/config_spec.rb +6 -1
  43. data/spec/lib/appsignal/environment_spec.rb +167 -0
  44. data/spec/lib/appsignal/hooks/activejob_spec.rb +458 -0
  45. data/spec/lib/appsignal/hooks/puma_spec.rb +2 -181
  46. data/spec/lib/appsignal/hooks/resque_spec.rb +185 -0
  47. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +292 -546
  48. data/spec/lib/appsignal/integrations/padrino_spec.rb +1 -1
  49. data/spec/lib/appsignal/integrations/que_spec.rb +25 -6
  50. data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +20 -137
  51. data/spec/lib/appsignal/integrations/resque_spec.rb +20 -85
  52. data/spec/lib/appsignal/probes/puma_spec.rb +180 -0
  53. data/spec/lib/appsignal/probes/sidekiq_spec.rb +204 -0
  54. data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +9 -4
  55. data/spec/lib/appsignal/transaction_spec.rb +35 -20
  56. data/spec/lib/appsignal_spec.rb +22 -0
  57. data/spec/lib/puma/appsignal_spec.rb +1 -1
  58. data/spec/support/helpers/action_mailer_helpers.rb +25 -0
  59. data/spec/support/helpers/dependency_helper.rb +12 -0
  60. data/spec/support/helpers/env_helpers.rb +1 -1
  61. data/spec/support/helpers/environment_metdata_helper.rb +16 -0
  62. data/spec/support/helpers/transaction_helpers.rb +6 -0
  63. data/spec/support/stubs/sidekiq/api.rb +2 -2
  64. metadata +25 -5
@@ -0,0 +1,458 @@
1
+ if DependencyHelper.active_job_present?
2
+ require "active_job"
3
+ require "action_mailer"
4
+
5
+ describe Appsignal::Hooks::ActiveJobHook do
6
+ describe "#dependencies_present?" do
7
+ subject { described_class.new.dependencies_present? }
8
+
9
+ context "when ActiveJob constant is found" do
10
+ before { stub_const "ActiveJob", Class.new }
11
+
12
+ it { is_expected.to be_truthy }
13
+ end
14
+
15
+ context "when ActiveJob constant is not found" do
16
+ before { hide_const "ActiveJob" }
17
+
18
+ it { is_expected.to be_falsy }
19
+ end
20
+ end
21
+
22
+ describe "#install" do
23
+ it "extends ActiveJob::Base with the AppSignal ActiveJob plugin" do
24
+ described_class.new.install
25
+
26
+ path, _line_number = ActiveJob::Base.method(:execute).source_location
27
+ expect(path).to end_with("/lib/appsignal/hooks/active_job.rb")
28
+ end
29
+ end
30
+ end
31
+
32
+ describe Appsignal::Hooks::ActiveJobHook::ActiveJobClassInstrumentation do
33
+ let(:time) { Time.parse("2001-01-01 10:00:00UTC") }
34
+ let(:namespace) { Appsignal::Transaction::BACKGROUND_JOB }
35
+ let(:log) { StringIO.new }
36
+ let(:parameterized_given_args) do
37
+ {
38
+ :foo => "Foo",
39
+ "bar" => "Bar",
40
+ "baz" => { "1" => "foo" }
41
+ }
42
+ end
43
+ let(:method_given_args) do
44
+ [
45
+ "foo",
46
+ parameterized_given_args
47
+ ]
48
+ end
49
+ let(:parameterized_expected_args) do
50
+ {
51
+ "_aj_symbol_keys" => ["foo"],
52
+ "foo" => "Foo",
53
+ "bar" => "Bar",
54
+ "baz" => {
55
+ "_aj_symbol_keys" => [],
56
+ "1" => "foo"
57
+ }
58
+ }
59
+ end
60
+ let(:method_expected_args) do
61
+ [
62
+ "foo",
63
+ parameterized_expected_args
64
+ ]
65
+ end
66
+ before do
67
+ ActiveJob::Base.queue_adapter = :inline
68
+
69
+ start_agent
70
+ Appsignal.logger = test_logger(log)
71
+ class ActiveJobTestJob < ActiveJob::Base
72
+ def perform(*_args)
73
+ end
74
+ end
75
+
76
+ class ActiveJobErrorTestJob < ActiveJob::Base
77
+ def perform
78
+ raise "uh oh"
79
+ end
80
+ end
81
+ end
82
+ around { |example| keep_transactions { example.run } }
83
+ after do
84
+ Object.send(:remove_const, :ActiveJobTestJob)
85
+ Object.send(:remove_const, :ActiveJobErrorTestJob)
86
+ end
87
+
88
+ it "reports the name from the ActiveJob integration" do
89
+ perform_job(ActiveJobTestJob)
90
+
91
+ transaction = last_transaction
92
+ transaction_hash = transaction.to_h
93
+ expect(transaction_hash).to include(
94
+ "action" => "ActiveJobTestJob#perform",
95
+ "error" => nil,
96
+ "namespace" => namespace,
97
+ "metadata" => {},
98
+ "sample_data" => hash_including(
99
+ "params" => [],
100
+ "tags" => {
101
+ "queue" => "default"
102
+ }
103
+ )
104
+ )
105
+ events = transaction_hash["events"]
106
+ .sort_by { |e| e["start"] }
107
+ .map { |event| event["name"] }
108
+ expect(events).to eq(["perform_start.active_job", "perform.active_job"])
109
+ end
110
+
111
+ context "with error" do
112
+ it "reports the error on the transaction from the ActiveRecord integration" do
113
+ expect do
114
+ perform_job(ActiveJobErrorTestJob)
115
+ end.to raise_error(RuntimeError, "uh oh")
116
+
117
+ transaction = last_transaction
118
+ transaction_hash = transaction.to_h
119
+ expect(transaction_hash).to include(
120
+ "action" => "ActiveJobErrorTestJob#perform",
121
+ "error" => {
122
+ "name" => "RuntimeError",
123
+ "message" => "uh oh",
124
+ "backtrace" => kind_of(String)
125
+ },
126
+ "namespace" => namespace,
127
+ "metadata" => {},
128
+ "sample_data" => hash_including(
129
+ "params" => [],
130
+ "tags" => {
131
+ "queue" => "default"
132
+ }
133
+ )
134
+ )
135
+ events = transaction_hash["events"]
136
+ .sort_by { |e| e["start"] }
137
+ .map { |event| event["name"] }
138
+ expect(events).to eq(["perform_start.active_job", "perform.active_job"])
139
+ end
140
+ end
141
+
142
+ context "when wrapped in another transaction" do
143
+ it "does not create a new transaction or close the currently open one" do
144
+ current_transaction = background_job_transaction
145
+ allow(current_transaction).to receive(:complete).and_call_original
146
+ set_current_transaction current_transaction
147
+
148
+ perform_job(ActiveJobTestJob)
149
+
150
+ expect(created_transactions.count).to eql(1)
151
+ expect(current_transaction).to_not have_received(:complete)
152
+ current_transaction.complete
153
+
154
+ transaction = current_transaction
155
+ transaction_hash = transaction.to_h
156
+ # It does set data on the transaction
157
+ expect(transaction_hash).to include(
158
+ "id" => current_transaction.transaction_id,
159
+ "action" => "ActiveJobTestJob#perform",
160
+ "error" => nil,
161
+ "namespace" => namespace,
162
+ "metadata" => {},
163
+ "sample_data" => hash_including(
164
+ "params" => [],
165
+ "tags" => {
166
+ "queue" => "default"
167
+ }
168
+ )
169
+ )
170
+ events = transaction_hash["events"]
171
+ .reject { |e| e["name"] == "enqueue.active_job" }
172
+ .sort_by { |e| e["start"] }
173
+ .map { |event| event["name"] }
174
+ expect(events).to eq(["perform_start.active_job", "perform.active_job"])
175
+ end
176
+ end
177
+
178
+ context "with params" do
179
+ it "filters the configured params" do
180
+ Appsignal.config = project_fixture_config("production")
181
+ Appsignal.config[:filter_parameters] = ["foo"]
182
+ perform_job(ActiveJobTestJob, method_given_args)
183
+
184
+ transaction = last_transaction
185
+ transaction_hash = transaction.to_h
186
+ expect(transaction_hash["sample_data"]["params"]).to include(
187
+ [
188
+ "foo",
189
+ {
190
+ "_aj_symbol_keys" => ["foo"],
191
+ "foo" => "[FILTERED]",
192
+ "bar" => "Bar",
193
+ "baz" => { "_aj_symbol_keys" => [], "1" => "foo" }
194
+ }
195
+ ]
196
+ )
197
+ end
198
+ end
199
+
200
+ context "with provider_job_id", :skip => DependencyHelper.rails_version < Gem::Version.new("5.0.0") do
201
+ before do
202
+ module ActiveJob
203
+ module QueueAdapters
204
+ # Adapter used in our test suite to add provider data to the job
205
+ # data, as is done by Rails provided ActiveJob adapters.
206
+ #
207
+ # This implementation is based on the
208
+ # `ActiveJob::QueueAdapters::InlineAdapter`.
209
+ class AppsignalTestAdapter < InlineAdapter
210
+ def enqueue(job)
211
+ Base.execute(job.serialize.merge("provider_job_id" => "my_provider_job_id"))
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ class ProviderWrappedActiveJobTestJob < ActiveJob::Base
218
+ self.queue_adapter = :appsignal_test
219
+
220
+ def perform(*_args)
221
+ end
222
+ end
223
+ end
224
+ after do
225
+ ActiveJob::QueueAdapters.send(:remove_const, :AppsignalTestAdapter)
226
+ Object.send(:remove_const, :ProviderWrappedActiveJobTestJob)
227
+ end
228
+
229
+ it "sets provider_job_id as tag" do
230
+ perform_job(ProviderWrappedActiveJobTestJob)
231
+
232
+ transaction = last_transaction
233
+ transaction_hash = transaction.to_h
234
+ expect(transaction_hash["sample_data"]["tags"]).to include(
235
+ "provider_job_id" => "my_provider_job_id"
236
+ )
237
+ end
238
+ end
239
+
240
+ context "with enqueued_at", :skip => DependencyHelper.rails_version < Gem::Version.new("6.0.0") do
241
+ before do
242
+ module ActiveJob
243
+ module QueueAdapters
244
+ # Adapter used in our test suite to add provider data to the job
245
+ # data, as is done by Rails provided ActiveJob adapters.
246
+ #
247
+ # This implementation is based on the
248
+ # `ActiveJob::QueueAdapters::InlineAdapter`.
249
+ class AppsignalTestAdapter < InlineAdapter
250
+ def enqueue(job)
251
+ Base.execute(job.serialize.merge("enqueued_at" => "2020-10-10T10:10:10Z"))
252
+ end
253
+ end
254
+ end
255
+ end
256
+
257
+ class ProviderWrappedActiveJobTestJob < ActiveJob::Base
258
+ self.queue_adapter = :appsignal_test
259
+
260
+ def perform(*_args)
261
+ end
262
+ end
263
+ end
264
+ after do
265
+ ActiveJob::QueueAdapters.send(:remove_const, :AppsignalTestAdapter)
266
+ Object.send(:remove_const, :ProviderWrappedActiveJobTestJob)
267
+ end
268
+
269
+ it "sets queue time on transaction" do
270
+ allow_any_instance_of(Appsignal::Transaction).to receive(:set_queue_start).and_call_original
271
+ perform_job(ProviderWrappedActiveJobTestJob)
272
+
273
+ transaction = last_transaction
274
+ queue_time = Time.parse("2020-10-10T10:10:10Z")
275
+ expect(transaction).to have_received(:set_queue_start)
276
+ .with((queue_time.to_f * 1_000).to_i)
277
+ end
278
+ end
279
+
280
+ context "with ActionMailer job" do
281
+ include ActionMailerHelpers
282
+
283
+ before do
284
+ class ActionMailerTestJob < ActionMailer::Base
285
+ def welcome(_first_arg = nil, _second_arg = nil)
286
+ end
287
+ end
288
+ end
289
+ after do
290
+ Object.send(:remove_const, :ActionMailerTestJob)
291
+ end
292
+
293
+ context "without params" do
294
+ it "sets the Action mailer data on the transaction" do
295
+ perform_mailer(ActionMailerTestJob, :welcome)
296
+
297
+ transaction = last_transaction
298
+ transaction_hash = transaction.to_h
299
+ expect(transaction_hash).to include(
300
+ "action" => "ActionMailerTestJob#welcome",
301
+ "sample_data" => hash_including(
302
+ "params" => ["ActionMailerTestJob", "welcome", "deliver_now"],
303
+ "tags" => { "queue" => "mailers" }
304
+ )
305
+ )
306
+ end
307
+ end
308
+
309
+ context "with multiple arguments" do
310
+ it "sets the arguments on the transaction" do
311
+ perform_mailer(ActionMailerTestJob, :welcome, method_given_args)
312
+
313
+ transaction = last_transaction
314
+ transaction_hash = transaction.to_h
315
+ expect(transaction_hash).to include(
316
+ "action" => "ActionMailerTestJob#welcome",
317
+ "sample_data" => hash_including(
318
+ "params" => ["ActionMailerTestJob", "welcome", "deliver_now"] + method_expected_args,
319
+ "tags" => { "queue" => "mailers" }
320
+ )
321
+ )
322
+ end
323
+ end
324
+
325
+ if DependencyHelper.rails_version >= Gem::Version.new("5.2.0")
326
+ context "with parameterized arguments" do
327
+ it "sets the arguments on the transaction" do
328
+ perform_mailer(ActionMailerTestJob, :welcome, parameterized_given_args)
329
+
330
+ transaction = last_transaction
331
+ transaction_hash = transaction.to_h
332
+ expect(transaction_hash).to include(
333
+ "action" => "ActionMailerTestJob#welcome",
334
+ "sample_data" => hash_including(
335
+ "params" => ["ActionMailerTestJob", "welcome", "deliver_now", parameterized_expected_args],
336
+ "tags" => { "queue" => "mailers" }
337
+ )
338
+ )
339
+ end
340
+ end
341
+ end
342
+ end
343
+
344
+ if DependencyHelper.rails_version >= Gem::Version.new("6.0.0")
345
+ context "with ActionMailer MailDeliveryJob job" do
346
+ include ActionMailerHelpers
347
+
348
+ before do
349
+ class ActionMailerTestMailDeliveryJob < ActionMailer::Base
350
+ self.delivery_job = ActionMailer::MailDeliveryJob
351
+
352
+ def welcome(*_args)
353
+ end
354
+ end
355
+ end
356
+ after do
357
+ Object.send(:remove_const, :ActionMailerTestMailDeliveryJob)
358
+ end
359
+
360
+ it "sets the Action mailer data on the transaction" do
361
+ perform_mailer(ActionMailerTestMailDeliveryJob, :welcome)
362
+
363
+ transaction = last_transaction
364
+ transaction_hash = transaction.to_h
365
+ expect(transaction_hash).to include(
366
+ "action" => "ActionMailerTestMailDeliveryJob#welcome",
367
+ "sample_data" => hash_including(
368
+ "params" => [
369
+ "ActionMailerTestMailDeliveryJob",
370
+ "welcome",
371
+ "deliver_now",
372
+ { active_job_internal_key => ["args"], "args" => [] }
373
+ ],
374
+ "tags" => { "queue" => "mailers" }
375
+ )
376
+ )
377
+ end
378
+
379
+ context "with method arguments" do
380
+ it "sets the Action mailer data on the transaction" do
381
+ perform_mailer(ActionMailerTestMailDeliveryJob, :welcome, method_given_args)
382
+
383
+ transaction = last_transaction
384
+ transaction_hash = transaction.to_h
385
+ expect(transaction_hash).to include(
386
+ "action" => "ActionMailerTestMailDeliveryJob#welcome",
387
+ "sample_data" => hash_including(
388
+ "params" => [
389
+ "ActionMailerTestMailDeliveryJob",
390
+ "welcome",
391
+ "deliver_now",
392
+ {
393
+ active_job_internal_key => ["args"],
394
+ "args" => method_expected_args
395
+ }
396
+ ],
397
+ "tags" => { "queue" => "mailers" }
398
+ )
399
+ )
400
+ end
401
+ end
402
+
403
+ context "with parameterized arguments" do
404
+ it "sets the Action mailer data on the transaction" do
405
+ perform_mailer(ActionMailerTestMailDeliveryJob, :welcome, parameterized_given_args)
406
+
407
+ transaction = last_transaction
408
+ transaction_hash = transaction.to_h
409
+ expect(transaction_hash).to include(
410
+ "action" => "ActionMailerTestMailDeliveryJob#welcome",
411
+ "sample_data" => hash_including(
412
+ "params" => [
413
+ "ActionMailerTestMailDeliveryJob",
414
+ "welcome",
415
+ "deliver_now",
416
+ {
417
+ active_job_internal_key => ["params", "args"],
418
+ "args" => [],
419
+ "params" => parameterized_expected_args
420
+ }
421
+ ],
422
+ "tags" => { "queue" => "mailers" }
423
+ )
424
+ )
425
+ end
426
+ end
427
+ end
428
+ end
429
+
430
+ def perform_active_job
431
+ Timecop.freeze(time) do
432
+ yield
433
+ end
434
+ end
435
+
436
+ def perform_job(job_class, args = nil)
437
+ perform_active_job do
438
+ if args
439
+ job_class.perform_later(args)
440
+ else
441
+ job_class.perform_later
442
+ end
443
+ end
444
+ end
445
+
446
+ def perform_mailer(mailer, method, args = nil)
447
+ perform_active_job { perform_action_mailer(mailer, method, args) }
448
+ end
449
+
450
+ def active_job_internal_key
451
+ if DependencyHelper.ruby_version >= Gem::Version.new("2.7.0")
452
+ "_aj_ruby2_keywords"
453
+ else
454
+ "_aj_symbol_keys"
455
+ end
456
+ end
457
+ end
458
+ end