airbrake 9.1.0 → 9.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/airbrake/rack.rb +25 -0
- data/lib/airbrake/rack/instrumentable.rb +28 -0
- data/lib/airbrake/rails.rb +17 -1
- data/lib/airbrake/rails/curb.rb +35 -0
- data/lib/airbrake/rails/event.rb +4 -0
- data/lib/airbrake/rails/excon_subscriber.rb +21 -0
- data/lib/airbrake/rails/http.rb +12 -0
- data/lib/airbrake/rails/http_client.rb +10 -0
- data/lib/airbrake/rails/net_http.rb +2 -15
- data/lib/airbrake/rails/typhoeus.rb +12 -0
- data/lib/airbrake/version.rb +1 -1
- data/spec/apps/rails/dummy_app.rb +53 -1
- data/spec/apps/rails/logs/32.log +13385 -0
- data/spec/integration/rails/rails_spec.rb +93 -1
- data/spec/unit/rack/instrumentable_spec.rb +89 -0
- data/spec/unit/rack/rack_spec.rb +46 -0
- data/spec/unit/rails/excon_spec.rb +46 -0
- metadata +87 -6
@@ -322,7 +322,7 @@ RSpec.describe "Rails integration specs" do
|
|
322
322
|
end
|
323
323
|
end
|
324
324
|
|
325
|
-
context "when an action performs a HTTP request" do
|
325
|
+
context "when an action performs a Net::HTTP request" do
|
326
326
|
let!(:example_request) do
|
327
327
|
stub_request(:get, 'http://example.com').to_return(body: '')
|
328
328
|
end
|
@@ -334,5 +334,97 @@ RSpec.describe "Rails integration specs" do
|
|
334
334
|
expect(example_request).to have_been_made
|
335
335
|
end
|
336
336
|
end
|
337
|
+
|
338
|
+
context "when an action performs a Curl request" do
|
339
|
+
let!(:example_request) do
|
340
|
+
stub_request(:get, 'http://example.com').to_return(body: '')
|
341
|
+
end
|
342
|
+
|
343
|
+
before { skip("JRuby doesn't support Curb") if Airbrake::JRUBY }
|
344
|
+
|
345
|
+
it "includes the http breakdown" do
|
346
|
+
expect(Airbrake).to receive(:notify_performance_breakdown)
|
347
|
+
.with(hash_including(groups: { view: be > 0, http: be > 0 }))
|
348
|
+
get '/breakdown_curl_http'
|
349
|
+
expect(example_request).to have_been_made
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
context "when an action performs a Curl::Easy request" do
|
354
|
+
let!(:example_request) do
|
355
|
+
stub_request(:get, 'http://example.com').to_return(body: '')
|
356
|
+
end
|
357
|
+
|
358
|
+
before { skip("JRuby doesn't support Curb") if Airbrake::JRUBY }
|
359
|
+
|
360
|
+
it "includes the http breakdown" do
|
361
|
+
expect(Airbrake).to receive(:notify_performance_breakdown)
|
362
|
+
.with(hash_including(groups: { view: be > 0, http: be > 0 }))
|
363
|
+
get '/breakdown_curl_http_easy'
|
364
|
+
expect(example_request).to have_been_made
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
context "when an action performs a Curl::Multi request" do
|
369
|
+
before { skip("JRuby doesn't support Curb") if Airbrake::JRUBY }
|
370
|
+
|
371
|
+
it "includes the http breakdown" do
|
372
|
+
expect(Airbrake).to receive(:notify_performance_breakdown)
|
373
|
+
.with(hash_including(groups: { view: be > 0, http: be > 0 }))
|
374
|
+
get '/breakdown_curl_http_multi'
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
context "when an action performs an Excon request" do
|
379
|
+
let!(:example_request) do
|
380
|
+
stub_request(:get, 'http://example.com').to_return(body: '')
|
381
|
+
end
|
382
|
+
|
383
|
+
it "includes the http breakdown" do
|
384
|
+
expect(Airbrake).to receive(:notify_performance_breakdown)
|
385
|
+
.with(hash_including(groups: { http: be > 0 }))
|
386
|
+
get '/breakdown_excon'
|
387
|
+
expect(example_request).to have_been_made
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
context "when an action performs a HTTP.rb request" do
|
392
|
+
let!(:example_request) do
|
393
|
+
stub_request(:get, 'http://example.com').to_return(body: '')
|
394
|
+
end
|
395
|
+
|
396
|
+
it "includes the http breakdown" do
|
397
|
+
expect(Airbrake).to receive(:notify_performance_breakdown)
|
398
|
+
.with(hash_including(groups: { http: be > 0 }))
|
399
|
+
get '/breakdown_http_rb'
|
400
|
+
expect(example_request).to have_been_made
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
context "when an action performs a HTTPClient request" do
|
405
|
+
let!(:example_request) do
|
406
|
+
stub_request(:get, 'http://example.com').to_return(body: '')
|
407
|
+
end
|
408
|
+
|
409
|
+
it "includes the http breakdown" do
|
410
|
+
expect(Airbrake).to receive(:notify_performance_breakdown)
|
411
|
+
.with(hash_including(groups: { http: be > 0 }))
|
412
|
+
get '/breakdown_http_client'
|
413
|
+
expect(example_request).to have_been_made
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
context "when an action performs a Typhoeus request" do
|
418
|
+
let!(:example_request) do
|
419
|
+
stub_request(:get, 'http://example.com').to_return(body: '')
|
420
|
+
end
|
421
|
+
|
422
|
+
it "includes the http breakdown" do
|
423
|
+
expect(Airbrake).to receive(:notify_performance_breakdown)
|
424
|
+
.with(hash_including(groups: { http: be > 0 }))
|
425
|
+
get '/breakdown_typhoeus'
|
426
|
+
expect(example_request).to have_been_made
|
427
|
+
end
|
428
|
+
end
|
337
429
|
end
|
338
430
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
RSpec.describe Airbrake::Rack::Instrumentable do
|
2
|
+
after { Airbrake::Rack::RequestStore.clear }
|
3
|
+
|
4
|
+
describe ".airbrake_capture_timing" do
|
5
|
+
let(:routes) { Airbrake::Rack::RequestStore[:routes] }
|
6
|
+
|
7
|
+
let(:klass) do
|
8
|
+
Class.new do
|
9
|
+
extend Airbrake::Rack::Instrumentable
|
10
|
+
|
11
|
+
def method; end
|
12
|
+
airbrake_capture_timing :method
|
13
|
+
|
14
|
+
def method_with_arg(a); end
|
15
|
+
airbrake_capture_timing :method_with_arg
|
16
|
+
|
17
|
+
def method_with_args(a, b); end
|
18
|
+
airbrake_capture_timing :method_with_args
|
19
|
+
|
20
|
+
def method_with_vla(*args); end
|
21
|
+
airbrake_capture_timing :method_with_vla
|
22
|
+
|
23
|
+
def method_with_args_and_vla(*args); end
|
24
|
+
airbrake_capture_timing :method_with_args_and_vla
|
25
|
+
|
26
|
+
def method_with_kwargs(foo:, bar:); end
|
27
|
+
airbrake_capture_timing :method_with_kwargs
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when request store doesn't have any routes" do
|
32
|
+
before { Airbrake::Rack::RequestStore.clear }
|
33
|
+
|
34
|
+
it "doesn't store timing of the tracked method" do
|
35
|
+
klass.new.method
|
36
|
+
expect(Airbrake::Rack::RequestStore.store).to be_empty
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when request store has a route" do
|
41
|
+
let(:groups) { routes['/about'][:groups] }
|
42
|
+
|
43
|
+
before do
|
44
|
+
Airbrake::Rack::RequestStore[:routes] = {
|
45
|
+
'/about' => {
|
46
|
+
method: 'GET',
|
47
|
+
response_type: :html,
|
48
|
+
groups: {}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
it "attaches timing for a method without an argument" do
|
54
|
+
klass.new.method
|
55
|
+
expect(groups).to match('method' => be > 0)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "attaches timing for a method with an argument" do
|
59
|
+
klass.new.method_with_arg(1)
|
60
|
+
expect(groups).to match('method_with_arg' => be > 0)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "attaches timing for a variable-length argument method" do
|
64
|
+
klass.new.method_with_vla(1, 2, 3)
|
65
|
+
expect(groups).to match('method_with_vla' => be > 0)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "attaches timing for a method with args and a variable-length array" do
|
69
|
+
klass.new.method_with_args_and_vla(1, 2, 3)
|
70
|
+
expect(groups).to match('method_with_args_and_vla' => be > 0)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "attaches timing for a method with kwargs" do
|
74
|
+
klass.new.method_with_kwargs(foo: 1, bar: 2)
|
75
|
+
expect(groups).to match('method_with_kwargs' => be > 0)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "attaches all timings for multiple methods to the request store" do
|
79
|
+
klass.new.method
|
80
|
+
klass.new.method_with_arg(1)
|
81
|
+
|
82
|
+
expect(groups).to match(
|
83
|
+
'method' => be > 0,
|
84
|
+
'method_with_arg' => be > 0
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
RSpec.describe Airbrake::Rack do
|
2
|
+
after { Airbrake::Rack::RequestStore.clear }
|
3
|
+
|
4
|
+
describe ".timing" do
|
5
|
+
let(:routes) { Airbrake::Rack::RequestStore[:routes] }
|
6
|
+
|
7
|
+
context "when request store doesn't have any routes" do
|
8
|
+
it "doesn't store timing" do
|
9
|
+
described_class.capture_timing('operation') {}
|
10
|
+
expect(Airbrake::Rack::RequestStore.store).to be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns the value of the block" do
|
14
|
+
expect(described_class.capture_timing('operation') { 1 }).to eq(1)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when request store has a route" do
|
19
|
+
before do
|
20
|
+
Airbrake::Rack::RequestStore[:routes] = {
|
21
|
+
'/about' => {
|
22
|
+
method: 'GET',
|
23
|
+
response_type: :html,
|
24
|
+
groups: {}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
it "attaches all timings for different operations to the request store" do
|
30
|
+
described_class.capture_timing('operation 1') {}
|
31
|
+
described_class.capture_timing('operation 2') {}
|
32
|
+
described_class.capture_timing('operation 3') {}
|
33
|
+
|
34
|
+
expect(routes['/about'][:groups]).to match(
|
35
|
+
'operation 1' => be > 0,
|
36
|
+
'operation 2' => be > 0,
|
37
|
+
'operation 3' => be > 0
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns the value of the block" do
|
42
|
+
expect(described_class.capture_timing('operation') { 1 }).to eq(1)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'airbrake/rails/excon_subscriber'
|
2
|
+
|
3
|
+
RSpec.describe Airbrake::Rails::Excon do
|
4
|
+
after { Airbrake::Rack::RequestStore.clear }
|
5
|
+
|
6
|
+
let(:event) { double(Airbrake::Rails::Event) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
allow(Airbrake::Rails::Event).to receive(:new).and_return(event)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when there are no routes in the request store" do
|
13
|
+
it "doesn't notify requests" do
|
14
|
+
expect(Airbrake).not_to receive(:notify_performance_breakdown)
|
15
|
+
subject.call([])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when there's a route in the request store" do
|
20
|
+
let(:route) { Airbrake::Rack::RequestStore[:routes]['/test-route'] }
|
21
|
+
|
22
|
+
before do
|
23
|
+
Airbrake::Rack::RequestStore[:routes] = {
|
24
|
+
'/test-route' => { groups: {} }
|
25
|
+
}
|
26
|
+
|
27
|
+
expect(event).to receive(:duration).and_return(0.1)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "sets http group value of that route" do
|
31
|
+
subject.call([])
|
32
|
+
expect(route[:groups][:http]).to eq(0.1)
|
33
|
+
end
|
34
|
+
|
35
|
+
context "and when the subscriber is called multiple times" do
|
36
|
+
before { expect(event).to receive(:duration).and_return(0.1) }
|
37
|
+
|
38
|
+
it "increments http group value of that route" do
|
39
|
+
subject.call([])
|
40
|
+
subject.call([])
|
41
|
+
|
42
|
+
expect(route[:groups][:http]).to eq(0.2)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: airbrake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 9.
|
4
|
+
version: 9.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Airbrake Technologies, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: airbrake-ruby
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '4.
|
19
|
+
version: '4.3'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '4.
|
26
|
+
version: '4.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -240,6 +240,76 @@ dependencies:
|
|
240
240
|
- - "~>"
|
241
241
|
- !ruby/object:Gem::Version
|
242
242
|
version: '5'
|
243
|
+
- !ruby/object:Gem::Dependency
|
244
|
+
name: curb
|
245
|
+
requirement: !ruby/object:Gem::Requirement
|
246
|
+
requirements:
|
247
|
+
- - "~>"
|
248
|
+
- !ruby/object:Gem::Version
|
249
|
+
version: '0.9'
|
250
|
+
type: :development
|
251
|
+
prerelease: false
|
252
|
+
version_requirements: !ruby/object:Gem::Requirement
|
253
|
+
requirements:
|
254
|
+
- - "~>"
|
255
|
+
- !ruby/object:Gem::Version
|
256
|
+
version: '0.9'
|
257
|
+
- !ruby/object:Gem::Dependency
|
258
|
+
name: excon
|
259
|
+
requirement: !ruby/object:Gem::Requirement
|
260
|
+
requirements:
|
261
|
+
- - "~>"
|
262
|
+
- !ruby/object:Gem::Version
|
263
|
+
version: '0.64'
|
264
|
+
type: :development
|
265
|
+
prerelease: false
|
266
|
+
version_requirements: !ruby/object:Gem::Requirement
|
267
|
+
requirements:
|
268
|
+
- - "~>"
|
269
|
+
- !ruby/object:Gem::Version
|
270
|
+
version: '0.64'
|
271
|
+
- !ruby/object:Gem::Dependency
|
272
|
+
name: http
|
273
|
+
requirement: !ruby/object:Gem::Requirement
|
274
|
+
requirements:
|
275
|
+
- - "~>"
|
276
|
+
- !ruby/object:Gem::Version
|
277
|
+
version: '2.2'
|
278
|
+
type: :development
|
279
|
+
prerelease: false
|
280
|
+
version_requirements: !ruby/object:Gem::Requirement
|
281
|
+
requirements:
|
282
|
+
- - "~>"
|
283
|
+
- !ruby/object:Gem::Version
|
284
|
+
version: '2.2'
|
285
|
+
- !ruby/object:Gem::Dependency
|
286
|
+
name: httpclient
|
287
|
+
requirement: !ruby/object:Gem::Requirement
|
288
|
+
requirements:
|
289
|
+
- - "~>"
|
290
|
+
- !ruby/object:Gem::Version
|
291
|
+
version: '2.8'
|
292
|
+
type: :development
|
293
|
+
prerelease: false
|
294
|
+
version_requirements: !ruby/object:Gem::Requirement
|
295
|
+
requirements:
|
296
|
+
- - "~>"
|
297
|
+
- !ruby/object:Gem::Version
|
298
|
+
version: '2.8'
|
299
|
+
- !ruby/object:Gem::Dependency
|
300
|
+
name: typhoeus
|
301
|
+
requirement: !ruby/object:Gem::Requirement
|
302
|
+
requirements:
|
303
|
+
- - "~>"
|
304
|
+
- !ruby/object:Gem::Version
|
305
|
+
version: '1.3'
|
306
|
+
type: :development
|
307
|
+
prerelease: false
|
308
|
+
version_requirements: !ruby/object:Gem::Requirement
|
309
|
+
requirements:
|
310
|
+
- - "~>"
|
311
|
+
- !ruby/object:Gem::Version
|
312
|
+
version: '1.3'
|
243
313
|
description: |
|
244
314
|
Airbrake is an online tool that provides robust exception tracking in any of
|
245
315
|
your Ruby applications. In doing so, it allows you to easily review errors, tie
|
@@ -266,6 +336,7 @@ files:
|
|
266
336
|
- lib/airbrake/rack/context_filter.rb
|
267
337
|
- lib/airbrake/rack/http_headers_filter.rb
|
268
338
|
- lib/airbrake/rack/http_params_filter.rb
|
339
|
+
- lib/airbrake/rack/instrumentable.rb
|
269
340
|
- lib/airbrake/rack/middleware.rb
|
270
341
|
- lib/airbrake/rack/request_body_filter.rb
|
271
342
|
- lib/airbrake/rack/request_store.rb
|
@@ -285,8 +356,13 @@ files:
|
|
285
356
|
- lib/airbrake/rails/active_record_subscriber.rb
|
286
357
|
- lib/airbrake/rails/app.rb
|
287
358
|
- lib/airbrake/rails/backtrace_cleaner.rb
|
359
|
+
- lib/airbrake/rails/curb.rb
|
288
360
|
- lib/airbrake/rails/event.rb
|
361
|
+
- lib/airbrake/rails/excon_subscriber.rb
|
362
|
+
- lib/airbrake/rails/http.rb
|
363
|
+
- lib/airbrake/rails/http_client.rb
|
289
364
|
- lib/airbrake/rails/net_http.rb
|
365
|
+
- lib/airbrake/rails/typhoeus.rb
|
290
366
|
- lib/airbrake/rake.rb
|
291
367
|
- lib/airbrake/rake/tasks.rb
|
292
368
|
- lib/airbrake/resque.rb
|
@@ -315,7 +391,9 @@ files:
|
|
315
391
|
- spec/unit/rack/context_filter_spec.rb
|
316
392
|
- spec/unit/rack/http_headers_filter_spec.rb
|
317
393
|
- spec/unit/rack/http_params_filter_spec.rb
|
394
|
+
- spec/unit/rack/instrumentable_spec.rb
|
318
395
|
- spec/unit/rack/middleware_spec.rb
|
396
|
+
- spec/unit/rack/rack_spec.rb
|
319
397
|
- spec/unit/rack/request_body_filter_spec.rb
|
320
398
|
- spec/unit/rack/request_store_spec.rb
|
321
399
|
- spec/unit/rack/route_filter_spec.rb
|
@@ -327,6 +405,7 @@ files:
|
|
327
405
|
- spec/unit/rails/action_controller_performance_breakdown_subscriber_spec.rb
|
328
406
|
- spec/unit/rails/action_controller_route_subscriber_spec.rb
|
329
407
|
- spec/unit/rails/active_record_subscriber_spec.rb
|
408
|
+
- spec/unit/rails/excon_spec.rb
|
330
409
|
- spec/unit/rake/tasks_spec.rb
|
331
410
|
- spec/unit/shoryuken_spec.rb
|
332
411
|
- spec/unit/sidekiq/retryable_jobs_filter_spec.rb
|
@@ -351,8 +430,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
351
430
|
- !ruby/object:Gem::Version
|
352
431
|
version: '0'
|
353
432
|
requirements: []
|
354
|
-
|
355
|
-
rubygems_version: 2.6.13
|
433
|
+
rubygems_version: 3.0.1
|
356
434
|
signing_key:
|
357
435
|
specification_version: 4
|
358
436
|
summary: Airbrake is an online tool that provides robust exception tracking in any
|
@@ -369,10 +447,12 @@ test_files:
|
|
369
447
|
- spec/unit/rack/request_body_filter_spec.rb
|
370
448
|
- spec/unit/rack/http_params_filter_spec.rb
|
371
449
|
- spec/unit/rack/http_headers_filter_spec.rb
|
450
|
+
- spec/unit/rack/rack_spec.rb
|
372
451
|
- spec/unit/rack/middleware_spec.rb
|
373
452
|
- spec/unit/rack/session_filter_spec.rb
|
374
453
|
- spec/unit/rack/context_filter_spec.rb
|
375
454
|
- spec/unit/rack/user_filter_spec.rb
|
455
|
+
- spec/unit/rack/instrumentable_spec.rb
|
376
456
|
- spec/unit/rack/user_spec.rb
|
377
457
|
- spec/unit/rack/route_filter_spec.rb
|
378
458
|
- spec/unit/rails/action_controller_performance_breakdown_subscriber_spec.rb
|
@@ -380,6 +460,7 @@ test_files:
|
|
380
460
|
- spec/unit/rails/action_cable/notify_callback_spec.rb
|
381
461
|
- spec/unit/rails/action_controller_notify_subscriber_spec.rb
|
382
462
|
- spec/unit/rails/action_controller_route_subscriber_spec.rb
|
463
|
+
- spec/unit/rails/excon_spec.rb
|
383
464
|
- spec/integration/sinatra/sinatra_spec.rb
|
384
465
|
- spec/integration/rack/rack_spec.rb
|
385
466
|
- spec/integration/shared_examples/rack_examples.rb
|