appsignal 2.8.4-java → 2.9.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rubocop_todo.yml +7 -16
  4. data/.travis.yml +4 -1
  5. data/CHANGELOG.md +16 -0
  6. data/README.md +23 -0
  7. data/Rakefile +10 -7
  8. data/appsignal.gemspec +3 -0
  9. data/build_matrix.yml +5 -1
  10. data/ext/Rakefile +23 -16
  11. data/ext/agent.yml +37 -37
  12. data/ext/base.rb +86 -24
  13. data/ext/extconf.rb +33 -26
  14. data/gemfiles/rails-6.0.gemfile +5 -0
  15. data/lib/appsignal.rb +14 -489
  16. data/lib/appsignal/cli/diagnose.rb +84 -4
  17. data/lib/appsignal/cli/diagnose/paths.rb +0 -5
  18. data/lib/appsignal/cli/diagnose/utils.rb +17 -0
  19. data/lib/appsignal/cli/helpers.rb +6 -0
  20. data/lib/appsignal/cli/install.rb +13 -7
  21. data/lib/appsignal/config.rb +1 -2
  22. data/lib/appsignal/event_formatter.rb +4 -5
  23. data/lib/appsignal/event_formatter/moped/query_formatter.rb +60 -59
  24. data/lib/appsignal/extension.rb +2 -2
  25. data/lib/appsignal/helpers/instrumentation.rb +485 -0
  26. data/lib/appsignal/helpers/metrics.rb +55 -0
  27. data/lib/appsignal/hooks.rb +9 -8
  28. data/lib/appsignal/hooks/puma.rb +65 -9
  29. data/lib/appsignal/hooks/sidekiq.rb +90 -0
  30. data/lib/appsignal/integrations/mongo_ruby_driver.rb +7 -0
  31. data/lib/appsignal/integrations/railtie.rb +2 -1
  32. data/lib/appsignal/marker.rb +2 -3
  33. data/lib/appsignal/minutely.rb +164 -14
  34. data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -1
  35. data/lib/appsignal/system.rb +16 -18
  36. data/lib/appsignal/utils/rails_helper.rb +16 -0
  37. data/lib/appsignal/version.rb +1 -1
  38. data/spec/lib/appsignal/cli/diagnose_spec.rb +129 -22
  39. data/spec/lib/appsignal/cli/install_spec.rb +6 -1
  40. data/spec/lib/appsignal/config_spec.rb +3 -3
  41. data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +6 -0
  42. data/spec/lib/appsignal/event_formatter_spec.rb +168 -69
  43. data/spec/lib/appsignal/hooks/puma_spec.rb +129 -0
  44. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +147 -0
  45. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +24 -1
  46. data/spec/lib/appsignal/minutely_spec.rb +251 -21
  47. data/spec/lib/appsignal/system_spec.rb +0 -35
  48. data/spec/lib/appsignal/utils/hash_sanitizer_spec.rb +39 -31
  49. data/spec/lib/appsignal/utils/json_spec.rb +7 -3
  50. data/spec/lib/appsignal_spec.rb +27 -2
  51. data/spec/spec_helper.rb +13 -0
  52. data/spec/support/helpers/log_helpers.rb +6 -0
  53. data/spec/support/project_fixture/config/appsignal.yml +1 -0
  54. data/spec/support/stubs/sidekiq/api.rb +4 -0
  55. metadata +8 -2
@@ -19,41 +19,6 @@ describe Appsignal::System do
19
19
  end
20
20
  end
21
21
 
22
- describe ".installed_agent_architecture" do
23
- let(:const_name) { "GEM_EXT_PATH".freeze }
24
- let(:tmp_ext_dir) { File.join(tmp_dir, "ext") }
25
- let(:architecture_file) { File.join(Appsignal::System::GEM_EXT_PATH, "appsignal.architecture") }
26
- around do |example|
27
- original_gem_ext_path = Appsignal::System.const_get(const_name)
28
- Appsignal::System.send(:remove_const, const_name)
29
- Appsignal::System.const_set(const_name, tmp_ext_dir)
30
- example.run
31
- Appsignal::System.send(:remove_const, const_name)
32
- Appsignal::System.const_set(const_name, original_gem_ext_path)
33
- end
34
- after { FileUtils.rm_rf(tmp_ext_dir) }
35
- subject { described_class.installed_agent_architecture }
36
-
37
- context "with an ext/appsignal.architecture file" do
38
- before do
39
- FileUtils.mkdir_p(Appsignal::System::GEM_EXT_PATH)
40
- File.open(architecture_file, "w") do |file|
41
- file.write "foo"
42
- end
43
- end
44
-
45
- it "returns the contents of the file" do
46
- expect(subject).to eq("foo")
47
- end
48
- end
49
-
50
- context "without an ext/appsignal.architecture file" do
51
- it "returns nil" do
52
- expect(subject).to be_nil
53
- end
54
- end
55
- end
56
-
57
22
  describe ".agent_platform" do
58
23
  let(:os) { "linux-gnu" }
59
24
  let(:ldd_output) { "" }
@@ -30,19 +30,20 @@ describe Appsignal::Utils::HashSanitizer do
30
30
  let(:sanitized_params) { described_class.sanitize(params) }
31
31
  subject { sanitized_params }
32
32
 
33
- it { is_expected.to be_instance_of Hash }
34
- it { expect(subject[:text]).to eq("string") }
35
- it { expect(subject["string"]).to eq("string key value") }
36
- it do
33
+ it "returns a sanitized Hash" do
34
+ expect(subject).to_not eq(params)
35
+ is_expected.to be_instance_of Hash
36
+ expect(subject[:text]).to eq("string")
37
+ expect(subject["string"]).to eq("string key value")
37
38
  expect(subject[:file]).to be_instance_of String
38
39
  expect(subject[:file]).to include "::UploadedFile"
40
+ expect(subject[:float]).to eq(0.0)
41
+ expect(subject[:bool_true]).to be(true)
42
+ expect(subject[:bool_false]).to be(false)
43
+ expect(subject[:nil]).to be_nil
44
+ expect(subject[:int]).to eq(1)
45
+ expect(subject[:int64]).to eq(1 << 64)
39
46
  end
40
- it { expect(subject[:float]).to eq(0.0) }
41
- it { expect(subject[:bool_true]).to be(true) }
42
- it { expect(subject[:bool_false]).to be(false) }
43
- it { expect(subject[:nil]).to be_nil }
44
- it { expect(subject[:int]).to eq(1) }
45
- it { expect(subject[:int64]).to eq(1 << 64) }
46
47
 
47
48
  it "does not change the original params" do
48
49
  subject
@@ -50,29 +51,34 @@ describe Appsignal::Utils::HashSanitizer do
50
51
  expect(params[:hash][:nested_array][2]).to eq(file)
51
52
  end
52
53
 
53
- describe ":hash" do
54
+ describe ":hash key" do
54
55
  subject { sanitized_params[:hash] }
55
56
 
56
- it { is_expected.to be_instance_of Hash }
57
- it { expect(subject[:nested_text]).to eq("string") }
57
+ it "returns a sanitized Hash" do
58
+ expect(subject).to_not eq(params[:hash])
59
+ is_expected.to be_instance_of Hash
60
+ expect(subject[:nested_text]).to eq("string")
61
+ end
58
62
 
59
- describe ":nested_array" do
63
+ describe ":nested_array key" do
60
64
  subject { sanitized_params[:hash][:nested_array] }
61
65
 
62
- it { is_expected.to be_instance_of Array }
63
- it { expect(subject[0]).to eq("something") }
64
- it { expect(subject[1]).to eq("else") }
65
- it do
66
+ it "returns a sanitized Array" do
67
+ expect(subject).to_not eq(params[:hash][:nested_array])
68
+ is_expected.to be_instance_of Array
69
+ expect(subject[0]).to eq("something")
70
+ expect(subject[1]).to eq("else")
66
71
  expect(subject[2]).to be_instance_of String
67
72
  expect(subject[2]).to include "::UploadedFile"
68
73
  end
69
74
 
70
- describe ":nested_hash" do
75
+ describe ":nested_hash key" do
71
76
  subject { sanitized_params[:hash][:nested_array][3] }
72
77
 
73
- it { is_expected.to be_instance_of Hash }
74
- it { expect(subject[:key]).to eq("value") }
75
- it do
78
+ it "returns a sanitized Hash" do
79
+ expect(subject).to_not eq(params[:hash][:nested_array][3])
80
+ is_expected.to be_instance_of Hash
81
+ expect(subject[:key]).to eq("value")
76
82
  expect(subject[:file]).to be_instance_of String
77
83
  expect(subject[:file]).to include "::UploadedFile"
78
84
  end
@@ -86,17 +92,19 @@ describe Appsignal::Utils::HashSanitizer do
86
92
  end
87
93
  subject { sanitized_params }
88
94
 
89
- it { expect(subject[:text]).to eq(described_class::FILTERED) }
90
- it { expect(subject[:hash]).to eq(described_class::FILTERED) }
91
- it do
95
+ it "returns a sanitized Hash with the given keys filtered out" do
96
+ expect(subject).to_not eq(params)
97
+ expect(subject[:text]).to eq(described_class::FILTERED)
98
+ expect(subject[:hash]).to eq(described_class::FILTERED)
99
+
92
100
  expect(subject[:file]).to be_instance_of String
93
101
  expect(subject[:file]).to include "::UploadedFile"
102
+ expect(subject[:float]).to eq(0.0)
103
+ expect(subject[:bool_true]).to be(true)
104
+ expect(subject[:bool_false]).to be(false)
105
+ expect(subject[:nil]).to be_nil
106
+ expect(subject[:int]).to eq(1)
94
107
  end
95
- it { expect(subject[:float]).to eq(0.0) }
96
- it { expect(subject[:bool_true]).to be(true) }
97
- it { expect(subject[:bool_false]).to be(false) }
98
- it { expect(subject[:nil]).to be_nil }
99
- it { expect(subject[:int]).to eq(1) }
100
108
 
101
109
  context "with strings as key filter values" do
102
110
  let(:sanitized_params) do
@@ -108,7 +116,7 @@ describe Appsignal::Utils::HashSanitizer do
108
116
  end
109
117
  end
110
118
 
111
- describe ":hash" do
119
+ describe ":hash key" do
112
120
  let(:sanitized_params) do
113
121
  described_class.sanitize(params, %w[nested_text])
114
122
  end
@@ -16,10 +16,12 @@ describe Appsignal::Utils::JSON do
16
16
  }
17
17
  end
18
18
 
19
- it { is_expected.to eq %({"the":"payload","1":true,"":"test","foo":[1,2,"three"],"bar":null,"baz":{"foo":"bar"}}) }
19
+ it "returns a JSON string" do
20
+ is_expected.to eq %({"the":"payload","1":true,"":"test","foo":[1,2,"three"],"bar":null,"baz":{"foo":"bar"}})
21
+ end
20
22
  end
21
23
 
22
- context "with a body that contains strings with invalid utf-8 content" do
24
+ context "with a body that contains strings with invalid UTF-8 content" do
23
25
  let(:string_with_invalid_utf8) { [0x61, 0x61, 0x85].pack("c*") }
24
26
  let(:body) do
25
27
  {
@@ -34,7 +36,9 @@ describe Appsignal::Utils::JSON do
34
36
  }
35
37
  end
36
38
 
37
- it { is_expected.to eq %({"field_one":"aa","field_two":"aa�","field_three":["one","aa�"],"field_four":{"one":"aa�"}}) }
39
+ it "returns a JSON string with invalid UTF-8 content" do
40
+ is_expected.to eq %({"field_one":"aa","field_two":"aa�","field_three":["one","aa�"],"field_four":{"one":"aa�"}})
41
+ end
38
42
  end
39
43
  end
40
44
  end
@@ -90,12 +90,14 @@ describe Appsignal do
90
90
  unless Appsignal::System.jruby?
91
91
  it "installs the allocation event hook" do
92
92
  expect(Appsignal::Extension).to receive(:install_allocation_event_hook)
93
+ .and_call_original
93
94
  Appsignal.start
94
95
  end
95
96
  end
96
97
 
97
98
  it "should add the gc probe to minutely" do
98
- expect(Appsignal::Minutely).to receive(:add_gc_probe)
99
+ expect(Appsignal::Minutely).to receive(:register_garbage_collection_probe)
100
+ .and_call_original
99
101
  Appsignal.start
100
102
  end
101
103
  end
@@ -117,7 +119,7 @@ describe Appsignal do
117
119
  end
118
120
 
119
121
  it "should not add the gc probe to minutely" do
120
- expect(Appsignal::Minutely).not_to receive(:add_gc_probe)
122
+ expect(Appsignal::Minutely).not_to receive(:register_garbage_collection_probe)
121
123
  Appsignal.start
122
124
  end
123
125
  end
@@ -650,6 +652,29 @@ describe Appsignal do
650
652
 
651
653
  after { Appsignal.send_error(error, nil, namespace) }
652
654
  end
655
+
656
+ context "when given a block" do
657
+ it "yields the transaction and allows additional metadata to be set" do
658
+ captured_transaction = nil
659
+ Appsignal.send_error(StandardError.new("my_error")) do |transaction|
660
+ captured_transaction = transaction
661
+ transaction.set_action("my_action")
662
+ transaction.set_namespace("my_namespace")
663
+
664
+ # Don't flush the transaction, so we can inspect it
665
+ expect(transaction).to receive(:complete)
666
+ end
667
+ expect(captured_transaction.to_h).to include(
668
+ "namespace" => "my_namespace",
669
+ "action" => "my_action",
670
+ "error" => {
671
+ "name" => "StandardError",
672
+ "message" => "my_error",
673
+ "backtrace" => kind_of(String) # TODO: should be Array
674
+ }
675
+ )
676
+ end
677
+ end
653
678
  end
654
679
 
655
680
  describe ".listen_for_error" do
@@ -83,6 +83,7 @@ RSpec.configure do |config|
83
83
  end
84
84
 
85
85
  config.before do
86
+ stop_minutely_probes
86
87
  ENV["RAILS_ENV"] ||= "test"
87
88
  ENV["RACK_ENV"] ||= "test"
88
89
  ENV["PADRINO_ENV"] ||= "test"
@@ -114,6 +115,7 @@ RSpec.configure do |config|
114
115
 
115
116
  config.after do
116
117
  Thread.current[:appsignal_transaction] = nil
118
+ stop_minutely_probes
117
119
  end
118
120
 
119
121
  config.after :context do
@@ -121,4 +123,15 @@ RSpec.configure do |config|
121
123
  Appsignal.config = nil
122
124
  Appsignal.logger = nil
123
125
  end
126
+
127
+ def stop_minutely_probes
128
+ thread =
129
+ begin
130
+ Appsignal::Minutely.class_variable_get(:@@thread) # Fetch old thread
131
+ rescue NameError
132
+ nil
133
+ end
134
+ Appsignal::Minutely.stop
135
+ thread && thread.join # Wait for old thread to exit
136
+ end
124
137
  end
@@ -1,4 +1,10 @@
1
1
  module LogHelpers
2
+ def capture_logs(&block)
3
+ log = std_stream
4
+ use_logger_with(log, &block)
5
+ log_contents(log)
6
+ end
7
+
2
8
  def use_logger_with(log)
3
9
  Appsignal.logger = test_logger(log)
4
10
  yield
@@ -8,6 +8,7 @@ default: &defaults
8
8
  "REQUEST_METHOD", "REQUEST_URI", "SERVER_NAME", "SERVER_PORT",
9
9
  "SERVER_PROTOCOL", "HTTP_USER_AGENT"
10
10
  ]
11
+ enable_minutely_probes: false
11
12
 
12
13
  production:
13
14
  <<: *defaults
@@ -0,0 +1,4 @@
1
+ class Sidekiq
2
+ class API
3
+ end
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.8.4
4
+ version: 2.9.0
5
5
  platform: java
6
6
  authors:
7
7
  - Robert Beekman
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-02-28 00:00:00.000000000 Z
12
+ date: 2019-03-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -180,6 +180,7 @@ files:
180
180
  - gemfiles/rails-5.0.gemfile
181
181
  - gemfiles/rails-5.1.gemfile
182
182
  - gemfiles/rails-5.2.gemfile
183
+ - gemfiles/rails-6.0.gemfile
183
184
  - gemfiles/resque.gemfile
184
185
  - gemfiles/sequel-435.gemfile
185
186
  - gemfiles/sequel.gemfile
@@ -209,6 +210,8 @@ files:
209
210
  - lib/appsignal/extension.rb
210
211
  - lib/appsignal/extension/jruby.rb
211
212
  - lib/appsignal/garbage_collection_profiler.rb
213
+ - lib/appsignal/helpers/instrumentation.rb
214
+ - lib/appsignal/helpers/metrics.rb
212
215
  - lib/appsignal/hooks.rb
213
216
  - lib/appsignal/hooks/action_cable.rb
214
217
  - lib/appsignal/hooks/active_support_notifications.rb
@@ -259,6 +262,7 @@ files:
259
262
  - lib/appsignal/utils/hash_sanitizer.rb
260
263
  - lib/appsignal/utils/json.rb
261
264
  - lib/appsignal/utils/query_params_sanitizer.rb
265
+ - lib/appsignal/utils/rails_helper.rb
262
266
  - lib/appsignal/version.rb
263
267
  - lib/sequel/extensions/appsignal_integration.rb
264
268
  - resources/appsignal.yml.erb
@@ -366,6 +370,7 @@ files:
366
370
  - spec/support/rails/my_app.rb
367
371
  - spec/support/shared_examples/instrument.rb
368
372
  - spec/support/stubs/delayed_job.rb
373
+ - spec/support/stubs/sidekiq/api.rb
369
374
  - support/bundler_wrapper
370
375
  - support/install_deps
371
376
  homepage: https://github.com/appsignal/appsignal-ruby
@@ -496,3 +501,4 @@ test_files:
496
501
  - spec/support/rails/my_app.rb
497
502
  - spec/support/shared_examples/instrument.rb
498
503
  - spec/support/stubs/delayed_job.rb
504
+ - spec/support/stubs/sidekiq/api.rb