appsignal 2.11.0.beta.3-java → 2.11.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.semaphore/semaphore.yml +57 -1
  3. data/CHANGELOG.md +26 -0
  4. data/README.md +11 -5
  5. data/Rakefile +27 -9
  6. data/appsignal.gemspec +1 -1
  7. data/build_matrix.yml +2 -2
  8. data/ext/Rakefile +2 -0
  9. data/ext/agent.yml +17 -25
  10. data/ext/appsignal_extension.c +1 -1
  11. data/ext/base.rb +7 -0
  12. data/ext/extconf.rb +2 -0
  13. data/lib/appsignal.rb +1 -0
  14. data/lib/appsignal/auth_check.rb +4 -2
  15. data/lib/appsignal/cli/diagnose.rb +1 -1
  16. data/lib/appsignal/config.rb +82 -17
  17. data/lib/appsignal/extension.rb +6 -5
  18. data/lib/appsignal/extension/jruby.rb +6 -5
  19. data/lib/appsignal/hooks.rb +24 -0
  20. data/lib/appsignal/hooks/action_mailer.rb +22 -0
  21. data/lib/appsignal/hooks/active_job.rb +41 -12
  22. data/lib/appsignal/hooks/active_support_notifications.rb +72 -0
  23. data/lib/appsignal/hooks/puma.rb +0 -1
  24. data/lib/appsignal/hooks/sidekiq.rb +1 -2
  25. data/lib/appsignal/integrations/delayed_job_plugin.rb +1 -1
  26. data/lib/appsignal/probes.rb +7 -0
  27. data/lib/appsignal/probes/puma.rb +1 -1
  28. data/lib/appsignal/probes/sidekiq.rb +3 -1
  29. data/lib/appsignal/utils/deprecation_message.rb +1 -1
  30. data/lib/appsignal/version.rb +1 -1
  31. data/spec/lib/appsignal/auth_check_spec.rb +23 -0
  32. data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
  33. data/spec/lib/appsignal/capistrano3_spec.rb +1 -1
  34. data/spec/lib/appsignal/cli/diagnose_spec.rb +42 -0
  35. data/spec/lib/appsignal/config_spec.rb +39 -1
  36. data/spec/lib/appsignal/extension/jruby_spec.rb +31 -28
  37. data/spec/lib/appsignal/extension_install_failure_spec.rb +23 -0
  38. data/spec/lib/appsignal/hooks/action_mailer_spec.rb +54 -0
  39. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +35 -0
  40. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +145 -0
  41. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +69 -0
  42. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +9 -137
  43. data/spec/lib/appsignal/hooks/activejob_spec.rb +82 -12
  44. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +3 -14
  45. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +7 -5
  46. data/spec/lib/appsignal/hooks_spec.rb +57 -0
  47. data/spec/lib/appsignal/marker_spec.rb +1 -1
  48. data/spec/spec_helper.rb +5 -0
  49. data/spec/support/helpers/config_helpers.rb +3 -2
  50. data/spec/support/helpers/dependency_helper.rb +4 -0
  51. data/spec/support/helpers/transaction_helpers.rb +1 -1
  52. data/spec/support/testing.rb +19 -19
  53. metadata +21 -9
@@ -110,7 +110,10 @@ if DependencyHelper.active_job_present?
110
110
  "metadata" => {},
111
111
  "sample_data" => hash_including(
112
112
  "params" => [],
113
- "tags" => { "queue" => queue }
113
+ "tags" => {
114
+ "active_job_id" => kind_of(String),
115
+ "queue" => queue
116
+ }
114
117
  )
115
118
  )
116
119
  events = transaction_hash["events"]
@@ -130,7 +133,7 @@ if DependencyHelper.active_job_present?
130
133
  transaction_hash = transaction.to_h
131
134
  expect(transaction_hash).to include(
132
135
  "sample_data" => hash_including(
133
- "tags" => { "queue" => "custom_queue" }
136
+ "tags" => hash_including("queue" => "custom_queue")
134
137
  )
135
138
  )
136
139
  end
@@ -151,9 +154,11 @@ if DependencyHelper.active_job_present?
151
154
  end
152
155
 
153
156
  it "reports the priority as tag on the transaction" do
154
- tags = { :priority => 10, :queue => queue }
157
+ tags = { :queue => queue }
155
158
  expect(Appsignal).to receive(:increment_counter)
156
159
  .with("active_job_queue_job_count", 1, tags.merge(:status => :processed))
160
+ expect(Appsignal).to receive(:increment_counter)
161
+ .with("active_job_queue_priority_job_count", 1, tags.merge(:priority => 10, :status => :processed))
157
162
 
158
163
  perform_job(ActiveJobPriorityTestJob)
159
164
 
@@ -161,7 +166,7 @@ if DependencyHelper.active_job_present?
161
166
  transaction_hash = transaction.to_h
162
167
  expect(transaction_hash).to include(
163
168
  "sample_data" => hash_including(
164
- "tags" => { "queue" => queue, "priority" => 10 }
169
+ "tags" => hash_including("queue" => queue, "priority" => 10)
165
170
  )
166
171
  )
167
172
  end
@@ -194,7 +199,10 @@ if DependencyHelper.active_job_present?
194
199
  "metadata" => {},
195
200
  "sample_data" => hash_including(
196
201
  "params" => [],
197
- "tags" => { "queue" => queue }
202
+ "tags" => {
203
+ "active_job_id" => kind_of(String),
204
+ "queue" => queue
205
+ }
198
206
  )
199
207
  )
200
208
  events = transaction_hash["events"]
@@ -202,6 +210,47 @@ if DependencyHelper.active_job_present?
202
210
  .map { |event| event["name"] }
203
211
  expect(events).to eq(["perform_start.active_job", "perform.active_job"])
204
212
  end
213
+
214
+ if DependencyHelper.rails_version >= Gem::Version.new("5.0.0")
215
+ context "with priority" do
216
+ before do
217
+ class ActiveJobErrorPriorityTestJob < ActiveJob::Base
218
+ queue_with_priority 10
219
+
220
+ def perform(*_args)
221
+ raise "uh oh"
222
+ end
223
+ end
224
+ end
225
+ after do
226
+ Object.send(:remove_const, :ActiveJobErrorPriorityTestJob)
227
+ end
228
+
229
+ it "reports the priority as tag on the transaction" do
230
+ tags = { :queue => queue }
231
+ expect(Appsignal).to receive(:increment_counter)
232
+ .with("active_job_queue_job_count", 1, tags.merge(:status => :processed))
233
+ expect(Appsignal).to receive(:increment_counter)
234
+ .with("active_job_queue_job_count", 1, tags.merge(:status => :failed))
235
+ expect(Appsignal).to receive(:increment_counter)
236
+ .with("active_job_queue_priority_job_count", 1, tags.merge(:priority => 10, :status => :processed))
237
+ expect(Appsignal).to receive(:increment_counter)
238
+ .with("active_job_queue_priority_job_count", 1, tags.merge(:priority => 10, :status => :failed))
239
+
240
+ expect do
241
+ perform_job(ActiveJobErrorPriorityTestJob)
242
+ end.to raise_error(RuntimeError, "uh oh")
243
+
244
+ transaction = last_transaction
245
+ transaction_hash = transaction.to_h
246
+ expect(transaction_hash).to include(
247
+ "sample_data" => hash_including(
248
+ "tags" => hash_including("queue" => queue, "priority" => 10)
249
+ )
250
+ )
251
+ end
252
+ end
253
+ end
205
254
  end
206
255
 
207
256
  context "when wrapped in another transaction" do
@@ -227,7 +276,10 @@ if DependencyHelper.active_job_present?
227
276
  "metadata" => {},
228
277
  "sample_data" => hash_including(
229
278
  "params" => [],
230
- "tags" => { "queue" => queue }
279
+ "tags" => {
280
+ "active_job_id" => kind_of(String),
281
+ "queue" => queue
282
+ }
231
283
  )
232
284
  )
233
285
  events = transaction_hash["events"]
@@ -363,7 +415,10 @@ if DependencyHelper.active_job_present?
363
415
  "action" => "ActionMailerTestJob#welcome",
364
416
  "sample_data" => hash_including(
365
417
  "params" => ["ActionMailerTestJob", "welcome", "deliver_now"],
366
- "tags" => { "queue" => "mailers" }
418
+ "tags" => {
419
+ "active_job_id" => kind_of(String),
420
+ "queue" => "mailers"
421
+ }
367
422
  )
368
423
  )
369
424
  end
@@ -379,7 +434,10 @@ if DependencyHelper.active_job_present?
379
434
  "action" => "ActionMailerTestJob#welcome",
380
435
  "sample_data" => hash_including(
381
436
  "params" => ["ActionMailerTestJob", "welcome", "deliver_now"] + method_expected_args,
382
- "tags" => { "queue" => "mailers" }
437
+ "tags" => {
438
+ "active_job_id" => kind_of(String),
439
+ "queue" => "mailers"
440
+ }
383
441
  )
384
442
  )
385
443
  end
@@ -396,7 +454,10 @@ if DependencyHelper.active_job_present?
396
454
  "action" => "ActionMailerTestJob#welcome",
397
455
  "sample_data" => hash_including(
398
456
  "params" => ["ActionMailerTestJob", "welcome", "deliver_now", parameterized_expected_args],
399
- "tags" => { "queue" => "mailers" }
457
+ "tags" => {
458
+ "active_job_id" => kind_of(String),
459
+ "queue" => "mailers"
460
+ }
400
461
  )
401
462
  )
402
463
  end
@@ -434,7 +495,10 @@ if DependencyHelper.active_job_present?
434
495
  "deliver_now",
435
496
  { active_job_internal_key => ["args"], "args" => [] }
436
497
  ],
437
- "tags" => { "queue" => "mailers" }
498
+ "tags" => {
499
+ "active_job_id" => kind_of(String),
500
+ "queue" => "mailers"
501
+ }
438
502
  )
439
503
  )
440
504
  end
@@ -457,7 +521,10 @@ if DependencyHelper.active_job_present?
457
521
  "args" => method_expected_args
458
522
  }
459
523
  ],
460
- "tags" => { "queue" => "mailers" }
524
+ "tags" => {
525
+ "active_job_id" => kind_of(String),
526
+ "queue" => "mailers"
527
+ }
461
528
  )
462
529
  )
463
530
  end
@@ -482,7 +549,10 @@ if DependencyHelper.active_job_present?
482
549
  "params" => parameterized_expected_args
483
550
  }
484
551
  ],
485
- "tags" => { "queue" => "mailers" }
552
+ "tags" => {
553
+ "active_job_id" => kind_of(String),
554
+ "queue" => "mailers"
555
+ }
486
556
  )
487
557
  )
488
558
  end
@@ -227,25 +227,14 @@ describe Appsignal::Hooks::DelayedJobHook do
227
227
  end
228
228
  end
229
229
 
230
- context "without job name" do
231
- let(:job_data) do
232
- { :name => "", :payload_object => payload_object }
233
- end
234
-
235
- it "wraps it in a transaction using the class method job name" do
236
- perform
237
- expect(last_transaction.to_h["action"]).to eql("unknown")
238
- end
239
- end
240
-
241
- context "with invalid job name" do
230
+ context "with only job class name" do
242
231
  let(:job_data) do
243
232
  { :name => "Banana", :payload_object => payload_object }
244
233
  end
245
234
 
246
- it "wraps it in a transaction using the class method job name" do
235
+ it "appends #perform to the class name" do
247
236
  perform
248
- expect(last_transaction.to_h["action"]).to eql("unknown")
237
+ expect(last_transaction.to_h["action"]).to eql("Banana#perform")
249
238
  end
250
239
  end
251
240
 
@@ -76,9 +76,10 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
76
76
  ]
77
77
  end
78
78
  let(:job_class) { "TestClass" }
79
+ let(:jid) { "b4a577edbccf1d805744efa9" }
79
80
  let(:item) do
80
81
  {
81
- "jid" => "b4a577edbccf1d805744efa9",
82
+ "jid" => jid,
82
83
  "class" => job_class,
83
84
  "retry_count" => 0,
84
85
  "queue" => "default",
@@ -151,7 +152,7 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
151
152
  context "when using the Sidekiq delayed extension" do
152
153
  let(:item) do
153
154
  {
154
- "jid" => "efb140489485999d32b5504c",
155
+ "jid" => jid,
155
156
  "class" => "Sidekiq::Extensions::DelayedClass",
156
157
  "queue" => "default",
157
158
  "args" => [
@@ -191,7 +192,7 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
191
192
  context "when using the Sidekiq ActiveRecord instance delayed extension" do
192
193
  let(:item) do
193
194
  {
194
- "jid" => "efb140489485999d32b5504c",
195
+ "jid" => jid,
195
196
  "class" => "Sidekiq::Extensions::DelayedModel",
196
197
  "queue" => "default",
197
198
  "args" => [
@@ -243,7 +244,7 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
243
244
 
244
245
  transaction_hash = transaction.to_h
245
246
  expect(transaction_hash).to include(
246
- "id" => kind_of(String),
247
+ "id" => jid,
247
248
  "action" => "TestClass#perform",
248
249
  "error" => {
249
250
  "name" => "ExampleException",
@@ -277,7 +278,7 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
277
278
 
278
279
  transaction_hash = transaction.to_h
279
280
  expect(transaction_hash).to include(
280
- "id" => kind_of(String),
281
+ "id" => jid,
281
282
  "action" => "TestClass#perform",
282
283
  "error" => nil,
283
284
  "metadata" => {
@@ -361,6 +362,7 @@ if DependencyHelper.active_job_present?
361
362
  end
362
363
  let(:expected_tags) do
363
364
  {}.tap do |hash|
365
+ hash["active_job_id"] = kind_of(String)
364
366
  if DependencyHelper.rails_version >= Gem::Version.new("5.0.0")
365
367
  hash["provider_job_id"] = kind_of(String)
366
368
  end
@@ -78,6 +78,63 @@ describe Appsignal::Hooks do
78
78
  expect(Appsignal::Hooks.hooks[:mock_error_hook].installed?).to be_falsy
79
79
  Appsignal::Hooks.hooks.delete(:mock_error_hook)
80
80
  end
81
+
82
+ describe "missing constants" do
83
+ let(:err_stream) { std_stream }
84
+ let(:stderr) { err_stream.read }
85
+ let(:log_stream) { std_stream }
86
+ let(:log) { log_contents(log_stream) }
87
+ before do
88
+ Appsignal.logger = test_logger(log_stream)
89
+ end
90
+
91
+ def call_constant(&block)
92
+ capture_std_streams(std_stream, err_stream, &block)
93
+ end
94
+
95
+ describe "SidekiqProbe" do
96
+ it "logs a deprecation message and returns the new constant" do
97
+ constant = call_constant { Appsignal::Hooks::SidekiqProbe }
98
+
99
+ expect(constant).to eql(Appsignal::Probes::SidekiqProbe)
100
+ expect(constant.name).to eql("Appsignal::Probes::SidekiqProbe")
101
+
102
+ deprecation_message =
103
+ "The constant Appsignal::Hooks::SidekiqProbe has been deprecated. " \
104
+ "Please update the constant name to Appsignal::Probes::SidekiqProbe " \
105
+ "in the following file to remove this message.\n#{__FILE__}:"
106
+ expect(stderr).to include "appsignal WARNING: #{deprecation_message}"
107
+ expect(log).to contains_log :warn, deprecation_message
108
+ end
109
+ end
110
+
111
+ describe "PumaProbe" do
112
+ it "logs a deprecation message and returns the new constant" do
113
+ constant = call_constant { Appsignal::Hooks::PumaProbe }
114
+
115
+ expect(constant).to eql(Appsignal::Probes::PumaProbe)
116
+ expect(constant.name).to eql("Appsignal::Probes::PumaProbe")
117
+
118
+ deprecation_message =
119
+ "The constant Appsignal::Hooks::PumaProbe has been deprecated. " \
120
+ "Please update the constant name to Appsignal::Probes::PumaProbe " \
121
+ "in the following file to remove this message.\n#{__FILE__}:"
122
+ expect(stderr).to include "appsignal WARNING: #{deprecation_message}"
123
+ expect(log).to contains_log :warn, deprecation_message
124
+ end
125
+ end
126
+
127
+ describe "other constant" do
128
+ it "raises a NameError like Ruby normally does" do
129
+ expect do
130
+ call_constant { Appsignal::Hooks::Unknown }
131
+ end.to raise_error(NameError)
132
+
133
+ expect(stderr).to be_empty
134
+ expect(log).to be_empty
135
+ end
136
+ end
137
+ end
81
138
  end
82
139
 
83
140
  describe Appsignal::Hooks::Helpers do
@@ -4,7 +4,7 @@ describe Appsignal::Marker do
4
4
  described_class.new(
5
5
  {
6
6
  :revision => "503ce0923ed177a3ce000005",
7
- :repository => "master",
7
+ :repository => "main",
8
8
  :user => "batman",
9
9
  :rails_env => "production"
10
10
  },
@@ -65,6 +65,10 @@ RSpec.configure do |config|
65
65
 
66
66
  config.example_status_persistence_file_path = "spec/examples.txt"
67
67
  config.fail_if_no_examples = true
68
+ config.filter_run_excluding(
69
+ :extension_installation_failure => true,
70
+ :jruby => !DependencyHelper.running_jruby?
71
+ )
68
72
  config.mock_with :rspec do |mocks|
69
73
  mocks.syntax = :expect
70
74
  end
@@ -111,6 +115,7 @@ RSpec.configure do |config|
111
115
  # in the diagnose task, so add it manually to the list of to-be cleaned up
112
116
  # keys.
113
117
  env_keys << "_APPSIGNAL_DIAGNOSE"
118
+ env_keys << "_TEST_APPSIGNAL_EXTENSION_FAILURE"
114
119
  env_keys.each do |key|
115
120
  # First set the ENV var to an empty string and then delete the key from
116
121
  # the env. We set the env var to an empty string first as JRuby doesn't
@@ -5,12 +5,13 @@ module ConfigHelpers
5
5
  )
6
6
  end
7
7
 
8
- def project_fixture_config(env = "production", initial_config = {}, logger = Appsignal.logger)
8
+ def project_fixture_config(env = "production", initial_config = {}, logger = Appsignal.logger, config_file = nil)
9
9
  Appsignal::Config.new(
10
10
  project_fixture_path,
11
11
  env,
12
12
  initial_config,
13
- logger
13
+ logger,
14
+ config_file
14
15
  )
15
16
  end
16
17
 
@@ -37,6 +37,10 @@ module DependencyHelper
37
37
  dependency_present? "actioncable"
38
38
  end
39
39
 
40
+ def action_mailer_present?
41
+ dependency_present? "actionmailer"
42
+ end
43
+
40
44
  def active_job_present?
41
45
  dependency_present? "activejob"
42
46
  end
@@ -46,7 +46,7 @@ module TransactionHelpers
46
46
 
47
47
  # Set current transaction manually.
48
48
  # Cleared by {clear_current_transaction!}
49
- def set_current_transaction(transaction) # rubocop:disable Style/AccessorMethodName
49
+ def set_current_transaction(transaction) # rubocop:disable Naming/AccessorMethodName
50
50
  Thread.current[:appsignal_transaction] = transaction
51
51
  end
52
52
 
@@ -38,25 +38,9 @@ module Appsignal
38
38
  end
39
39
  end
40
40
 
41
- class Transaction
42
- class << self
43
- alias original_new new
44
-
45
- # Override the {Appsignal::Transaction.new} method so we can track which
46
- # transactions are created on the {Appsignal::Testing.transactions} list.
47
- #
48
- # @see TransactionHelpers#last_transaction
49
- def new(*args)
50
- transaction = original_new(*args)
51
- Appsignal::Testing.transactions << transaction
52
- transaction
53
- end
54
- end
55
- end
56
-
57
41
  class Extension
58
42
  class Transaction
59
- alias original_finish finish
43
+ alias original_finish finish if method_defined? :finish
60
44
 
61
45
  # Override default {Extension::Transaction#finish} behavior to always
62
46
  # return true, which tells the transaction to add its sample data (unless
@@ -72,7 +56,7 @@ module Appsignal
72
56
  return_value
73
57
  end
74
58
 
75
- alias original_complete complete
59
+ alias original_complete complete if method_defined? :complete
76
60
 
77
61
  # Override default {Extension::Transaction#complete} behavior to
78
62
  # store the transaction JSON before the transaction is completed
@@ -94,7 +78,7 @@ module Appsignal
94
78
  @completed || false
95
79
  end
96
80
 
97
- alias original_to_json to_json
81
+ alias original_to_json to_json if method_defined? :to_json
98
82
 
99
83
  # Override default {Extension::Transaction#to_json} behavior to
100
84
  # return the stored the transaction JSON when the transaction was
@@ -111,3 +95,19 @@ module Appsignal
111
95
  end
112
96
  end
113
97
  end
98
+
99
+ module AppsignalTest
100
+ module Transaction
101
+ # Override the {Appsignal::Transaction.new} method so we can track which
102
+ # transactions are created on the {Appsignal::Testing.transactions} list.
103
+ #
104
+ # @see TransactionHelpers#last_transaction
105
+ def new(*_args)
106
+ transaction = super
107
+ Appsignal::Testing.transactions << transaction
108
+ transaction
109
+ end
110
+ end
111
+ end
112
+
113
+ Appsignal::Transaction.extend(AppsignalTest::Transaction)