appsignal 2.8.4-java → 2.9.0-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 (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