appsignal 2.4.3 → 2.5.0.alpha.1

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +14 -5
  3. data/.rubocop_todo.yml +3 -0
  4. data/.travis.yml +3 -4
  5. data/CHANGELOG.md +3 -0
  6. data/Rakefile +21 -6
  7. data/appsignal.gemspec +12 -5
  8. data/ext/Rakefile +27 -0
  9. data/ext/agent.yml +52 -21
  10. data/ext/base.rb +79 -0
  11. data/ext/extconf.rb +5 -76
  12. data/gemfiles/sequel-435.gemfile +5 -1
  13. data/gemfiles/sequel.gemfile +5 -1
  14. data/lib/appsignal.rb +11 -6
  15. data/lib/appsignal/cli.rb +1 -2
  16. data/lib/appsignal/cli/install.rb +3 -3
  17. data/lib/appsignal/config.rb +56 -37
  18. data/lib/appsignal/extension.rb +28 -4
  19. data/lib/appsignal/extension/jruby.rb +460 -0
  20. data/lib/appsignal/hooks/sidekiq.rb +4 -4
  21. data/lib/appsignal/integrations/capistrano/appsignal.cap +7 -2
  22. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +8 -3
  23. data/lib/appsignal/system.rb +16 -1
  24. data/lib/appsignal/transaction.rb +2 -2
  25. data/lib/appsignal/utils.rb +3 -1
  26. data/lib/appsignal/version.rb +1 -3
  27. data/spec/.rubocop.yml +3 -0
  28. data/spec/lib/appsignal/capistrano2_spec.rb +55 -41
  29. data/spec/lib/appsignal/capistrano3_spec.rb +87 -61
  30. data/spec/lib/appsignal/cli/diagnose_spec.rb +3 -3
  31. data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +4 -4
  32. data/spec/lib/appsignal/config_spec.rb +54 -21
  33. data/spec/lib/appsignal/extension/jruby_spec.rb +43 -0
  34. data/spec/lib/appsignal/extension_spec.rb +28 -12
  35. data/spec/lib/appsignal/hooks/sequel_spec.rb +7 -1
  36. data/spec/lib/appsignal/integrations/que_spec.rb +5 -5
  37. data/spec/lib/appsignal/system_spec.rb +5 -4
  38. data/spec/lib/appsignal/transaction_spec.rb +8 -8
  39. data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +4 -4
  40. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +3 -3
  41. data/spec/lib/appsignal_spec.rb +5 -3
  42. data/spec/spec_helper.rb +29 -8
  43. data/spec/support/helpers/config_helpers.rb +3 -2
  44. metadata +12 -7
@@ -260,12 +260,12 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
260
260
  "Agent diagnostics",
261
261
  " Error while parsing agent diagnostics report:",
262
262
  " Output: invalid agent\njson"
263
- expect(output).to match(/Error: \d+: unexpected token at 'invalid agent\njson'/)
263
+ expect(output).to match(/Error:( \d+:)? unexpected token at 'invalid agent\njson'/)
264
264
  end
265
265
 
266
266
  it "adds the output to the report" do
267
267
  expect(received_report["agent"]["error"])
268
- .to match(/\d+: unexpected token at 'invalid agent\njson'/)
268
+ .to match(/unexpected token at 'invalid agent\njson'/)
269
269
  expect(received_report["agent"]["output"]).to eq(["invalid agent", "json"])
270
270
  end
271
271
  end
@@ -652,7 +652,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
652
652
  it "adds paths to the report" do
653
653
  run
654
654
  expect(received_report["paths"].keys)
655
- .to match_array(%w(root_path working_dir log_dir_path log_file_path))
655
+ .to match_array(%w[root_path working_dir log_dir_path log_file_path])
656
656
  end
657
657
  end
658
658
 
@@ -75,7 +75,7 @@ describe Appsignal::CLI::NotifyOfDeploy do
75
75
 
76
76
  it "requires environment option" do
77
77
  expect { run }.to raise_error(SystemExit)
78
- expect(output).to include_missing_options(%w(environment))
78
+ expect(output).to include_missing_options(%w[environment])
79
79
  expect(output).to_not include_deploy_notification
80
80
  end
81
81
  end
@@ -98,7 +98,7 @@ describe Appsignal::CLI::NotifyOfDeploy do
98
98
  it "prints a missing required options error" do
99
99
  expect { run }.to raise_error(SystemExit)
100
100
  expect(output).to_not include_config_error
101
- expect(output).to include_missing_options(%w(revision user))
101
+ expect(output).to include_missing_options(%w[revision user])
102
102
  expect(output).to_not include_deploy_notification
103
103
  end
104
104
 
@@ -108,7 +108,7 @@ describe Appsignal::CLI::NotifyOfDeploy do
108
108
  it "prints a missing required option error" do
109
109
  expect { run }.to raise_error(SystemExit)
110
110
  expect(output).to_not include_config_error
111
- expect(output).to include_missing_options(%w(user))
111
+ expect(output).to include_missing_options(%w[user])
112
112
  expect(output).to_not include_deploy_notification
113
113
  end
114
114
  end
@@ -133,7 +133,7 @@ describe Appsignal::CLI::NotifyOfDeploy do
133
133
  it "requires name option" do
134
134
  expect { run }.to raise_error(SystemExit)
135
135
  expect(output).to_not include_config_error
136
- expect(output).to include_missing_options(%w(name))
136
+ expect(output).to include_missing_options(%w[name])
137
137
  expect(output).to_not include_deploy_notification
138
138
  end
139
139
  end
@@ -222,43 +222,54 @@ describe Appsignal::Config do
222
222
  end
223
223
  end
224
224
 
225
- describe "old-style config keys" do
226
- describe ":api_key" do
227
- subject { config[:push_api_key] }
225
+ describe "support for old config keys" do
226
+ let(:config) { project_fixture_config(env, {}, test_logger(log)) }
227
+ let(:log) { StringIO.new }
228
228
 
229
+ describe ":api_key" do
229
230
  context "without :push_api_key" do
230
- let(:config) { project_fixture_config("old_config") }
231
+ let(:env) { "old_config" }
231
232
 
232
233
  it "sets the :push_api_key with the old :api_key value" do
233
- expect(subject).to eq "def"
234
+ expect(config[:push_api_key]).to eq "def"
235
+ expect(config.config_hash).to_not have_key :api_key
236
+ expect(log_contents(log)).to contains_log :warn,
237
+ "Old configuration key found. Please update the 'api_key' to 'push_api_key'"
234
238
  end
235
239
  end
236
240
 
237
241
  context "with :push_api_key" do
238
- let(:config) { project_fixture_config("old_config_mixed_with_new_config") }
242
+ let(:env) { "old_config_mixed_with_new_config" }
239
243
 
240
- it "ignores the :api_key config" do
241
- expect(subject).to eq "ghi"
244
+ it "ignores the :api_key config and deletes it" do
245
+ expect(config[:push_api_key]).to eq "ghi"
246
+ expect(config.config_hash).to_not have_key :api_key
247
+ expect(log_contents(log)).to contains_log :warn,
248
+ "Old configuration key found. Please update the 'api_key' to 'push_api_key'"
242
249
  end
243
250
  end
244
251
  end
245
252
 
246
253
  describe ":ignore_exceptions" do
247
- subject { config[:ignore_errors] }
248
-
249
254
  context "without :ignore_errors" do
250
- let(:config) { project_fixture_config("old_config") }
255
+ let(:env) { "old_config" }
251
256
 
252
257
  it "sets :ignore_errors with the old :ignore_exceptions value" do
253
- expect(subject).to eq ["StandardError"]
258
+ expect(config[:ignore_errors]).to eq ["StandardError"]
259
+ expect(config.config_hash).to_not have_key :ignore_exceptions
260
+ expect(log_contents(log)).to contains_log :warn,
261
+ "Old configuration key found. Please update the 'ignore_exceptions' to 'ignore_errors'"
254
262
  end
255
263
  end
256
264
 
257
265
  context "with :ignore_errors" do
258
- let(:config) { project_fixture_config("old_config_mixed_with_new_config") }
266
+ let(:env) { "old_config_mixed_with_new_config" }
259
267
 
260
268
  it "ignores the :ignore_exceptions config" do
261
- expect(subject).to eq ["NoMethodError"]
269
+ expect(config[:ignore_errors]).to eq ["NoMethodError"]
270
+ expect(config.config_hash).to_not have_key :ignore_exceptions
271
+ expect(log_contents(log)).to contains_log :warn,
272
+ "Old configuration key found. Please update the 'ignore_exceptions' to 'ignore_errors'"
262
273
  end
263
274
  end
264
275
  end
@@ -298,9 +309,9 @@ describe Appsignal::Config do
298
309
  expect(config[:active]).to eq(true)
299
310
  expect(config[:name]).to eq "App name"
300
311
  expect(config[:debug]).to eq(true)
301
- expect(config[:ignore_actions]).to eq %w(action1 action2)
302
- expect(config[:ignore_errors]).to eq %w(ExampleStandardError AnotherError)
303
- expect(config[:ignore_namespaces]).to eq %w(admin private_namespace)
312
+ expect(config[:ignore_actions]).to eq %w[action1 action2]
313
+ expect(config[:ignore_errors]).to eq %w[ExampleStandardError AnotherError]
314
+ expect(config[:ignore_namespaces]).to eq %w[admin private_namespace]
304
315
  expect(config[:instrument_net_http]).to eq(false)
305
316
  expect(config[:instrument_redis]).to eq(false)
306
317
  expect(config[:instrument_sequel]).to eq(false)
@@ -384,13 +395,13 @@ describe Appsignal::Config do
384
395
  let(:config) { project_fixture_config(:production) }
385
396
  before do
386
397
  config[:http_proxy] = "http://localhost"
387
- config[:ignore_actions] = %w(action1 action2)
388
- config[:ignore_errors] = %w(ExampleStandardError AnotherError)
389
- config[:ignore_namespaces] = %w(admin private_namespace)
398
+ config[:ignore_actions] = %w[action1 action2]
399
+ config[:ignore_errors] = %w[ExampleStandardError AnotherError]
400
+ config[:ignore_namespaces] = %w[admin private_namespace]
390
401
  config[:log] = "stdout"
391
402
  config[:log_path] = "/tmp"
392
403
  config[:hostname] = "app1.local"
393
- config[:filter_parameters] = %w(password confirm_password)
404
+ config[:filter_parameters] = %w[password confirm_password]
394
405
  config[:running_in_container] = false
395
406
  config[:dns_servers] = ["8.8.8.8", "8.8.4.4"]
396
407
  config.write_to_environment
@@ -601,4 +612,26 @@ describe Appsignal::Config do
601
612
  end
602
613
  end
603
614
  end
615
+
616
+ describe "#validate" do
617
+ before { config.validate }
618
+ subject { config.valid? }
619
+ let(:config) { described_class.new(Dir.pwd, "production", :push_api_key => push_api_key) }
620
+
621
+ context "with missing push_api_key" do
622
+ let(:push_api_key) { nil }
623
+
624
+ it "sets valid to false" do
625
+ is_expected.to eq(false)
626
+ end
627
+ end
628
+
629
+ context "with push_api_key present" do
630
+ let(:push_api_key) { "abc" }
631
+
632
+ it "sets valid to true" do
633
+ is_expected.to eq(true)
634
+ end
635
+ end
636
+ end
604
637
  end
@@ -0,0 +1,43 @@
1
+ if Appsignal::System.jruby?
2
+ describe Appsignal::Extension::Jruby do
3
+ let(:extension) { Appsignal::Extension }
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 🎄"
11
+
12
+ appsignal_string = extension.make_appsignal_string(string)
13
+ ruby_string = extension.make_ruby_string(appsignal_string)
14
+
15
+ expect(ruby_string).to eq("Merry Christmas! \u0000 🎄")
16
+ end
17
+ end
18
+
19
+ it "loads libappsignal with FFI" do
20
+ expect(described_class.ffi_libraries.map(&:name).first).to include "libappsignal"
21
+ end
22
+
23
+ describe ".lib_extension" do
24
+ subject { described_class.lib_extension }
25
+
26
+ context "when on a darwin system" do
27
+ before { expect(Appsignal::System).to receive(:agent_platform).and_return("darwin") }
28
+
29
+ it "returns the extension for darwin" do
30
+ is_expected.to eq "dylib"
31
+ end
32
+ end
33
+
34
+ context "when on a linux system" do
35
+ before { expect(Appsignal::System).to receive(:agent_platform).and_return("linux") }
36
+
37
+ it "returns the lib extension for linux" do
38
+ is_expected.to eq "so"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,6 +1,4 @@
1
- require "fileutils"
2
-
3
- describe "extension loading and operation" do
1
+ describe Appsignal::Extension do
4
2
  describe ".agent_config" do
5
3
  subject { Appsignal::Extension.agent_config }
6
4
 
@@ -11,7 +9,7 @@ describe "extension loading and operation" do
11
9
  describe ".agent_version" do
12
10
  subject { Appsignal::Extension.agent_version }
13
11
 
14
- it { is_expected.to_not be_nil }
12
+ it { is_expected.to be_kind_of(String) }
15
13
  end
16
14
 
17
15
  context "when the extension library can be loaded" do
@@ -21,9 +19,29 @@ describe "extension loading and operation" do
21
19
  expect(Appsignal.extension_loaded?).to be_truthy
22
20
  end
23
21
 
24
- it "should have a start and stop method" do
25
- subject.start
26
- subject.stop
22
+ context "without valid config" do
23
+ let(:out_stream) { std_stream }
24
+ let(:output) { out_stream.read }
25
+
26
+ describe ".start" do
27
+ it "outputs a warning about not starting the extension" do
28
+ capture_std_streams(out_stream, out_stream) do
29
+ subject.start
30
+ end
31
+
32
+ expect(output).to include \
33
+ "WARNING: Error when reading appsignal config, appsignal not starting"
34
+ end
35
+ end
36
+
37
+ describe ".stop" do
38
+ it "does nothing" do
39
+ capture_std_streams(out_stream, out_stream) do
40
+ subject.stop
41
+ end
42
+ expect(output).to be_empty
43
+ end
44
+ end
27
45
  end
28
46
 
29
47
  context "with a valid config" do
@@ -101,11 +119,9 @@ describe "extension loading and operation" do
101
119
  context "when the extension library cannot be loaded" do
102
120
  subject { Appsignal::Extension }
103
121
 
104
- before :context do
105
- Appsignal.extension_loaded = false
106
- end
107
- after :context do
108
- Appsignal.extension_loaded = true
122
+ before do
123
+ allow(Appsignal).to receive(:extension_loaded).and_return(false)
124
+ allow(Appsignal).to receive(:testing?).and_return(false)
109
125
  end
110
126
 
111
127
  it "should indicate that the extension is not loaded" do
@@ -1,6 +1,12 @@
1
1
  describe Appsignal::Hooks::SequelHook do
2
2
  if DependencyHelper.sequel_present?
3
- let(:db) { Sequel.sqlite }
3
+ let(:db) do
4
+ if Appsignal::System.jruby?
5
+ Sequel.connect("jdbc:sqlite::memory:")
6
+ else
7
+ Sequel.sqlite
8
+ end
9
+ end
4
10
 
5
11
  before :context do
6
12
  start_agent
@@ -9,7 +9,7 @@ if DependencyHelper.que_present?
9
9
  :queue => "dfl",
10
10
  :job_class => "MyQueJob",
11
11
  :priority => 100,
12
- :args => %w(1 birds),
12
+ :args => %w[1 birds],
13
13
  :run_at => fixed_time,
14
14
  :error_count => 0
15
15
  }
@@ -26,7 +26,7 @@ if DependencyHelper.que_present?
26
26
  :run_at => fixed_time.to_s,
27
27
  :attempts => 0
28
28
  },
29
- :params => %w(1 birds)
29
+ :params => %w[1 birds]
30
30
  }
31
31
  end
32
32
 
@@ -92,7 +92,7 @@ if DependencyHelper.que_present?
92
92
  "title" => ""
93
93
  )
94
94
  expect(subject["sample_data"]).to include(
95
- "params" => %w(1 birds),
95
+ "params" => %w[1 birds],
96
96
  "metadata" => {
97
97
  "attempts" => 0,
98
98
  "id" => 123,
@@ -125,7 +125,7 @@ if DependencyHelper.que_present?
125
125
  "message" => error.message
126
126
  )
127
127
  expect(subject["sample_data"]).to include(
128
- "params" => %w(1 birds),
128
+ "params" => %w[1 birds],
129
129
  "metadata" => {
130
130
  "attempts" => 0,
131
131
  "id" => 123,
@@ -158,7 +158,7 @@ if DependencyHelper.que_present?
158
158
  "message" => error.message
159
159
  )
160
160
  expect(subject["sample_data"]).to include(
161
- "params" => %w(1 birds),
161
+ "params" => %w[1 birds],
162
162
  "metadata" => {
163
163
  "attempts" => 0,
164
164
  "id" => 123,
@@ -55,11 +55,12 @@ describe Appsignal::System do
55
55
  end
56
56
 
57
57
  describe ".agent_platform" do
58
- let(:os) { "linux" }
58
+ let(:os) { "linux-gnu" }
59
59
  let(:ldd_output) { "" }
60
60
  before do
61
61
  allow(described_class).to receive(:ldd_version_output).and_return(ldd_output)
62
- allow(Gem::Platform.local).to receive(:os).and_return(os)
62
+ allow(RbConfig::CONFIG).to receive(:[])
63
+ allow(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return(os)
63
64
  end
64
65
  subject { described_class.agent_platform }
65
66
 
@@ -110,7 +111,7 @@ describe Appsignal::System do
110
111
  end
111
112
 
112
113
  context "when on macOS" do
113
- let(:os) { "darwin" }
114
+ let(:os) { "darwin16.7.0" }
114
115
  let(:ldd_output) { "ldd: command not found" }
115
116
 
116
117
  it "returns the darwin build" do
@@ -119,7 +120,7 @@ describe Appsignal::System do
119
120
  end
120
121
 
121
122
  context "when on FreeBSD" do
122
- let(:os) { "freebsd" }
123
+ let(:os) { "freebsd11" }
123
124
  let(:ldd_output) { "ldd: illegal option -- -" }
124
125
 
125
126
  it "returns the darwin build" do
@@ -59,7 +59,7 @@ describe Appsignal::Transaction do
59
59
  new_transaction = create_transaction("2")
60
60
  expect(new_transaction).to eq(current_transaction)
61
61
  expect(new_transaction.transaction_id).to eq(transaction_id)
62
- end.to_not change { current_transaction }
62
+ end.to_not(change { current_transaction })
63
63
  end
64
64
 
65
65
  it "logs a debug message" do
@@ -835,7 +835,7 @@ describe Appsignal::Transaction do
835
835
  end
836
836
 
837
837
  context "with AppSignal filtering" do
838
- before { Appsignal.config.config_hash[:filter_parameters] = %w(foo) }
838
+ before { Appsignal.config.config_hash[:filter_parameters] = %w[foo] }
839
839
  after { Appsignal.config.config_hash[:filter_parameters] = [] }
840
840
 
841
841
  it "returns sanitized custom params" do
@@ -871,16 +871,16 @@ describe Appsignal::Transaction do
871
871
 
872
872
  context "with an array" do
873
873
  let(:request) do
874
- Appsignal::Transaction::GenericRequest.new(background_env_with_data(:params => %w(arg1 arg2)))
874
+ Appsignal::Transaction::GenericRequest.new(background_env_with_data(:params => %w[arg1 arg2]))
875
875
  end
876
876
 
877
- it { is_expected.to eq %w(arg1 arg2) }
877
+ it { is_expected.to eq %w[arg1 arg2] }
878
878
 
879
879
  context "with AppSignal filtering" do
880
- before { Appsignal.config.config_hash[:filter_parameters] = %w(foo) }
880
+ before { Appsignal.config.config_hash[:filter_parameters] = %w[foo] }
881
881
  after { Appsignal.config.config_hash[:filter_parameters] = [] }
882
882
 
883
- it { is_expected.to eq %w(arg1 arg2) }
883
+ it { is_expected.to eq %w[arg1 arg2] }
884
884
  end
885
885
  end
886
886
 
@@ -901,7 +901,7 @@ describe Appsignal::Transaction do
901
901
  Appsignal::Transaction::GenericRequest.new \
902
902
  http_request_env_with_data(:params => { :foo => :bar, :baz => :bat })
903
903
  end
904
- before { Appsignal.config.config_hash[:filter_parameters] = %w(foo) }
904
+ before { Appsignal.config.config_hash[:filter_parameters] = %w[foo] }
905
905
  after { Appsignal.config.config_hash[:filter_parameters] = [] }
906
906
 
907
907
  it "should call the params sanitizer with filtering" do
@@ -1055,7 +1055,7 @@ describe Appsignal::Transaction do
1055
1055
  :both_symbols => :valid_value,
1056
1056
  :integer_value => 1,
1057
1057
  :hash_value => { "invalid" => "hash" },
1058
- :array_value => %w(invalid array),
1058
+ :array_value => %w[invalid array],
1059
1059
  :to_long_value => SecureRandom.urlsafe_base64(101),
1060
1060
  :object => Object.new,
1061
1061
  SecureRandom.urlsafe_base64(101) => "to_long_key"
@@ -82,7 +82,7 @@ describe Appsignal::Utils::ParamsSanitizer do
82
82
 
83
83
  context "with :filter_parameters option" do
84
84
  let(:sanitized_params) do
85
- described_class.sanitize(params, :filter_parameters => %w(text hash))
85
+ described_class.sanitize(params, :filter_parameters => %w[text hash])
86
86
  end
87
87
  subject { sanitized_params }
88
88
 
@@ -100,7 +100,7 @@ describe Appsignal::Utils::ParamsSanitizer do
100
100
 
101
101
  context "with strings as key filter values" do
102
102
  let(:sanitized_params) do
103
- described_class.sanitize(params, :filter_parameters => %w(string))
103
+ described_class.sanitize(params, :filter_parameters => %w[string])
104
104
  end
105
105
 
106
106
  it "sanitizes values" do
@@ -110,7 +110,7 @@ describe Appsignal::Utils::ParamsSanitizer do
110
110
 
111
111
  describe ":hash" do
112
112
  let(:sanitized_params) do
113
- described_class.sanitize(params, :filter_parameters => %w(nested_text))
113
+ described_class.sanitize(params, :filter_parameters => %w[nested_text])
114
114
  end
115
115
  subject { sanitized_params[:hash] }
116
116
 
@@ -121,7 +121,7 @@ describe Appsignal::Utils::ParamsSanitizer do
121
121
  describe ":nested_array" do
122
122
  describe ":nested_hash" do
123
123
  let(:sanitized_params) do
124
- described_class.sanitize(params, :filter_parameters => %w(key))
124
+ described_class.sanitize(params, :filter_parameters => %w[key])
125
125
  end
126
126
  subject { sanitized_params[:hash][:nested_array][3] }
127
127