appsignal 2.11.0.beta.4-java → 2.11.0.beta.5-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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.semaphore/semaphore.yml +57 -1
  3. data/CHANGELOG.md +12 -0
  4. data/README.md +4 -4
  5. data/Rakefile +16 -4
  6. data/appsignal.gemspec +1 -1
  7. data/build_matrix.yml +2 -2
  8. data/ext/Rakefile +2 -0
  9. data/ext/agent.yml +19 -19
  10. data/ext/base.rb +7 -0
  11. data/ext/extconf.rb +2 -0
  12. data/lib/appsignal.rb +1 -0
  13. data/lib/appsignal/auth_check.rb +4 -2
  14. data/lib/appsignal/cli/diagnose.rb +1 -1
  15. data/lib/appsignal/config.rb +35 -2
  16. data/lib/appsignal/extension.rb +6 -5
  17. data/lib/appsignal/extension/jruby.rb +6 -5
  18. data/lib/appsignal/hooks.rb +23 -0
  19. data/lib/appsignal/hooks/active_job.rb +32 -9
  20. data/lib/appsignal/hooks/puma.rb +0 -1
  21. data/lib/appsignal/hooks/sidekiq.rb +0 -1
  22. data/lib/appsignal/probes.rb +7 -0
  23. data/lib/appsignal/probes/puma.rb +1 -1
  24. data/lib/appsignal/probes/sidekiq.rb +3 -1
  25. data/lib/appsignal/utils/deprecation_message.rb +1 -1
  26. data/lib/appsignal/version.rb +1 -1
  27. data/spec/lib/appsignal/auth_check_spec.rb +23 -0
  28. data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
  29. data/spec/lib/appsignal/capistrano3_spec.rb +1 -1
  30. data/spec/lib/appsignal/cli/diagnose_spec.rb +42 -0
  31. data/spec/lib/appsignal/config_spec.rb +21 -0
  32. data/spec/lib/appsignal/extension/jruby_spec.rb +31 -28
  33. data/spec/lib/appsignal/extension_install_failure_spec.rb +23 -0
  34. data/spec/lib/appsignal/hooks/activejob_spec.rb +44 -1
  35. data/spec/lib/appsignal/hooks_spec.rb +57 -0
  36. data/spec/lib/appsignal/marker_spec.rb +1 -1
  37. data/spec/spec_helper.rb +5 -0
  38. data/spec/support/helpers/config_helpers.rb +3 -2
  39. data/spec/support/helpers/transaction_helpers.rb +1 -1
  40. data/spec/support/testing.rb +19 -19
  41. metadata +6 -3
@@ -0,0 +1,7 @@
1
+ module Appsignal
2
+ module Probes
3
+ end
4
+ end
5
+
6
+ require "appsignal/probes/puma"
7
+ require "appsignal/probes/sidekiq"
@@ -1,11 +1,11 @@
1
1
  module Appsignal
2
2
  module Probes
3
- # @api private
4
3
  class PumaProbe
5
4
  def initialize
6
5
  @hostname = Appsignal.config[:hostname] || Socket.gethostname
7
6
  end
8
7
 
8
+ # @api private
9
9
  def call
10
10
  puma_stats = fetch_puma_stats
11
11
  return unless puma_stats
@@ -1,9 +1,10 @@
1
1
  module Appsignal
2
2
  module Probes
3
- # @api private
4
3
  class SidekiqProbe
4
+ # @api private
5
5
  attr_reader :config
6
6
 
7
+ # @api private
7
8
  def self.dependencies_present?
8
9
  Gem::Version.new(::Redis::VERSION) >= Gem::Version.new("3.3.5")
9
10
  end
@@ -16,6 +17,7 @@ module Appsignal
16
17
  require "sidekiq/api"
17
18
  end
18
19
 
20
+ # @api private
19
21
  def call
20
22
  track_redis_info
21
23
  track_stats
@@ -2,7 +2,7 @@ module Appsignal
2
2
  module Utils
3
3
  module DeprecationMessage
4
4
  def self.message(message, logger = Appsignal.logger)
5
- $stderr.puts "appsignal WARNING: #{message}"
5
+ Kernel.warn "appsignal WARNING: #{message}"
6
6
  logger.warn message
7
7
  end
8
8
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "2.11.0.beta.4".freeze
4
+ VERSION = "2.11.0.beta.5".freeze
5
5
  end
@@ -28,6 +28,29 @@ describe Appsignal::AuthCheck do
28
28
  end.join("&")
29
29
  end
30
30
 
31
+ describe ".new" do
32
+ describe "with logger argument" do
33
+ let(:err_stream) { std_stream }
34
+ let(:stderr) { err_stream.read }
35
+ let(:log_stream) { std_stream }
36
+ let(:log) { log_contents(log_stream) }
37
+
38
+ it "logs and prints a deprecation message" do
39
+ Appsignal.logger = test_logger(log_stream)
40
+
41
+ capture_std_streams(std_stream, err_stream) do
42
+ Appsignal::AuthCheck.new(config, Appsignal.logger)
43
+ end
44
+
45
+ deprecation_message =
46
+ "`Appsignal::AuthCheck.new`'s `logger` argument " \
47
+ "will be removed in the next major version."
48
+ expect(stderr).to include "appsignal WARNING: #{deprecation_message}"
49
+ expect(log).to contains_log :warn, deprecation_message
50
+ end
51
+ end
52
+ end
53
+
31
54
  describe "#perform" do
32
55
  subject { auth_check.perform }
33
56
 
@@ -10,7 +10,7 @@ if DependencyHelper.capistrano2_present?
10
10
  let(:capistrano_config) do
11
11
  Capistrano::Configuration.new.tap do |c|
12
12
  c.set(:rails_env, "production")
13
- c.set(:repository, "master")
13
+ c.set(:repository, "main")
14
14
  c.set(:deploy_to, "/home/username/app")
15
15
  c.set(:current_release, "")
16
16
  c.set(:current_revision, "503ce0923ed177a3ce000005")
@@ -15,7 +15,7 @@ if DependencyHelper.capistrano3_present?
15
15
  c.set(:log_level, :error)
16
16
  c.set(:logger, logger)
17
17
  c.set(:rails_env, "production")
18
- c.set(:repository, "master")
18
+ c.set(:repository, "main")
19
19
  c.set(:deploy_to, "/home/username/app")
20
20
  c.set(:current_release, "")
21
21
  c.set(:current_revision, "503ce0923ed177a3ce000005")
@@ -290,6 +290,8 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
290
290
  jruby = Appsignal::System.jruby?
291
291
  expect(output).to include(
292
292
  "Extension installation report",
293
+ "Installation result",
294
+ " Status: success",
293
295
  "Language details",
294
296
  " Implementation: #{jruby ? "jruby" : "ruby"}",
295
297
  " Ruby version: #{"#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}"}",
@@ -310,6 +312,46 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
310
312
  )
311
313
  end
312
314
 
315
+ context "with error in install report" do
316
+ let(:error) { RuntimeError.new("some error") }
317
+ before do
318
+ allow(File).to receive(:read).and_call_original
319
+ expect(File).to receive(:read)
320
+ .with(File.expand_path("../../../../../ext/install.report", __FILE__))
321
+ .and_return(
322
+ YAML.dump(
323
+ "result" => {
324
+ "status" => "error",
325
+ "error" => "RuntimeError: some error",
326
+ "backtrace" => error.backtrace
327
+ }
328
+ )
329
+ )
330
+ end
331
+
332
+ it "sends an error" do
333
+ run
334
+ expect(received_report["installation"]).to match(
335
+ "result" => {
336
+ "status" => "error",
337
+ "error" => "RuntimeError: some error",
338
+ "backtrace" => error.backtrace
339
+ }
340
+ )
341
+ end
342
+
343
+ it "prints the error" do
344
+ run
345
+
346
+ expect(output).to include(
347
+ "Extension installation report",
348
+ "Installation result",
349
+ "Status: error\n Error: RuntimeError: some error"
350
+ )
351
+ expect(output).to_not include("Raw report:")
352
+ end
353
+ end
354
+
313
355
  context "without install report" do
314
356
  let(:error) { RuntimeError.new("foo") }
315
357
  before do
@@ -244,6 +244,27 @@ describe Appsignal::Config do
244
244
  end
245
245
  end
246
246
 
247
+ context "with an overriden config file" do
248
+ let(:config) do
249
+ project_fixture_config("production", {}, Appsignal.logger, File.join(project_fixture_path, "config", "appsignal.yml"))
250
+ end
251
+
252
+ it "is valid and active" do
253
+ expect(config.valid?).to be_truthy
254
+ expect(config.active?).to be_truthy
255
+ end
256
+
257
+ context "with an invalid overriden config file" do
258
+ let(:config) do
259
+ project_fixture_config("production", {}, Appsignal.logger, File.join(project_fixture_path, "config", "missing.yml"))
260
+ end
261
+
262
+ it "is not valid" do
263
+ expect(config.valid?).to be_falsy
264
+ end
265
+ end
266
+ end
267
+
247
268
  context "with the config file causing an error" do
248
269
  let(:config_path) do
249
270
  File.expand_path(
@@ -1,42 +1,45 @@
1
- if Appsignal::System.jruby?
2
- describe Appsignal::Extension::Jruby do
3
- let(:extension) { Appsignal::Extension }
1
+ describe "JRuby extension", :jruby do
2
+ let(:extension) { Appsignal::Extension }
3
+ let(:jruby_module) { Appsignal::Extension::Jruby }
4
4
 
5
- describe "string conversions" do
6
- it "keeps the same value during string type conversions" do
7
- # UTF-8 string with NULL
8
- # Tests if the conversions between the conversions without breaking on
9
- # NULL terminated strings in C.
10
- string = "Merry Christmas! \u0000 🎄"
5
+ it "creates a JRuby extension module" do
6
+ expect(Appsignal::Extension::Jruby).to be_kind_of(Module)
7
+ end
11
8
 
12
- appsignal_string = extension.make_appsignal_string(string)
13
- ruby_string = extension.make_ruby_string(appsignal_string)
9
+ describe "string conversions" do
10
+ it "keeps the same value during string type conversions" do
11
+ # UTF-8 string with NULL
12
+ # Tests if the conversions between the conversions without breaking on
13
+ # NULL terminated strings in C.
14
+ string = "Merry Christmas! \u0000 🎄"
14
15
 
15
- expect(ruby_string).to eq("Merry Christmas! \u0000 🎄")
16
- end
17
- end
16
+ appsignal_string = extension.make_appsignal_string(string)
17
+ ruby_string = extension.make_ruby_string(appsignal_string)
18
18
 
19
- it "loads libappsignal with FFI" do
20
- expect(described_class.ffi_libraries.map(&:name).first).to include "libappsignal"
19
+ expect(ruby_string).to eq("Merry Christmas! \u0000 🎄")
21
20
  end
21
+ end
22
22
 
23
- describe ".lib_extension" do
24
- subject { described_class.lib_extension }
23
+ it "loads libappsignal with FFI" do
24
+ expect(jruby_module.ffi_libraries.map(&:name).first).to include "libappsignal"
25
+ end
26
+
27
+ describe ".lib_extension" do
28
+ subject { jruby_module.lib_extension }
25
29
 
26
- context "when on a darwin system" do
27
- before { expect(Appsignal::System).to receive(:agent_platform).and_return("darwin") }
30
+ context "when on a darwin system" do
31
+ before { expect(Appsignal::System).to receive(:agent_platform).and_return("darwin") }
28
32
 
29
- it "returns the extension for darwin" do
30
- is_expected.to eq "dylib"
31
- end
33
+ it "returns the extension for darwin" do
34
+ is_expected.to eq "dylib"
32
35
  end
36
+ end
33
37
 
34
- context "when on a linux system" do
35
- before { expect(Appsignal::System).to receive(:agent_platform).and_return("linux") }
38
+ context "when on a linux system" do
39
+ before { expect(Appsignal::System).to receive(:agent_platform).and_return("linux") }
36
40
 
37
- it "returns the lib extension for linux" do
38
- is_expected.to eq "so"
39
- end
41
+ it "returns the lib extension for linux" do
42
+ is_expected.to eq "so"
40
43
  end
41
44
  end
42
45
  end
@@ -0,0 +1,23 @@
1
+ describe Appsignal::Extension, :extension_installation_failure do
2
+ context "when the extension library cannot be loaded" do
3
+ # This test breaks the installation on purpose and is not run by default.
4
+ # See `rake test:failure`. If this test was run, run `rake
5
+ # extension:install` again to fix the extension installation.
6
+ it "prints and logs an error" do
7
+ # ENV var to make sure installation fails on purpurse
8
+ ENV["_TEST_APPSIGNAL_EXTENSION_FAILURE"] = "true"
9
+ `rake extension:install` # Run installation
10
+
11
+ require "open3"
12
+ _stdout, stderr, _status = Open3.capture3("bin/appsignal --version")
13
+ expect(stderr).to include("ERROR: AppSignal failed to load extension")
14
+ error_message =
15
+ if DependencyHelper.running_jruby?
16
+ "cannot open shared object file"
17
+ else
18
+ "LoadError: cannot load such file"
19
+ end
20
+ expect(stderr).to include(error_message)
21
+ end
22
+ end
23
+ end
@@ -154,9 +154,11 @@ if DependencyHelper.active_job_present?
154
154
  end
155
155
 
156
156
  it "reports the priority as tag on the transaction" do
157
- tags = { :priority => 10, :queue => queue }
157
+ tags = { :queue => queue }
158
158
  expect(Appsignal).to receive(:increment_counter)
159
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))
160
162
 
161
163
  perform_job(ActiveJobPriorityTestJob)
162
164
 
@@ -208,6 +210,47 @@ if DependencyHelper.active_job_present?
208
210
  .map { |event| event["name"] }
209
211
  expect(events).to eq(["perform_start.active_job", "perform.active_job"])
210
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
211
254
  end
212
255
 
213
256
  context "when wrapped in another transaction" do
@@ -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