appsignal 2.2.1 → 2.3.0.beta.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/appsignal.gemspec +1 -2
- data/ext/agent.yml +11 -11
- data/ext/appsignal_extension.c +17 -1
- data/lib/appsignal/config.rb +7 -4
- data/lib/appsignal/hooks.rb +1 -6
- data/lib/appsignal/hooks/action_cable.rb +113 -0
- data/lib/appsignal/hooks/active_support_notifications.rb +12 -4
- data/lib/appsignal/hooks/shoryuken.rb +11 -11
- data/lib/appsignal/hooks/sidekiq.rb +5 -3
- data/lib/appsignal/integrations/delayed_job_plugin.rb +5 -1
- data/lib/appsignal/integrations/resque_active_job.rb +4 -1
- data/lib/appsignal/transaction.rb +40 -13
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/config_spec.rb +8 -1
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +370 -0
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +39 -7
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +179 -34
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +125 -30
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +140 -21
- data/spec/lib/appsignal/hooks_spec.rb +0 -21
- data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +62 -17
- data/spec/lib/appsignal/integrations/resque_spec.rb +24 -12
- data/spec/lib/appsignal/transaction_spec.rb +230 -91
- data/spec/spec_helper.rb +8 -2
- data/spec/support/helpers/dependency_helper.rb +4 -0
- data/spec/support/helpers/env_helpers.rb +1 -1
- data/spec/support/helpers/log_helpers.rb +17 -0
- data/spec/support/matchers/contains_log.rb +7 -0
- data/spec/support/shared_examples/instrument.rb +2 -2
- metadata +13 -20
data/lib/appsignal/version.rb
CHANGED
@@ -84,8 +84,9 @@ describe Appsignal::Config do
|
|
84
84
|
expect(config.config_hash).to eq(
|
85
85
|
:debug => false,
|
86
86
|
:log => "file",
|
87
|
-
:ignore_errors => [],
|
88
87
|
:ignore_actions => [],
|
88
|
+
:ignore_errors => [],
|
89
|
+
:ignore_namespaces => [],
|
89
90
|
:filter_parameters => [],
|
90
91
|
:instrument_net_http => true,
|
91
92
|
:instrument_redis => true,
|
@@ -279,6 +280,8 @@ describe Appsignal::Config do
|
|
279
280
|
ENV["APPSIGNAL_APP_NAME"] = "App name"
|
280
281
|
ENV["APPSIGNAL_DEBUG"] = "true"
|
281
282
|
ENV["APPSIGNAL_IGNORE_ACTIONS"] = "action1,action2"
|
283
|
+
ENV["APPSIGNAL_IGNORE_ERRORS"] = "VerySpecificError,AnotherError"
|
284
|
+
ENV["APPSIGNAL_IGNORE_NAMESPACES"] = "admin,private_namespace"
|
282
285
|
ENV["APPSIGNAL_INSTRUMENT_NET_HTTP"] = "false"
|
283
286
|
ENV["APPSIGNAL_INSTRUMENT_REDIS"] = "false"
|
284
287
|
ENV["APPSIGNAL_INSTRUMENT_SEQUEL"] = "false"
|
@@ -294,6 +297,8 @@ describe Appsignal::Config do
|
|
294
297
|
expect(config[:name]).to eq "App name"
|
295
298
|
expect(config[:debug]).to be_truthy
|
296
299
|
expect(config[:ignore_actions]).to eq %w(action1 action2)
|
300
|
+
expect(config[:ignore_errors]).to eq %w(VerySpecificError AnotherError)
|
301
|
+
expect(config[:ignore_namespaces]).to eq %w(admin private_namespace)
|
297
302
|
expect(config[:instrument_net_http]).to be_falsey
|
298
303
|
expect(config[:instrument_redis]).to be_falsey
|
299
304
|
expect(config[:instrument_sequel]).to be_falsey
|
@@ -366,6 +371,7 @@ describe Appsignal::Config do
|
|
366
371
|
config[:http_proxy] = "http://localhost"
|
367
372
|
config[:ignore_actions] = %w(action1 action2)
|
368
373
|
config[:ignore_errors] = %w(VerySpecificError AnotherError)
|
374
|
+
config[:ignore_namespaces] = %w(admin private_namespace)
|
369
375
|
config[:log] = "stdout"
|
370
376
|
config[:log_path] = "/tmp"
|
371
377
|
config[:hostname] = "app1.local"
|
@@ -391,6 +397,7 @@ describe Appsignal::Config do
|
|
391
397
|
expect(ENV["_APPSIGNAL_HTTP_PROXY"]).to eq "http://localhost"
|
392
398
|
expect(ENV["_APPSIGNAL_IGNORE_ACTIONS"]).to eq "action1,action2"
|
393
399
|
expect(ENV["_APPSIGNAL_IGNORE_ERRORS"]).to eq "VerySpecificError,AnotherError"
|
400
|
+
expect(ENV["_APPSIGNAL_IGNORE_NAMESPACES"]).to eq "admin,private_namespace"
|
394
401
|
expect(ENV["_APPSIGNAL_FILTER_PARAMETERS"]).to eq "password,confirm_password"
|
395
402
|
expect(ENV["_APPSIGNAL_SEND_PARAMS"]).to eq "true"
|
396
403
|
expect(ENV["_APPSIGNAL_RUNNING_IN_CONTAINER"]).to eq "false"
|
@@ -0,0 +1,370 @@
|
|
1
|
+
describe Appsignal::Hooks::ActionCableHook do
|
2
|
+
if DependencyHelper.action_cable_present?
|
3
|
+
context "with ActionCable" do
|
4
|
+
require "action_cable/engine"
|
5
|
+
|
6
|
+
describe ".dependencies_present?" do
|
7
|
+
subject { described_class.new.dependencies_present? }
|
8
|
+
|
9
|
+
it "returns true" do
|
10
|
+
is_expected.to be_truthy
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe ActionCable::Channel::Base do
|
15
|
+
let(:transaction) do
|
16
|
+
Appsignal::Transaction.new(
|
17
|
+
transaction_id,
|
18
|
+
Appsignal::Transaction::ACTION_CABLE,
|
19
|
+
ActionDispatch::Request.new(env)
|
20
|
+
)
|
21
|
+
end
|
22
|
+
let(:channel) do
|
23
|
+
Class.new(ActionCable::Channel::Base) do
|
24
|
+
def speak(_data)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.to_s
|
28
|
+
"MyChannel"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
let(:log) { StringIO.new }
|
33
|
+
let(:server) do
|
34
|
+
ActionCable::Server::Base.new.tap do |s|
|
35
|
+
s.config.logger = ActiveSupport::Logger.new(log)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
let(:connection) { ActionCable::Connection::Base.new(server, env) }
|
39
|
+
let(:identifier) { { :channel => "MyChannel" }.to_json }
|
40
|
+
let(:params) { {} }
|
41
|
+
let(:request_id) { SecureRandom.uuid }
|
42
|
+
let(:transaction_id) { request_id }
|
43
|
+
let(:env) do
|
44
|
+
http_request_env_with_data("action_dispatch.request_id" => request_id, :params => params)
|
45
|
+
end
|
46
|
+
let(:instance) { channel.new(connection, identifier, params) }
|
47
|
+
subject { transaction.to_h }
|
48
|
+
before do
|
49
|
+
start_agent
|
50
|
+
expect(Appsignal.active?).to be_truthy
|
51
|
+
transaction
|
52
|
+
|
53
|
+
expect(Appsignal::Transaction).to receive(:create)
|
54
|
+
.with(transaction_id, Appsignal::Transaction::ACTION_CABLE, kind_of(ActionDispatch::Request))
|
55
|
+
.and_return(transaction)
|
56
|
+
allow(Appsignal::Transaction).to receive(:current).and_return(transaction)
|
57
|
+
# Make sure sample data is added
|
58
|
+
expect(transaction.ext).to receive(:finish).and_return(true)
|
59
|
+
# Stub complete call, stops it from being cleared in the extension
|
60
|
+
# And allows us to call `#to_h` on it after it's been completed.
|
61
|
+
expect(transaction.ext).to receive(:complete)
|
62
|
+
|
63
|
+
# Stub transmit call for subscribe/unsubscribe tests
|
64
|
+
allow(connection).to receive(:websocket)
|
65
|
+
.and_return(instance_double("ActionCable::Connection::WebSocket", :transmit => nil))
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#perform_action" do
|
69
|
+
it "creates a transaction for an action" do
|
70
|
+
instance.perform_action("message" => "foo", "action" => "speak")
|
71
|
+
|
72
|
+
expect(subject).to include(
|
73
|
+
"action" => "MyChannel#speak",
|
74
|
+
"error" => nil,
|
75
|
+
"id" => transaction_id,
|
76
|
+
"namespace" => Appsignal::Transaction::ACTION_CABLE,
|
77
|
+
"metadata" => {
|
78
|
+
"method" => "websocket",
|
79
|
+
"path" => "/blog"
|
80
|
+
}
|
81
|
+
)
|
82
|
+
expect(subject["events"].first).to include(
|
83
|
+
"allocation_count" => kind_of(Integer),
|
84
|
+
"body" => "",
|
85
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
86
|
+
"child_allocation_count" => kind_of(Integer),
|
87
|
+
"child_duration" => kind_of(Float),
|
88
|
+
"child_gc_duration" => kind_of(Float),
|
89
|
+
"count" => 1,
|
90
|
+
"gc_duration" => kind_of(Float),
|
91
|
+
"start" => kind_of(Float),
|
92
|
+
"duration" => kind_of(Float),
|
93
|
+
"name" => "perform_action.action_cable",
|
94
|
+
"title" => ""
|
95
|
+
)
|
96
|
+
expect(subject["sample_data"]).to include(
|
97
|
+
"params" => {
|
98
|
+
"action" => "speak",
|
99
|
+
"message" => "foo"
|
100
|
+
}
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
context "without request_id (standalone server)" do
|
105
|
+
let(:request_id) { nil }
|
106
|
+
let(:transaction_id) { SecureRandom.uuid }
|
107
|
+
let(:action_transaction) do
|
108
|
+
Appsignal::Transaction.new(
|
109
|
+
transaction_id,
|
110
|
+
Appsignal::Transaction::ACTION_CABLE,
|
111
|
+
ActionDispatch::Request.new(env)
|
112
|
+
)
|
113
|
+
end
|
114
|
+
before do
|
115
|
+
# Stub future (private AppSignal) transaction id generated by the hook.
|
116
|
+
expect(SecureRandom).to receive(:uuid).and_return(transaction_id)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "uses its own internal request_id set by the subscribed callback" do
|
120
|
+
# Subscribe action, sets the request_id
|
121
|
+
instance.subscribe_to_channel
|
122
|
+
expect(transaction.to_h["id"]).to eq(transaction_id)
|
123
|
+
|
124
|
+
# Expect another transaction for the action.
|
125
|
+
# This transaction will use the same request_id as the
|
126
|
+
# transaction id used to subscribe to the channel.
|
127
|
+
expect(Appsignal::Transaction).to receive(:create).with(
|
128
|
+
transaction_id,
|
129
|
+
Appsignal::Transaction::ACTION_CABLE,
|
130
|
+
kind_of(ActionDispatch::Request)
|
131
|
+
).and_return(action_transaction)
|
132
|
+
allow(Appsignal::Transaction).to receive(:current).and_return(action_transaction)
|
133
|
+
# Stub complete call, stops it from being cleared in the extension
|
134
|
+
# And allows us to call `#to_h` on it after it's been completed.
|
135
|
+
expect(action_transaction.ext).to receive(:complete)
|
136
|
+
|
137
|
+
instance.perform_action("message" => "foo", "action" => "speak")
|
138
|
+
expect(action_transaction.to_h["id"]).to eq(transaction_id)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "with an error in the action" do
|
143
|
+
let(:channel) do
|
144
|
+
Class.new(ActionCable::Channel::Base) do
|
145
|
+
def speak(_data)
|
146
|
+
raise VerySpecificError, "oh no!"
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.to_s
|
150
|
+
"MyChannel"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
it "registers an error on the transaction" do
|
156
|
+
expect do
|
157
|
+
instance.perform_action("message" => "foo", "action" => "speak")
|
158
|
+
end.to raise_error(VerySpecificError)
|
159
|
+
|
160
|
+
expect(subject).to include(
|
161
|
+
"action" => "MyChannel#speak",
|
162
|
+
"id" => transaction_id,
|
163
|
+
"namespace" => Appsignal::Transaction::ACTION_CABLE,
|
164
|
+
"metadata" => {
|
165
|
+
"method" => "websocket",
|
166
|
+
"path" => "/blog"
|
167
|
+
}
|
168
|
+
)
|
169
|
+
expect(subject["error"]).to include(
|
170
|
+
"backtrace" => kind_of(String),
|
171
|
+
"name" => "VerySpecificError",
|
172
|
+
"message" => "oh no!"
|
173
|
+
)
|
174
|
+
expect(subject["sample_data"]).to include(
|
175
|
+
"params" => {
|
176
|
+
"action" => "speak",
|
177
|
+
"message" => "foo"
|
178
|
+
}
|
179
|
+
)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "subscribe callback" do
|
185
|
+
let(:params) { { "internal" => true } }
|
186
|
+
|
187
|
+
it "creates a transaction for a subscription" do
|
188
|
+
instance.subscribe_to_channel
|
189
|
+
|
190
|
+
expect(subject).to include(
|
191
|
+
"action" => "MyChannel#subscribed",
|
192
|
+
"error" => nil,
|
193
|
+
"id" => transaction_id,
|
194
|
+
"namespace" => Appsignal::Transaction::ACTION_CABLE,
|
195
|
+
"metadata" => {
|
196
|
+
"method" => "websocket",
|
197
|
+
"path" => "/blog"
|
198
|
+
}
|
199
|
+
)
|
200
|
+
expect(subject["events"].first).to include(
|
201
|
+
"allocation_count" => kind_of(Integer),
|
202
|
+
"body" => "",
|
203
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
204
|
+
"child_allocation_count" => kind_of(Integer),
|
205
|
+
"child_duration" => kind_of(Float),
|
206
|
+
"child_gc_duration" => kind_of(Float),
|
207
|
+
"count" => 1,
|
208
|
+
"gc_duration" => kind_of(Float),
|
209
|
+
"start" => kind_of(Float),
|
210
|
+
"duration" => kind_of(Float),
|
211
|
+
"name" => "subscribed.action_cable",
|
212
|
+
"title" => ""
|
213
|
+
)
|
214
|
+
expect(subject["sample_data"]).to include(
|
215
|
+
"params" => { "internal" => "true" }
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
context "without request_id (standalone server)" do
|
220
|
+
let(:request_id) { nil }
|
221
|
+
let(:transaction_id) { SecureRandom.uuid }
|
222
|
+
before do
|
223
|
+
allow(SecureRandom).to receive(:uuid).and_return(transaction_id)
|
224
|
+
instance.subscribe_to_channel
|
225
|
+
end
|
226
|
+
|
227
|
+
it "uses its own internal request_id" do
|
228
|
+
expect(subject["id"]).to eq(transaction_id)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context "with an error in the callback" do
|
233
|
+
let(:channel) do
|
234
|
+
Class.new(ActionCable::Channel::Base) do
|
235
|
+
def subscribed
|
236
|
+
raise VerySpecificError, "oh no!"
|
237
|
+
end
|
238
|
+
|
239
|
+
def self.to_s
|
240
|
+
"MyChannel"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
it "registers an error on the transaction" do
|
246
|
+
expect do
|
247
|
+
instance.subscribe_to_channel
|
248
|
+
end.to raise_error(VerySpecificError)
|
249
|
+
|
250
|
+
expect(subject).to include(
|
251
|
+
"action" => "MyChannel#subscribed",
|
252
|
+
"id" => transaction_id,
|
253
|
+
"namespace" => Appsignal::Transaction::ACTION_CABLE,
|
254
|
+
"metadata" => {
|
255
|
+
"method" => "websocket",
|
256
|
+
"path" => "/blog"
|
257
|
+
}
|
258
|
+
)
|
259
|
+
expect(subject["error"]).to include(
|
260
|
+
"backtrace" => kind_of(String),
|
261
|
+
"name" => "VerySpecificError",
|
262
|
+
"message" => "oh no!"
|
263
|
+
)
|
264
|
+
expect(subject["sample_data"]).to include(
|
265
|
+
"params" => { "internal" => "true" }
|
266
|
+
)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "unsubscribe callback" do
|
272
|
+
let(:params) { { "internal" => true } }
|
273
|
+
|
274
|
+
it "creates a transaction for a subscription" do
|
275
|
+
instance.unsubscribe_from_channel
|
276
|
+
|
277
|
+
expect(subject).to include(
|
278
|
+
"action" => "MyChannel#unsubscribed",
|
279
|
+
"error" => nil,
|
280
|
+
"id" => transaction_id,
|
281
|
+
"namespace" => Appsignal::Transaction::ACTION_CABLE,
|
282
|
+
"metadata" => {
|
283
|
+
"method" => "websocket",
|
284
|
+
"path" => "/blog"
|
285
|
+
}
|
286
|
+
)
|
287
|
+
expect(subject["events"].first).to include(
|
288
|
+
"allocation_count" => kind_of(Integer),
|
289
|
+
"body" => "",
|
290
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
291
|
+
"child_allocation_count" => kind_of(Integer),
|
292
|
+
"child_duration" => kind_of(Float),
|
293
|
+
"child_gc_duration" => kind_of(Float),
|
294
|
+
"count" => 1,
|
295
|
+
"gc_duration" => kind_of(Float),
|
296
|
+
"start" => kind_of(Float),
|
297
|
+
"duration" => kind_of(Float),
|
298
|
+
"name" => "unsubscribed.action_cable",
|
299
|
+
"title" => ""
|
300
|
+
)
|
301
|
+
expect(subject["sample_data"]).to include(
|
302
|
+
"params" => { "internal" => "true" }
|
303
|
+
)
|
304
|
+
end
|
305
|
+
|
306
|
+
context "without request_id (standalone server)" do
|
307
|
+
let(:request_id) { nil }
|
308
|
+
let(:transaction_id) { SecureRandom.uuid }
|
309
|
+
before do
|
310
|
+
allow(SecureRandom).to receive(:uuid).and_return(transaction_id)
|
311
|
+
instance.unsubscribe_from_channel
|
312
|
+
end
|
313
|
+
|
314
|
+
it "uses its own internal request_id" do
|
315
|
+
expect(subject["id"]).to eq(transaction_id)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
context "with an error in the callback" do
|
320
|
+
let(:channel) do
|
321
|
+
Class.new(ActionCable::Channel::Base) do
|
322
|
+
def unsubscribed
|
323
|
+
raise VerySpecificError, "oh no!"
|
324
|
+
end
|
325
|
+
|
326
|
+
def self.to_s
|
327
|
+
"MyChannel"
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
it "registers an error on the transaction" do
|
333
|
+
expect do
|
334
|
+
instance.unsubscribe_from_channel
|
335
|
+
end.to raise_error(VerySpecificError)
|
336
|
+
|
337
|
+
expect(subject).to include(
|
338
|
+
"action" => "MyChannel#unsubscribed",
|
339
|
+
"id" => transaction_id,
|
340
|
+
"namespace" => Appsignal::Transaction::ACTION_CABLE,
|
341
|
+
"metadata" => {
|
342
|
+
"method" => "websocket",
|
343
|
+
"path" => "/blog"
|
344
|
+
}
|
345
|
+
)
|
346
|
+
expect(subject["error"]).to include(
|
347
|
+
"backtrace" => kind_of(String),
|
348
|
+
"name" => "VerySpecificError",
|
349
|
+
"message" => "oh no!"
|
350
|
+
)
|
351
|
+
expect(subject["sample_data"]).to include(
|
352
|
+
"params" => { "internal" => "true" }
|
353
|
+
)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
else
|
360
|
+
context "without ActionCable" do
|
361
|
+
describe ".dependencies_present?" do
|
362
|
+
subject { described_class.new.dependencies_present? }
|
363
|
+
|
364
|
+
it "returns false" do
|
365
|
+
is_expected.to be_falsy
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
@@ -1,45 +1,77 @@
|
|
1
1
|
describe Appsignal::Hooks::ActiveSupportNotificationsHook do
|
2
2
|
if active_support_present?
|
3
|
+
let(:notifier) { ActiveSupport::Notifications::Fanout.new }
|
4
|
+
let(:as) { ActiveSupport::Notifications }
|
3
5
|
before :context do
|
4
6
|
start_agent
|
5
7
|
end
|
6
8
|
before do
|
9
|
+
as.notifier = notifier
|
7
10
|
Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
|
8
11
|
end
|
9
12
|
|
10
|
-
let(:notifier) { ActiveSupport::Notifications::Fanout.new }
|
11
|
-
let(:instrumenter) { ActiveSupport::Notifications::Instrumenter.new(notifier) }
|
12
|
-
|
13
13
|
describe "#dependencies_present?" do
|
14
14
|
subject { described_class.new.dependencies_present? }
|
15
15
|
|
16
16
|
it { is_expected.to be_truthy }
|
17
17
|
end
|
18
18
|
|
19
|
-
it "
|
19
|
+
it "instruments an ActiveSupport::Notifications.instrument event" do
|
20
20
|
expect(Appsignal::Transaction.current).to receive(:start_event)
|
21
21
|
.at_least(:once)
|
22
22
|
expect(Appsignal::Transaction.current).to receive(:finish_event)
|
23
23
|
.at_least(:once)
|
24
24
|
.with("sql.active_record", nil, "SQL", 1)
|
25
25
|
|
26
|
-
return_value =
|
26
|
+
return_value = as.instrument("sql.active_record", :sql => "SQL") do
|
27
27
|
"value"
|
28
28
|
end
|
29
29
|
|
30
30
|
expect(return_value).to eq "value"
|
31
31
|
end
|
32
32
|
|
33
|
-
it "
|
33
|
+
it "does not instrument events whose name starts with a bang" do
|
34
34
|
expect(Appsignal::Transaction.current).not_to receive(:start_event)
|
35
35
|
expect(Appsignal::Transaction.current).not_to receive(:finish_event)
|
36
36
|
|
37
|
-
return_value =
|
37
|
+
return_value = as.instrument("!sql.active_record", :sql => "SQL") do
|
38
38
|
"value"
|
39
39
|
end
|
40
40
|
|
41
41
|
expect(return_value).to eq "value"
|
42
42
|
end
|
43
|
+
|
44
|
+
context "when an error is raised in an instrumented block" do
|
45
|
+
it "instruments an ActiveSupport::Notifications.instrument event" do
|
46
|
+
expect(Appsignal::Transaction.current).to receive(:start_event)
|
47
|
+
.at_least(:once)
|
48
|
+
expect(Appsignal::Transaction.current).to receive(:finish_event)
|
49
|
+
.at_least(:once)
|
50
|
+
.with("sql.active_record", nil, "SQL", 1)
|
51
|
+
|
52
|
+
expect do
|
53
|
+
as.instrument("sql.active_record", :sql => "SQL") do
|
54
|
+
raise VerySpecificError, "foo"
|
55
|
+
end
|
56
|
+
end.to raise_error(VerySpecificError, "foo")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when a message is thrown in an instrumented block" do
|
61
|
+
it "instruments an ActiveSupport::Notifications.instrument event" do
|
62
|
+
expect(Appsignal::Transaction.current).to receive(:start_event)
|
63
|
+
.at_least(:once)
|
64
|
+
expect(Appsignal::Transaction.current).to receive(:finish_event)
|
65
|
+
.at_least(:once)
|
66
|
+
.with("sql.active_record", nil, "SQL", 1)
|
67
|
+
|
68
|
+
expect do
|
69
|
+
as.instrument("sql.active_record", :sql => "SQL") do
|
70
|
+
throw :foo
|
71
|
+
end
|
72
|
+
end.to throw_symbol(:foo)
|
73
|
+
end
|
74
|
+
end
|
43
75
|
else
|
44
76
|
describe "#dependencies_present?" do
|
45
77
|
subject { described_class.new.dependencies_present? }
|