airbrake 7.4.0 → 7.5.0.pre.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/lib/airbrake/rack.rb +1 -0
- data/lib/airbrake/rack/middleware.rb +53 -1
- data/lib/airbrake/rack/route_filter.rb +45 -0
- data/lib/airbrake/version.rb +1 -1
- data/spec/integration/rails/rails_spec.rb +33 -0
- data/spec/integration/rails/rake_spec.rb +1 -1
- data/spec/integration/sinatra/sinatra_spec.rb +5 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/rack/route_filter_spec.rb +11 -0
- metadata +11 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: daaa847e504e6c5ce90d20d14abbfe22673742c8
|
4
|
+
data.tar.gz: bf1064650bc6e0ea0ac33913bb8f1ec27b914b8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9ca5aab85564501b4035eae6d3263c8ce2d0b3d2353b04326d9aa7c1c8538d5a2c226055b04a46c33b4e5c7260e6527ce89a34d5544a7e34371304118c0c269
|
7
|
+
data.tar.gz: 2b04e5b8828ae024ea513c0e8189f95490bdacdbaa9b511d121a8691f921de756968bde759e28673eb53feb5c477aac7d02896657ca5d23d5b6b984779d1a929
|
data/lib/airbrake/rack.rb
CHANGED
@@ -6,6 +6,8 @@ module Airbrake
|
|
6
6
|
#
|
7
7
|
# The middleware automatically sends information about the framework that
|
8
8
|
# uses it (name and version).
|
9
|
+
#
|
10
|
+
# For Rails apps the middleware collects route performance statistics.
|
9
11
|
class Middleware
|
10
12
|
# @return [Array<Class>] the list of Rack filters that read Rack request
|
11
13
|
# information and append it to notices
|
@@ -13,7 +15,8 @@ module Airbrake
|
|
13
15
|
Airbrake::Rack::ContextFilter,
|
14
16
|
Airbrake::Rack::SessionFilter,
|
15
17
|
Airbrake::Rack::HttpParamsFilter,
|
16
|
-
Airbrake::Rack::HttpHeadersFilter
|
18
|
+
Airbrake::Rack::HttpHeadersFilter,
|
19
|
+
Airbrake::Rack::RouteFilter,
|
17
20
|
|
18
21
|
# Optional filters (must be included by users):
|
19
22
|
# Airbrake::Rack::RequestBodyFilter
|
@@ -37,6 +40,9 @@ module Airbrake
|
|
37
40
|
RACK_FILTERS.each do |filter|
|
38
41
|
@notifier.add_filter(filter.new)
|
39
42
|
end
|
43
|
+
|
44
|
+
return unless defined?(Rails)
|
45
|
+
subscribe_route_stats_hook
|
40
46
|
end
|
41
47
|
|
42
48
|
# Rescues any exceptions, sends them to Airbrake and re-raises the
|
@@ -69,6 +75,8 @@ module Airbrake
|
|
69
75
|
notice.stash[:rack_request] =
|
70
76
|
if defined?(ActionDispatch::Request)
|
71
77
|
ActionDispatch::Request.new(env)
|
78
|
+
elsif defined?(Sinatra::Request)
|
79
|
+
Sinatra::Request.new(env)
|
72
80
|
else
|
73
81
|
::Rack::Request.new(env)
|
74
82
|
end
|
@@ -87,6 +95,50 @@ module Airbrake
|
|
87
95
|
env['sinatra.error'] ||
|
88
96
|
env['rack.exception']
|
89
97
|
end
|
98
|
+
|
99
|
+
def subscribe_route_stats_hook
|
100
|
+
ActiveSupport::Notifications.subscribe(
|
101
|
+
'process_action.action_controller'
|
102
|
+
) do |*args|
|
103
|
+
@all_routes ||= find_all_routes
|
104
|
+
|
105
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
106
|
+
payload = event.payload
|
107
|
+
|
108
|
+
if (route = find_route(payload[:params]))
|
109
|
+
@notifier.inc_request(
|
110
|
+
payload[:method],
|
111
|
+
route,
|
112
|
+
payload[:status],
|
113
|
+
event.duration,
|
114
|
+
event.time
|
115
|
+
)
|
116
|
+
else
|
117
|
+
@config.logger.info(
|
118
|
+
"#{LOG_LABEL} Rack::Middleware#route_stats_hook: couldn't find " \
|
119
|
+
"a route for path: #{payload[:path]}"
|
120
|
+
)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def find_route(params)
|
126
|
+
@all_routes.each do |r|
|
127
|
+
if r.defaults[:controller] == params['controller'] &&
|
128
|
+
r.defaults[:action] == params['action']
|
129
|
+
return r.path.spec.to_s
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Finds all routes that the app supports, including engines.
|
135
|
+
def find_all_routes
|
136
|
+
routes = [*::Rails.application.routes.routes.routes]
|
137
|
+
::Rails::Engine.subclasses.each do |engine|
|
138
|
+
routes.push(*engine.routes.routes.routes)
|
139
|
+
end
|
140
|
+
routes
|
141
|
+
end
|
90
142
|
end
|
91
143
|
end
|
92
144
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Airbrake
|
2
|
+
module Rack
|
3
|
+
# Adds route slugs to context/route.
|
4
|
+
# @since v7.5.0
|
5
|
+
class RouteFilter
|
6
|
+
attr_reader :weight
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@weight = 100
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(notice)
|
13
|
+
return unless (request = notice.stash[:rack_request])
|
14
|
+
|
15
|
+
notice[:context][:route] =
|
16
|
+
if defined?(ActionDispatch::Request) &&
|
17
|
+
request.instance_of?(ActionDispatch::Request)
|
18
|
+
rails_route(request)
|
19
|
+
elsif defined?(Sinatra::Request) &&
|
20
|
+
request.instance_of?(Sinatra::Request)
|
21
|
+
sinatra_route(request)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def rails_route(request)
|
28
|
+
::Rails.application.routes.router.recognize(request) do |route, _parameters|
|
29
|
+
# Rails can recognize multiple routes for the given request. For
|
30
|
+
# example, if we visit /users/2/edit, then Rails sees these routes:
|
31
|
+
# * "/users/:id/edit(.:format)"
|
32
|
+
# * "/"
|
33
|
+
#
|
34
|
+
# We return the first route as, what it seems, the most optimal
|
35
|
+
# approach.
|
36
|
+
return route.path.spec.to_s
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def sinatra_route(request)
|
41
|
+
request.env['sinatra.route'].split(' ').drop(1).join(' ')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/airbrake/version.rb
CHANGED
@@ -8,6 +8,12 @@ RSpec.describe "Rails integration specs" do
|
|
8
8
|
|
9
9
|
include_examples 'rack examples'
|
10
10
|
|
11
|
+
# Airbrake Ruby has a background thread that sends requests to
|
12
|
+
# `/routes-stats` periodically. We don't want this to get in the way.
|
13
|
+
before do
|
14
|
+
allow(Airbrake[:default]).to receive(:inc_request).and_return(nil)
|
15
|
+
end
|
16
|
+
|
11
17
|
if ::Rails.version.start_with?('5.')
|
12
18
|
it "inserts the Airbrake Rack middleware after DebugExceptions" do
|
13
19
|
middlewares = Rails.configuration.middleware.middlewares.map(&:inspect)
|
@@ -68,6 +74,10 @@ RSpec.describe "Rails integration specs" do
|
|
68
74
|
/"context":{.*"params":{.*"controller":"dummy","action":"#{action}".*}/
|
69
75
|
)
|
70
76
|
end
|
77
|
+
|
78
|
+
it "includes route" do
|
79
|
+
wait_for_a_request_with_body(/"context":{.*"route":"#{route}\(\.:format\)".*}/)
|
80
|
+
end
|
71
81
|
end
|
72
82
|
|
73
83
|
describe "context payload" do
|
@@ -273,4 +283,27 @@ RSpec.describe "Rails integration specs" do
|
|
273
283
|
end
|
274
284
|
end
|
275
285
|
end
|
286
|
+
|
287
|
+
describe "the route stats hook" do
|
288
|
+
let(:routes_endpoint) do
|
289
|
+
'https://api.airbrake.io/api/v4/projects/113743/routes-stats'
|
290
|
+
end
|
291
|
+
|
292
|
+
before do
|
293
|
+
stub_request(:put, routes_endpoint).to_return(status: 200, body: '')
|
294
|
+
end
|
295
|
+
|
296
|
+
it "increments the request count" do
|
297
|
+
expect(Airbrake[:default]).to receive(:inc_request).and_call_original
|
298
|
+
|
299
|
+
get '/crash'
|
300
|
+
sleep 2
|
301
|
+
|
302
|
+
wait_for_a_request_with_body(/"errors"/)
|
303
|
+
|
304
|
+
body = %r|{"routes":\[{"method":"GET","route":"\/crash\(\.:format\)"|
|
305
|
+
wait_for(a_request(:put, routes_endpoint).with(body: body)).
|
306
|
+
to have_been_made.once
|
307
|
+
end
|
308
|
+
end
|
276
309
|
end
|
@@ -106,7 +106,7 @@ RSpec.describe "Rake integration" do
|
|
106
106
|
|
107
107
|
it "includes argv info" do
|
108
108
|
wait_for_a_request_with_body(
|
109
|
-
%r("params":{.*"argv":"
|
109
|
+
%r("params":{.*"argv":".*spec/integration/rails/.+_spec.rb".*})
|
110
110
|
)
|
111
111
|
end
|
112
112
|
|
@@ -17,6 +17,11 @@ RSpec.describe "Sinatra integration specs" do
|
|
17
17
|
get '/crash'
|
18
18
|
wait_for_a_request_with_body(/"context":{.*"versions":{"sinatra":"\d\./)
|
19
19
|
end
|
20
|
+
|
21
|
+
it "includes route" do
|
22
|
+
get '/crash'
|
23
|
+
wait_for_a_request_with_body(%r("context":{.*"route":"\/crash".*}))
|
24
|
+
end
|
20
25
|
end
|
21
26
|
|
22
27
|
context "when multiple apps are mounted" do
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Airbrake::Rack::RouteFilter do
|
4
|
+
context "when there's no request object available" do
|
5
|
+
it "doesn't add context/route" do
|
6
|
+
notice = Airbrake.build_notice('oops')
|
7
|
+
subject.call(notice)
|
8
|
+
expect(notice[:context][:route]).to be_nil
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: airbrake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.
|
4
|
+
version: 7.5.0.pre.1
|
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: 2018-10-
|
11
|
+
date: 2018-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: airbrake-ruby
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.13.0.pre.1
|
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:
|
26
|
+
version: 2.13.0.pre.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,6 +254,7 @@ files:
|
|
254
254
|
- lib/airbrake/rack/http_params_filter.rb
|
255
255
|
- lib/airbrake/rack/middleware.rb
|
256
256
|
- lib/airbrake/rack/request_body_filter.rb
|
257
|
+
- lib/airbrake/rack/route_filter.rb
|
257
258
|
- lib/airbrake/rack/session_filter.rb
|
258
259
|
- lib/airbrake/rack/user.rb
|
259
260
|
- lib/airbrake/rails.rb
|
@@ -288,6 +289,7 @@ files:
|
|
288
289
|
- spec/unit/rack/http_params_filter_spec.rb
|
289
290
|
- spec/unit/rack/middleware_spec.rb
|
290
291
|
- spec/unit/rack/request_body_filter_spec.rb
|
292
|
+
- spec/unit/rack/route_filter_spec.rb
|
291
293
|
- spec/unit/rack/session_filter_spec.rb
|
292
294
|
- spec/unit/rack/user_spec.rb
|
293
295
|
- spec/unit/rake/tasks_spec.rb
|
@@ -310,9 +312,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
310
312
|
version: '2.0'
|
311
313
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
312
314
|
requirements:
|
313
|
-
- - "
|
315
|
+
- - ">"
|
314
316
|
- !ruby/object:Gem::Version
|
315
|
-
version:
|
317
|
+
version: 1.3.1
|
316
318
|
requirements: []
|
317
319
|
rubyforge_project:
|
318
320
|
rubygems_version: 2.6.13
|
@@ -335,6 +337,7 @@ test_files:
|
|
335
337
|
- spec/unit/rack/session_filter_spec.rb
|
336
338
|
- spec/unit/rack/context_filter_spec.rb
|
337
339
|
- spec/unit/rack/user_spec.rb
|
340
|
+
- spec/unit/rack/route_filter_spec.rb
|
338
341
|
- spec/integration/sinatra/sinatra_spec.rb
|
339
342
|
- spec/integration/rack/rack_spec.rb
|
340
343
|
- spec/integration/shared_examples/rack_examples.rb
|