appsignal 3.0.1-java → 3.0.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 +64 -199
  3. data/CHANGELOG.md +40 -17
  4. data/Rakefile +12 -4
  5. data/appsignal.gemspec +19 -4
  6. data/build_matrix.yml +16 -24
  7. data/ext/agent.yml +17 -17
  8. data/ext/base.rb +12 -1
  9. data/gemfiles/capistrano2.gemfile +0 -1
  10. data/gemfiles/capistrano3.gemfile +0 -1
  11. data/gemfiles/grape.gemfile +0 -1
  12. data/gemfiles/no_dependencies.gemfile +2 -6
  13. data/gemfiles/rails-3.2.gemfile +2 -0
  14. data/gemfiles/rails-4.2.gemfile +6 -0
  15. data/gemfiles/resque-2.gemfile +0 -4
  16. data/gemfiles/sequel-435.gemfile +0 -1
  17. data/gemfiles/sequel.gemfile +0 -1
  18. data/gemfiles/sinatra.gemfile +0 -1
  19. data/lib/appsignal/extension.rb +50 -0
  20. data/lib/appsignal/helpers/instrumentation.rb +2 -2
  21. data/lib/appsignal/hooks.rb +1 -1
  22. data/lib/appsignal/integrations/padrino.rb +1 -1
  23. data/lib/appsignal/integrations/railtie.rb +1 -5
  24. data/lib/appsignal/integrations/sinatra.rb +1 -1
  25. data/lib/appsignal/transaction.rb +2 -2
  26. data/lib/appsignal/version.rb +1 -1
  27. data/mono.yml +16 -0
  28. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -0
  29. data/spec/lib/appsignal/extension_install_failure_spec.rb +0 -7
  30. data/spec/lib/appsignal/extension_spec.rb +43 -9
  31. data/spec/lib/appsignal/hooks_spec.rb +4 -1
  32. data/spec/lib/appsignal/transaction_spec.rb +17 -0
  33. data/spec/lib/appsignal/utils/data_spec.rb +133 -87
  34. data/spec/lib/appsignal_spec.rb +2 -2
  35. data/spec/lib/puma/appsignal_spec.rb +1 -1
  36. data/spec/spec_helper.rb +22 -0
  37. data/spec/support/testing.rb +11 -1
  38. data/support/install_deps +9 -8
  39. metadata +4 -5
  40. data/gemfiles/rails-4.0.gemfile +0 -6
  41. data/gemfiles/rails-4.1.gemfile +0 -6
@@ -4,7 +4,3 @@ gem 'resque', "~> 2.0"
4
4
  gem 'sinatra'
5
5
 
6
6
  gemspec :path => '../'
7
-
8
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.1.0")
9
- gem 'nokogiri', '~> 1.6.0'
10
- end
@@ -6,6 +6,5 @@ if RUBY_PLATFORM == "java"
6
6
  else
7
7
  gem 'sqlite3'
8
8
  end
9
- gem 'rack', '~> 1.6'
10
9
 
11
10
  gemspec :path => '../'
@@ -6,6 +6,5 @@ if RUBY_PLATFORM == "java"
6
6
  else
7
7
  gem 'sqlite3'
8
8
  end
9
- gem 'rack', '~> 1.6'
10
9
 
11
10
  gemspec :path => '../'
@@ -1,6 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'sinatra'
4
- gem 'rack', '~> 1.6'
5
4
 
6
5
  gemspec :path => '../'
@@ -40,6 +40,16 @@ module Appsignal
40
40
  def method_missing(m, *args, &block)
41
41
  super if Appsignal.testing?
42
42
  end
43
+
44
+ unless Appsignal.extension_loaded?
45
+ def data_map_new
46
+ Appsignal::Extension::MockData.new
47
+ end
48
+
49
+ def data_array_new
50
+ Appsignal::Extension::MockData.new
51
+ end
52
+ end
43
53
  end
44
54
 
45
55
  if Appsignal::System.jruby?
@@ -62,5 +72,45 @@ module Appsignal
62
72
  "#<#{self.class.name}:#{object_id} #{self}>"
63
73
  end
64
74
  end
75
+
76
+ # Mock of the {Data} class. This mock is used when the extension cannot be
77
+ # loaded. This mock listens to all method calls and does nothing, and
78
+ # prevents NoMethodErrors from being raised.
79
+ #
80
+ # Disabled in testing so we can make sure that we don't miss an extension
81
+ # function implementation.
82
+ #
83
+ # This class inherits from the {Data} class so that it passes type checks.
84
+ class MockData < Data
85
+ def initialize(*_args)
86
+ # JRuby extension requirement, as it sends a pointer to the Data object
87
+ # when creating it
88
+ end
89
+
90
+ def method_missing(_method, *_args, &_block)
91
+ super if Appsignal.testing?
92
+ end
93
+
94
+ def to_s
95
+ "{}"
96
+ end
97
+ end
98
+
99
+ # Mock of the {Transaction} class. This mock is used when the extension
100
+ # cannot be loaded. This mock listens to all method calls and does nothing,
101
+ # and prevents NoMethodErrors from being raised.
102
+ #
103
+ # Disabled in testing so we can make sure that we don't miss an extension
104
+ # function implementation.
105
+ class MockTransaction
106
+ def initialize(*_args)
107
+ # JRuby extension requirement, as it sends a pointer to the Transaction
108
+ # object when creating it
109
+ end
110
+
111
+ def method_missing(_method, *_args, &_block)
112
+ super if Appsignal.testing?
113
+ end
114
+ end
65
115
  end
66
116
  end
@@ -223,7 +223,7 @@ module Appsignal
223
223
  "The namespace argument for `Appsignal.send_error` is deprecated. " \
224
224
  "Please use the block method to set the namespace instead.\n\n" \
225
225
  " Appsignal.send_error(error) do |transaction|\n" \
226
- " transaction.namespace(#{namespace.inspect})\n" \
226
+ " transaction.set_namespace(#{namespace.inspect})\n" \
227
227
  " end\n\n" \
228
228
  "Appsignal.send_error called on location: #{call_location}"
229
229
  end
@@ -316,7 +316,7 @@ module Appsignal
316
316
  "The namespace argument for `Appsignal.set_error` is deprecated. " \
317
317
  "Please use the block method to set the namespace instead.\n\n" \
318
318
  " Appsignal.set_error(error) do |transaction|\n" \
319
- " transaction.namespace(#{namespace.inspect})\n" \
319
+ " transaction.set_namespace(#{namespace.inspect})\n" \
320
320
  " end\n\n" \
321
321
  "Appsignal.set_error called on location: #{call_location}"
322
322
  end
@@ -32,7 +32,7 @@ module Appsignal
32
32
  return unless dependencies_present?
33
33
  return if installed?
34
34
 
35
- Appsignal.logger.info("Installing #{name} hook")
35
+ Appsignal.logger.debug("Installing #{name} hook")
36
36
  begin
37
37
  install
38
38
  @installed = true
@@ -7,7 +7,7 @@ module Appsignal
7
7
  # @api private
8
8
  module PadrinoPlugin
9
9
  def self.init
10
- Appsignal.logger.info("Loading Padrino (#{Padrino::VERSION}) integration")
10
+ Appsignal.logger.debug("Loading Padrino (#{Padrino::VERSION}) integration")
11
11
 
12
12
  root = Padrino.mounted_root
13
13
  Appsignal.config = Appsignal::Config.new(root, Padrino.env)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Appsignal.logger.info("Loading Rails (#{Rails.version}) integration")
3
+ Appsignal.logger.debug("Loading Rails (#{Rails.version}) integration")
4
4
 
5
5
  require "appsignal/utils/rails_helper"
6
6
  require "appsignal/rack/rails_instrumentation"
@@ -30,10 +30,6 @@ module Appsignal
30
30
  Appsignal::Rack::RailsInstrumentation
31
31
  )
32
32
 
33
- if Appsignal.config[:enable_frontend_error_catching]
34
- app.middleware.insert_before(Appsignal::Rack::RailsInstrumentation)
35
- end
36
-
37
33
  Appsignal.start
38
34
  end
39
35
  end
@@ -3,7 +3,7 @@
3
3
  require "appsignal"
4
4
  require "appsignal/rack/sinatra_instrumentation"
5
5
 
6
- Appsignal.logger.info("Loading Sinatra (#{Sinatra::VERSION}) integration")
6
+ Appsignal.logger.debug("Loading Sinatra (#{Sinatra::VERSION}) integration")
7
7
 
8
8
  app_settings = ::Sinatra::Application.settings
9
9
  Appsignal.config = Appsignal::Config.new(
@@ -90,7 +90,7 @@ module Appsignal
90
90
  @transaction_id,
91
91
  @namespace,
92
92
  self.class.garbage_collection_profiler.total_time
93
- )
93
+ ) || Appsignal::Extension::MockTransaction.new
94
94
  end
95
95
 
96
96
  def nil_transaction?
@@ -228,7 +228,7 @@ module Appsignal
228
228
  # "Web" and "background_job" gets transformed to "Background".
229
229
  #
230
230
  # @example
231
- # transaction.set_action("admin")
231
+ # transaction.set_namespace("background")
232
232
  #
233
233
  # @param namespace [String] namespace name to use for this transaction.
234
234
  # @return [void]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "3.0.1".freeze
4
+ VERSION = "3.0.5".freeze
5
5
  end
data/mono.yml ADDED
@@ -0,0 +1,16 @@
1
+ ---
2
+ language: ruby
3
+ repo: "https://github.com/appsignal/appsignal-ruby"
4
+ bootstrap:
5
+ post:
6
+ - "rake extension:install"
7
+ clean:
8
+ post:
9
+ - "bundle exec rake extension:clean"
10
+ - "rm -rf pkg"
11
+ build:
12
+ command: "bundle exec rake build:all"
13
+ publish:
14
+ gem_files_dir: pkg/
15
+ test:
16
+ command: "bundle exec rake test"
@@ -115,6 +115,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
115
115
  it "logs to the log file" do
116
116
  run
117
117
  log_contents = File.read(config.log_file_path)
118
+ p log_contents
118
119
  expect(log_contents).to contains_log :info, "Starting AppSignal diagnose"
119
120
  end
120
121
 
@@ -1,13 +1,6 @@
1
1
  describe Appsignal::Extension, :extension_installation_failure do
2
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
3
  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
4
  require "open3"
12
5
  _stdout, stderr, _status = Open3.capture3("bin/appsignal --version")
13
6
  expect(stderr).to include("ERROR: AppSignal failed to load extension")
@@ -119,22 +119,56 @@ describe Appsignal::Extension do
119
119
  end
120
120
  end
121
121
 
122
- context "when the extension library cannot be loaded" do
123
- subject { Appsignal::Extension }
122
+ context "when the extension library cannot be loaded", :extension_installation_failure do
123
+ let(:ext) { Appsignal::Extension }
124
124
 
125
- before do
126
- allow(Appsignal).to receive(:extension_loaded).and_return(false)
127
- allow(Appsignal).to receive(:testing?).and_return(false)
125
+ around do |example|
126
+ Appsignal::Testing.without_testing { example.run }
128
127
  end
129
128
 
130
129
  it "should indicate that the extension is not loaded" do
131
130
  expect(Appsignal.extension_loaded?).to be_falsy
132
131
  end
133
132
 
134
- it "should not raise errors when methods are called" do
135
- expect do
136
- subject.something
137
- end.not_to raise_error
133
+ it "does not raise errors when methods are called" do
134
+ ext.appsignal_start
135
+ ext.something
136
+ end
137
+
138
+ describe Appsignal::Extension::MockData do
139
+ it "does not error on missing data_map_new extension method calls" do
140
+ map = ext.data_map_new
141
+ expect(map).to be_kind_of(Appsignal::Extension::MockData)
142
+ # Does not raise errors any arbitrary method call that does not exist
143
+ map.set_string("key", "value")
144
+ map.set_int("key", 123)
145
+ map.something
146
+ end
147
+
148
+ it "does not error on missing data_array_new extension method calls" do
149
+ array = ext.data_array_new
150
+ expect(array).to be_kind_of(Appsignal::Extension::MockData)
151
+ # Does not raise errors any arbitrary method call that does not exist
152
+ array.append_string("value")
153
+ array.append_int(123)
154
+ array.something
155
+ end
156
+ end
157
+
158
+ describe Appsignal::Extension::MockTransaction do
159
+ it "does not error on missing transaction extension method calls" do
160
+ transaction = described_class.new
161
+
162
+ transaction.start_event(0)
163
+ transaction.finish_event(
164
+ "name",
165
+ "title",
166
+ "body",
167
+ Appsignal::EventFormatter::DEFAULT,
168
+ 0
169
+ )
170
+ transaction.something
171
+ end
138
172
  end
139
173
  end
140
174
  end
@@ -68,7 +68,10 @@ describe Appsignal::Hooks do
68
68
  expect(Appsignal::Hooks.hooks[:mock_error_hook].installed?).to be_falsy
69
69
 
70
70
  expect(Appsignal.logger).to receive(:error).with("Error while installing mock_error_hook hook: error").once
71
- expect(Appsignal.logger).to receive(:debug).once do |message|
71
+ expect(Appsignal.logger).to receive(:debug).ordered do |message|
72
+ expect(message).to eq("Installing mock_error_hook hook")
73
+ end
74
+ expect(Appsignal.logger).to receive(:debug).ordered do |message|
72
75
  # Start of the error backtrace as debug log
73
76
  expect(message).to start_with(File.expand_path("../../../../", __FILE__))
74
77
  end
@@ -246,6 +246,23 @@ describe Appsignal::Transaction do
246
246
  expect(transaction.ext).to_not be_nil
247
247
  end
248
248
 
249
+ context "when extension is not loaded", :extension_installation_failure do
250
+ around do |example|
251
+ Appsignal::Testing.without_testing { example.run }
252
+ end
253
+
254
+ it "does not error on missing extension method calls" do
255
+ expect(transaction.ext).to be_kind_of(Appsignal::Extension::MockTransaction)
256
+ transaction.start_event
257
+ transaction.finish_event(
258
+ "name",
259
+ "title",
260
+ "body",
261
+ Appsignal::EventFormatter::DEFAULT
262
+ )
263
+ end
264
+ end
265
+
249
266
  it "sets the transaction id" do
250
267
  expect(transaction.transaction_id).to eq "1"
251
268
  end
@@ -4,110 +4,156 @@ describe Appsignal::Utils::Data do
4
4
  describe ".generate" do
5
5
  subject { Appsignal::Utils::Data.generate(body) }
6
6
 
7
- context "with a valid hash body" do
8
- let(:body) do
9
- {
10
- "the" => "payload",
11
- "int" => 1, # Fixnum
12
- "int61" => 1 << 61, # Fixnum
13
- "int62" => 1 << 62, # Bignum, this one still works
14
- "int63" => 1 << 63, # Bignum, turnover point for C, too big for long
15
- "int64" => 1 << 64, # Bignum
16
- "float" => 1.0,
17
- 1 => true,
18
- nil => "test",
19
- :foo => [1, 2, "three", { "foo" => "bar" }],
20
- "bar" => nil,
21
- "baz" => { "foo" => "bʊr", "arr" => [1, 2] }
22
- }
7
+ context "when extension is not loaded", :extension_installation_failure do
8
+ around do |example|
9
+ Appsignal::Testing.without_testing { example.run }
23
10
  end
24
11
 
25
- it { is_expected.to eq Appsignal::Utils::Data.generate(body) }
26
- it { is_expected.to_not eq Appsignal::Utils::Data.generate({}) }
27
-
28
- describe "#to_s" do
29
- it "returns a serialized hash" do
30
- expect(subject.to_s).to eq %({"":"test",) +
31
- %("1":true,) +
32
- %("bar":null,) +
33
- %("baz":{"arr":[1,2],"foo":"bʊr"},) +
34
- %("float":1.0,) +
35
- %("foo":[1,2,"three",{"foo":"bar"}],) +
36
- %("int":1,) +
37
- %("int61":#{1 << 61},) +
38
- %("int62":#{1 << 62},) +
39
- %("int63":"bigint:#{1 << 63}",) +
40
- %("int64":"bigint:#{1 << 64}",) +
41
- %("the":"payload"})
12
+ context "with valid hash body" do
13
+ let(:body) { hash_body }
14
+
15
+ it "does not error and returns MockData class" do
16
+ expect(subject).to be_kind_of(Appsignal::Extension::MockData)
17
+ expect(subject.to_s).to eql("{}")
42
18
  end
43
19
  end
44
- end
45
20
 
46
- context "with a valid array body" do
47
- let(:body) do
48
- [
49
- nil,
50
- true,
51
- false,
52
- "string",
53
- 1, # Fixnum
54
- 1.0, # Float
55
- 1 << 61, # Fixnum
56
- 1 << 62, # Bignum, this one still works
57
- 1 << 63, # Bignum, turnover point for C, too big for long
58
- 1 << 64, # Bignum
59
- { "arr" => [1, 2, "three"], "foo" => "bʊr" }
60
- ]
21
+ context "with valid array body" do
22
+ let(:body) { array_body }
23
+
24
+ it "does not error and returns MockData class" do
25
+ expect(subject).to be_kind_of(Appsignal::Extension::MockData)
26
+ expect(subject.to_s).to eql("{}")
27
+ end
61
28
  end
62
29
 
63
- it { is_expected.to eq Appsignal::Utils::Data.generate(body) }
64
- it { is_expected.to_not eq Appsignal::Utils::Data.generate({}) }
65
-
66
- describe "#to_s" do
67
- it "returns a serialized array" do
68
- expect(subject.to_s).to eq %([null,) +
69
- %(true,) +
70
- %(false,) +
71
- %(\"string\",) +
72
- %(1,) +
73
- %(1.0,) +
74
- %(#{1 << 61},) +
75
- %(#{1 << 62},) +
76
- %("bigint:#{1 << 63}",) +
77
- %("bigint:#{1 << 64}",) +
78
- %({\"arr\":[1,2,\"three\"],\"foo\":\"bʊr\"}])
30
+ context "with an invalid body" do
31
+ let(:body) { "body" }
32
+
33
+ it "raise a type error" do
34
+ expect do
35
+ subject
36
+ end.to raise_error TypeError
79
37
  end
80
38
  end
81
39
  end
82
40
 
83
- context "with a body that contains strings with invalid utf-8 content" do
84
- let(:string_with_invalid_utf8) { [0x61, 0x61, 0x85].pack("c*") }
85
- let(:body) do
86
- {
87
- "field_one" => [0x61, 0x61].pack("c*"),
88
- :field_two => string_with_invalid_utf8,
89
- "field_three" => [
90
- "one", string_with_invalid_utf8
91
- ],
92
- "field_four" => {
93
- "one" => string_with_invalid_utf8
94
- }
95
- }
41
+ context "when extension is loaded" do
42
+ context "with a valid hash body" do
43
+ let(:body) { hash_body }
44
+
45
+ it "returns a valid Data object" do
46
+ is_expected.to eq Appsignal::Utils::Data.generate(body)
47
+ is_expected.to_not eq Appsignal::Utils::Data.generate({})
48
+ end
49
+
50
+ describe "#to_s" do
51
+ it "returns a serialized hash" do
52
+ expect(subject.to_s).to eq %({"":"test",) +
53
+ %("1":true,) +
54
+ %("bar":null,) +
55
+ %("baz":{"arr":[1,2],"foo":"bʊr"},) +
56
+ %("float":1.0,) +
57
+ %("foo":[1,2,"three",{"foo":"bar"}],) +
58
+ %("int":1,) +
59
+ %("int61":#{1 << 61},) +
60
+ %("int62":#{1 << 62},) +
61
+ %("int63":"bigint:#{1 << 63}",) +
62
+ %("int64":"bigint:#{1 << 64}",) +
63
+ %("the":"payload"})
64
+ end
65
+ end
66
+ end
67
+
68
+ context "with a valid array body" do
69
+ let(:body) { array_body }
70
+
71
+ it "returns a valid Data object" do
72
+ is_expected.to eq Appsignal::Utils::Data.generate(body)
73
+ is_expected.to_not eq Appsignal::Utils::Data.generate({})
74
+ end
75
+
76
+ describe "#to_s" do
77
+ it "returns a serialized array" do
78
+ expect(subject.to_s).to eq %([null,) +
79
+ %(true,) +
80
+ %(false,) +
81
+ %(\"string\",) +
82
+ %(1,) +
83
+ %(1.0,) +
84
+ %(#{1 << 61},) +
85
+ %(#{1 << 62},) +
86
+ %("bigint:#{1 << 63}",) +
87
+ %("bigint:#{1 << 64}",) +
88
+ %({\"arr\":[1,2,\"three\"],\"foo\":\"bʊr\"}])
89
+ end
90
+ end
96
91
  end
97
92
 
98
- describe "#to_s" do
99
- it { expect(subject.to_s).to eq %({"field_four":{"one":"aa�"},"field_one":"aa","field_three":["one","aa�"],"field_two":"aa�"}) }
93
+ context "with a body that contains strings with invalid utf-8 content" do
94
+ let(:string_with_invalid_utf8) { [0x61, 0x61, 0x85].pack("c*") }
95
+ let(:body) do
96
+ {
97
+ "field_one" => [0x61, 0x61].pack("c*"),
98
+ :field_two => string_with_invalid_utf8,
99
+ "field_three" => [
100
+ "one", string_with_invalid_utf8
101
+ ],
102
+ "field_four" => {
103
+ "one" => string_with_invalid_utf8
104
+ }
105
+ }
106
+ end
107
+
108
+ describe "#to_s" do
109
+ it "returns a JSON representation in a String" do
110
+ expect(subject.to_s).to eq %({"field_four":{"one":"aa�"},"field_one":"aa","field_three":["one","aa�"],"field_two":"aa�"})
111
+ end
112
+ end
100
113
  end
101
- end
102
114
 
103
- context "with an invalid body" do
104
- let(:body) { "body" }
115
+ context "with an invalid body" do
116
+ let(:body) { "body" }
105
117
 
106
- it "should raise a type error" do
107
- expect do
108
- subject
109
- end.to raise_error TypeError
118
+ it "raises a type error" do
119
+ expect do
120
+ subject
121
+ end.to raise_error TypeError
122
+ end
110
123
  end
111
124
  end
112
125
  end
126
+
127
+ def hash_body
128
+ {
129
+ "the" => "payload",
130
+ "int" => 1, # Fixnum
131
+ "int61" => 1 << 61, # Fixnum
132
+ "int62" => 1 << 62, # Bignum, this one still works
133
+ "int63" => 1 << 63, # Bignum, turnover point for C, too big for long
134
+ "int64" => 1 << 64, # Bignum
135
+ "float" => 1.0,
136
+ 1 => true,
137
+ nil => "test",
138
+ :foo => [1, 2, "three", { "foo" => "bar" }],
139
+ "bar" => nil,
140
+ "baz" => { "foo" => "bʊr", "arr" => [1, 2] }
141
+ }
142
+ end
143
+
144
+ def array_body
145
+ [
146
+ nil,
147
+ true,
148
+ false,
149
+ "string",
150
+ 1, # Fixnum
151
+ 1.0, # Float
152
+ 1 << 61, # Fixnum
153
+ 1 << 62, # Bignum, this one still works
154
+ 1 << 63, # Bignum, turnover point for C, too big for long
155
+ 1 << 64, # Bignum
156
+ { "arr" => [1, 2, "three"], "foo" => "bʊr" }
157
+ ]
158
+ end
113
159
  end