appsignal 3.5.6-java → 3.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -2
- data/ext/agent.rb +27 -27
- data/lib/appsignal/rack/body_wrapper.rb +161 -0
- data/lib/appsignal/rack/generic_instrumentation.rb +17 -4
- data/lib/appsignal/rack/rails_instrumentation.rb +15 -3
- data/lib/appsignal/rack/sinatra_instrumentation.rb +15 -3
- data/lib/appsignal/rack/streaming_listener.rb +26 -35
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +1 -0
- data/resources/cacert.pem +321 -159
- data/spec/lib/appsignal/rack/body_wrapper_spec.rb +220 -0
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +3 -2
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -1
- data/spec/lib/appsignal/rack/streaming_listener_spec.rb +9 -53
- metadata +5 -3
@@ -0,0 +1,220 @@
|
|
1
|
+
describe Appsignal::Rack::BodyWrapper do
|
2
|
+
let(:nil_txn) { Appsignal::Transaction::NilTransaction.new }
|
3
|
+
|
4
|
+
describe "with a body that supports all possible features" do
|
5
|
+
it "reduces the supported methods to just each()" do
|
6
|
+
# which is the safest thing to do, since the body is likely broken
|
7
|
+
fake_body = double(:each => nil, :call => nil, :to_ary => [], :to_path => "/tmp/foo.bin",
|
8
|
+
:close => nil)
|
9
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
10
|
+
expect(wrapped).to respond_to(:each)
|
11
|
+
expect(wrapped).not_to respond_to(:to_ary)
|
12
|
+
expect(wrapped).not_to respond_to(:call)
|
13
|
+
expect(wrapped).to respond_to(:close)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "with a body only supporting each()" do
|
18
|
+
it "wraps with appropriate class" do
|
19
|
+
fake_body = double
|
20
|
+
allow(fake_body).to receive(:each)
|
21
|
+
|
22
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
23
|
+
expect(wrapped).to respond_to(:each)
|
24
|
+
expect(wrapped).not_to respond_to(:to_ary)
|
25
|
+
expect(wrapped).not_to respond_to(:call)
|
26
|
+
expect(wrapped).to respond_to(:close)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "reads out the body in full using each" do
|
30
|
+
fake_body = double
|
31
|
+
expect(fake_body).to receive(:each).once.and_yield("a").and_yield("b").and_yield("c")
|
32
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
33
|
+
expect { |b| wrapped.each(&b) }.to yield_successive_args("a", "b", "c")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns an Enumerator if each() gets called without a block" do
|
37
|
+
fake_body = double
|
38
|
+
expect(fake_body).to receive(:each).once.and_yield("a").and_yield("b").and_yield("c")
|
39
|
+
|
40
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
41
|
+
enum = wrapped.each
|
42
|
+
expect(enum).to be_kind_of(Enumerator)
|
43
|
+
expect { |b| enum.each(&b) }.to yield_successive_args("a", "b", "c")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "sets the exception raised inside each() into the Appsignal transaction" do
|
47
|
+
fake_body = double
|
48
|
+
expect(fake_body).to receive(:each).once.and_raise(Exception.new("Oops"))
|
49
|
+
|
50
|
+
txn = double("Appsignal transaction", "nil_transaction?" => false)
|
51
|
+
expect(txn).to receive(:set_error).once.with(instance_of(Exception))
|
52
|
+
|
53
|
+
wrapped = described_class.wrap(fake_body, txn)
|
54
|
+
expect do
|
55
|
+
expect { |b| wrapped.each(&b) }.to yield_control
|
56
|
+
end.to raise_error(/Oops/)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "closes the body and the transaction when it gets closed" do
|
60
|
+
fake_body = double
|
61
|
+
expect(fake_body).to receive(:each).once.and_yield("a").and_yield("b").and_yield("c")
|
62
|
+
|
63
|
+
txn = double("Appsignal transaction", "nil_transaction?" => false)
|
64
|
+
expect(Appsignal::Transaction).to receive(:complete_current!).once
|
65
|
+
|
66
|
+
wrapped = described_class.wrap(fake_body, txn)
|
67
|
+
expect { |b| wrapped.each(&b) }.to yield_successive_args("a", "b", "c")
|
68
|
+
expect { wrapped.close }.not_to raise_error
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "with a body supporting both each() and call" do
|
73
|
+
it "wraps with the wrapper that conceals call() and exposes each" do
|
74
|
+
fake_body = double
|
75
|
+
allow(fake_body).to receive(:each)
|
76
|
+
allow(fake_body).to receive(:call)
|
77
|
+
|
78
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
79
|
+
expect(wrapped).to respond_to(:each)
|
80
|
+
expect(wrapped).not_to respond_to(:to_ary)
|
81
|
+
expect(wrapped).not_to respond_to(:call)
|
82
|
+
expect(wrapped).not_to respond_to(:to_path)
|
83
|
+
expect(wrapped).to respond_to(:close)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "with a body supporting both to_ary and each" do
|
88
|
+
let(:fake_body) { double(:each => nil, :to_ary => []) }
|
89
|
+
it "wraps with appropriate class" do
|
90
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
91
|
+
expect(wrapped).to respond_to(:each)
|
92
|
+
expect(wrapped).to respond_to(:to_ary)
|
93
|
+
expect(wrapped).not_to respond_to(:call)
|
94
|
+
expect(wrapped).not_to respond_to(:to_path)
|
95
|
+
expect(wrapped).to respond_to(:close)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "reads out the body in full using each" do
|
99
|
+
expect(fake_body).to receive(:each).once.and_yield("a").and_yield("b").and_yield("c")
|
100
|
+
|
101
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
102
|
+
expect { |b| wrapped.each(&b) }.to yield_successive_args("a", "b", "c")
|
103
|
+
end
|
104
|
+
|
105
|
+
it "sets the exception raised inside each() into the Appsignal transaction" do
|
106
|
+
expect(fake_body).to receive(:each).once.and_raise(Exception.new("Oops"))
|
107
|
+
|
108
|
+
txn = double("Appsignal transaction", "nil_transaction?" => false)
|
109
|
+
expect(txn).to receive(:set_error).once.with(instance_of(Exception))
|
110
|
+
|
111
|
+
wrapped = described_class.wrap(fake_body, txn)
|
112
|
+
expect do
|
113
|
+
expect { |b| wrapped.each(&b) }.to yield_control
|
114
|
+
end.to raise_error(/Oops/)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "reads out the body in full using to_ary" do
|
118
|
+
expect(fake_body).to receive(:to_ary).and_return(["one", "two", "three"])
|
119
|
+
|
120
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
121
|
+
expect(wrapped.to_ary).to eq(["one", "two", "three"])
|
122
|
+
end
|
123
|
+
|
124
|
+
it "sends the exception raised inside to_ary() into the Appsignal and closes txn" do
|
125
|
+
fake_body = double
|
126
|
+
allow(fake_body).to receive(:each)
|
127
|
+
expect(fake_body).to receive(:to_ary).once.and_raise(Exception.new("Oops"))
|
128
|
+
expect(fake_body).not_to receive(:close) # Per spec we expect the body has closed itself
|
129
|
+
|
130
|
+
txn = double("Appsignal transaction", "nil_transaction?" => false)
|
131
|
+
expect(txn).to receive(:set_error).once.with(instance_of(Exception))
|
132
|
+
expect(Appsignal::Transaction).to receive(:complete_current!).once
|
133
|
+
|
134
|
+
wrapped = described_class.wrap(fake_body, txn)
|
135
|
+
expect { wrapped.to_ary }.to raise_error(/Oops/)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "with a body supporting both to_path and each" do
|
140
|
+
let(:fake_body) { double(:each => nil, :to_path => nil) }
|
141
|
+
|
142
|
+
it "wraps with appropriate class" do
|
143
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
144
|
+
expect(wrapped).to respond_to(:each)
|
145
|
+
expect(wrapped).not_to respond_to(:to_ary)
|
146
|
+
expect(wrapped).not_to respond_to(:call)
|
147
|
+
expect(wrapped).to respond_to(:to_path)
|
148
|
+
expect(wrapped).to respond_to(:close)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "reads out the body in full using each()" do
|
152
|
+
expect(fake_body).to receive(:each).once.and_yield("a").and_yield("b").and_yield("c")
|
153
|
+
|
154
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
155
|
+
expect { |b| wrapped.each(&b) }.to yield_successive_args("a", "b", "c")
|
156
|
+
end
|
157
|
+
|
158
|
+
it "sets the exception raised inside each() into the Appsignal transaction" do
|
159
|
+
expect(fake_body).to receive(:each).once.and_raise(Exception.new("Oops"))
|
160
|
+
|
161
|
+
txn = double("Appsignal transaction", "nil_transaction?" => false)
|
162
|
+
expect(txn).to receive(:set_error).once.with(instance_of(Exception))
|
163
|
+
|
164
|
+
wrapped = described_class.wrap(fake_body, txn)
|
165
|
+
expect do
|
166
|
+
expect { |b| wrapped.each(&b) }.to yield_control
|
167
|
+
end.to raise_error(/Oops/)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "sets the exception raised inside to_path() into the Appsignal transaction" do
|
171
|
+
allow(fake_body).to receive(:to_path).once.and_raise(Exception.new("Oops"))
|
172
|
+
|
173
|
+
txn = double("Appsignal transaction", "nil_transaction?" => false)
|
174
|
+
expect(txn).to receive(:set_error).once.with(instance_of(Exception))
|
175
|
+
expect(txn).not_to receive(:complete) # gets called by the caller via close()
|
176
|
+
|
177
|
+
wrapped = described_class.wrap(fake_body, txn)
|
178
|
+
expect { wrapped.to_path }.to raise_error(/Oops/)
|
179
|
+
end
|
180
|
+
|
181
|
+
it "exposes to_path to the sender" do
|
182
|
+
allow(fake_body).to receive(:to_path).and_return("/tmp/file.bin")
|
183
|
+
|
184
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
185
|
+
expect(wrapped.to_path).to eq("/tmp/file.bin")
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "with a body only supporting call()" do
|
190
|
+
let(:fake_body) { double(:call => nil) }
|
191
|
+
it "wraps with appropriate class" do
|
192
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
193
|
+
expect(wrapped).not_to respond_to(:each)
|
194
|
+
expect(wrapped).not_to respond_to(:to_ary)
|
195
|
+
expect(wrapped).to respond_to(:call)
|
196
|
+
expect(wrapped).not_to respond_to(:to_path)
|
197
|
+
expect(wrapped).to respond_to(:close)
|
198
|
+
end
|
199
|
+
|
200
|
+
it "passes the stream into the call() of the body" do
|
201
|
+
fake_rack_stream = double("stream")
|
202
|
+
expect(fake_body).to receive(:call).with(fake_rack_stream)
|
203
|
+
|
204
|
+
wrapped = described_class.wrap(fake_body, nil_txn)
|
205
|
+
expect { wrapped.call(fake_rack_stream) }.not_to raise_error
|
206
|
+
end
|
207
|
+
|
208
|
+
it "sets the exception raised inside call() into the Appsignal transaction" do
|
209
|
+
fake_rack_stream = double
|
210
|
+
allow(fake_body).to receive(:call).with(fake_rack_stream).and_raise(Exception.new("Oopsie"))
|
211
|
+
|
212
|
+
txn = double("Appsignal transaction", "nil_transaction?" => false)
|
213
|
+
expect(txn).to receive(:set_error).once.with(instance_of(Exception))
|
214
|
+
expect(txn).not_to receive(:complete) # gets called by the caller via close()
|
215
|
+
wrapped = described_class.wrap(fake_body, txn)
|
216
|
+
|
217
|
+
expect { wrapped.call(fake_rack_stream) }.to raise_error(/Oopsie/)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -50,7 +50,7 @@ describe Appsignal::Rack::GenericInstrumentation do
|
|
50
50
|
expect(app).to receive(:call).with(env)
|
51
51
|
end
|
52
52
|
|
53
|
-
context "with an exception", :error => true do
|
53
|
+
context "with an exception raised from call()", :error => true do
|
54
54
|
let(:error) { ExampleException }
|
55
55
|
let(:app) do
|
56
56
|
double.tap do |d|
|
@@ -58,8 +58,9 @@ describe Appsignal::Rack::GenericInstrumentation do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
it "records the exception" do
|
61
|
+
it "records the exception and completes the transaction" do
|
62
62
|
expect_any_instance_of(Appsignal::Transaction).to receive(:set_error).with(error)
|
63
|
+
expect(Appsignal::Transaction).to receive(:complete_current!)
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
@@ -65,7 +65,8 @@ if DependencyHelper.rails_present?
|
|
65
65
|
|
66
66
|
describe "#call_with_appsignal_monitoring" do
|
67
67
|
def run
|
68
|
-
middleware.call(env)
|
68
|
+
_status, _headers, body = middleware.call(env)
|
69
|
+
body.close # Rack will always call close() on the body
|
69
70
|
end
|
70
71
|
|
71
72
|
it "calls the wrapped app" do
|
@@ -126,7 +127,8 @@ if DependencyHelper.rails_present?
|
|
126
127
|
end
|
127
128
|
end
|
128
129
|
|
129
|
-
it "records the exception" do
|
130
|
+
it "records the exception and completes the transaction" do
|
131
|
+
expect(Appsignal::Transaction).to receive(:complete_current!)
|
130
132
|
expect { run }.to raise_error(error)
|
131
133
|
|
132
134
|
transaction_hash = last_transaction.to_h
|
@@ -3,7 +3,9 @@ if DependencyHelper.sinatra_present?
|
|
3
3
|
|
4
4
|
module SinatraRequestHelpers
|
5
5
|
def make_request(env)
|
6
|
-
middleware.call(env)
|
6
|
+
_status, _headers, body = middleware.call(env)
|
7
|
+
# Close the body so that the transaction gets completed
|
8
|
+
body&.close
|
7
9
|
end
|
8
10
|
|
9
11
|
def make_request_with_error(env, error)
|
@@ -90,10 +90,11 @@ describe Appsignal::Rack::StreamingListener do
|
|
90
90
|
context "with an exception in the instrumentation call" do
|
91
91
|
let(:error) { ExampleException }
|
92
92
|
|
93
|
-
it "should add the exception to the transaction" do
|
93
|
+
it "should add the exception to the transaction and complete the transaction" do
|
94
94
|
allow(app).to receive(:call).and_raise(error)
|
95
95
|
|
96
96
|
expect(transaction).to receive(:set_error).with(error)
|
97
|
+
expect(Appsignal::Transaction).to receive(:complete_current!).and_call_original
|
97
98
|
|
98
99
|
expect do
|
99
100
|
listener.call_with_appsignal_monitoring(env)
|
@@ -101,64 +102,19 @@ describe Appsignal::Rack::StreamingListener do
|
|
101
102
|
end
|
102
103
|
end
|
103
104
|
|
104
|
-
it "should wrap the body in a wrapper" do
|
105
|
-
expect(Appsignal::StreamWrapper).to receive(:new)
|
106
|
-
.with("body", transaction)
|
107
|
-
.and_return(wrapper)
|
108
|
-
|
105
|
+
it "should wrap the response body in a wrapper" do
|
109
106
|
body = listener.call_with_appsignal_monitoring(env)[2]
|
110
107
|
|
111
|
-
expect(body).to
|
108
|
+
expect(body).to be_kind_of(Appsignal::Rack::BodyWrapper)
|
112
109
|
end
|
113
110
|
end
|
114
111
|
end
|
115
112
|
|
116
113
|
describe Appsignal::StreamWrapper do
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
describe "#each" do
|
124
|
-
it "calls the original stream" do
|
125
|
-
expect(stream).to receive(:each)
|
126
|
-
|
127
|
-
wrapper.each
|
128
|
-
end
|
129
|
-
|
130
|
-
context "when #each raises an error" do
|
131
|
-
let(:error) { ExampleException }
|
132
|
-
|
133
|
-
it "records the exception" do
|
134
|
-
allow(stream).to receive(:each).and_raise(error)
|
135
|
-
|
136
|
-
expect(transaction).to receive(:set_error).with(error)
|
137
|
-
|
138
|
-
expect { wrapper.send(:each) }.to raise_error(error)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
describe "#close" do
|
144
|
-
it "closes the original stream and completes the transaction" do
|
145
|
-
expect(stream).to receive(:close)
|
146
|
-
expect(Appsignal::Transaction).to receive(:complete_current!)
|
147
|
-
|
148
|
-
wrapper.close
|
149
|
-
end
|
150
|
-
|
151
|
-
context "when #close raises an error" do
|
152
|
-
let(:error) { ExampleException }
|
153
|
-
|
154
|
-
it "records the exception and completes the transaction" do
|
155
|
-
allow(stream).to receive(:close).and_raise(error)
|
156
|
-
|
157
|
-
expect(transaction).to receive(:set_error).with(error)
|
158
|
-
expect(transaction).to receive(:complete)
|
159
|
-
|
160
|
-
expect { wrapper.send(:close) }.to raise_error(error)
|
161
|
-
end
|
162
|
-
end
|
114
|
+
it ".new returns an EnumerableWrapper" do
|
115
|
+
fake_body = double(:each => nil)
|
116
|
+
fake_txn = double
|
117
|
+
stream_wrapper = Appsignal::StreamWrapper.new(fake_body, fake_txn)
|
118
|
+
expect(stream_wrapper).to be_kind_of(Appsignal::Rack::EnumerableBodyWrapper)
|
163
119
|
end
|
164
120
|
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: 3.
|
4
|
+
version: 3.6.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Robert Beekman
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-02-
|
13
|
+
date: 2024-02-26 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rack
|
@@ -282,6 +282,7 @@ files:
|
|
282
282
|
- lib/appsignal/probes/helpers.rb
|
283
283
|
- lib/appsignal/probes/mri.rb
|
284
284
|
- lib/appsignal/probes/sidekiq.rb
|
285
|
+
- lib/appsignal/rack/body_wrapper.rb
|
285
286
|
- lib/appsignal/rack/generic_instrumentation.rb
|
286
287
|
- lib/appsignal/rack/rails_instrumentation.rb
|
287
288
|
- lib/appsignal/rack/sinatra_instrumentation.rb
|
@@ -380,6 +381,7 @@ files:
|
|
380
381
|
- spec/lib/appsignal/probes/gvl_spec.rb
|
381
382
|
- spec/lib/appsignal/probes/mri_spec.rb
|
382
383
|
- spec/lib/appsignal/probes/sidekiq_spec.rb
|
384
|
+
- spec/lib/appsignal/rack/body_wrapper_spec.rb
|
383
385
|
- spec/lib/appsignal/rack/generic_instrumentation_spec.rb
|
384
386
|
- spec/lib/appsignal/rack/rails_instrumentation_spec.rb
|
385
387
|
- spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb
|
@@ -465,7 +467,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
465
467
|
- !ruby/object:Gem::Version
|
466
468
|
version: '0'
|
467
469
|
requirements: []
|
468
|
-
rubygems_version: 3.4.
|
470
|
+
rubygems_version: 3.4.15
|
469
471
|
signing_key:
|
470
472
|
specification_version: 4
|
471
473
|
summary: Logs performance and exception data from your app to appsignal.com
|