airbrake 3.1.6 → 11.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/airbrake.rb +23 -150
- data/lib/airbrake/capistrano.rb +6 -42
- data/lib/airbrake/capistrano/capistrano2.rb +40 -0
- data/lib/airbrake/capistrano/capistrano3.rb +23 -0
- data/lib/airbrake/delayed_job.rb +66 -0
- data/lib/airbrake/logger.rb +103 -0
- data/lib/airbrake/rack.rb +30 -45
- data/lib/airbrake/rack/context_filter.rb +65 -0
- data/lib/airbrake/rack/http_headers_filter.rb +44 -0
- data/lib/airbrake/rack/http_params_filter.rb +27 -0
- data/lib/airbrake/rack/instrumentable.rb +136 -0
- data/lib/airbrake/rack/middleware.rb +102 -0
- data/lib/airbrake/rack/request_body_filter.rb +33 -0
- data/lib/airbrake/rack/request_store.rb +34 -0
- data/lib/airbrake/rack/route_filter.rb +51 -0
- data/lib/airbrake/rack/session_filter.rb +25 -0
- data/lib/airbrake/rack/user.rb +74 -0
- data/lib/airbrake/rack/user_filter.rb +25 -0
- data/lib/airbrake/rails.rb +25 -31
- data/lib/airbrake/rails/action_cable.rb +35 -0
- data/lib/airbrake/rails/action_cable/notify_callback.rb +22 -0
- data/lib/airbrake/rails/action_controller.rb +40 -0
- data/lib/airbrake/rails/action_controller_notify_subscriber.rb +32 -0
- data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +51 -0
- data/lib/airbrake/rails/action_controller_route_subscriber.rb +33 -0
- data/lib/airbrake/rails/active_job.rb +50 -0
- data/lib/airbrake/rails/active_record.rb +36 -0
- data/lib/airbrake/rails/active_record_subscriber.rb +46 -0
- data/lib/airbrake/rails/app.rb +78 -0
- data/lib/airbrake/rails/backtrace_cleaner.rb +23 -0
- data/lib/airbrake/rails/curb.rb +32 -0
- data/lib/airbrake/rails/event.rb +81 -0
- data/lib/airbrake/rails/excon_subscriber.rb +25 -0
- data/lib/airbrake/rails/http.rb +14 -0
- data/lib/airbrake/rails/http_client.rb +16 -0
- data/lib/airbrake/rails/net_http.rb +18 -0
- data/lib/airbrake/rails/railtie.rb +151 -0
- data/lib/airbrake/rails/typhoeus.rb +16 -0
- data/lib/airbrake/rake.rb +65 -0
- data/lib/airbrake/rake/tasks.rb +112 -0
- data/lib/airbrake/resque.rb +61 -0
- data/lib/airbrake/shoryuken.rb +54 -0
- data/lib/airbrake/sidekiq.rb +55 -0
- data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +53 -0
- data/lib/airbrake/sneakers.rb +72 -0
- data/lib/airbrake/version.rb +5 -1
- data/lib/generators/airbrake_generator.rb +25 -0
- data/lib/generators/airbrake_initializer.rb.erb +80 -0
- metadata +206 -259
- data/CHANGELOG +0 -944
- data/Gemfile +0 -3
- data/Guardfile +0 -6
- data/INSTALL +0 -20
- data/MIT-LICENSE +0 -22
- data/README.md +0 -556
- data/README_FOR_HEROKU_ADDON.md +0 -94
- data/Rakefile +0 -223
- data/SUPPORTED_RAILS_VERSIONS +0 -38
- data/TESTING.md +0 -41
- data/airbrake.gemspec +0 -40
- data/bin/airbrake +0 -12
- data/features/metal.feature +0 -18
- data/features/rack.feature +0 -60
- data/features/rails.feature +0 -272
- data/features/rails_with_js_notifier.feature +0 -97
- data/features/rake.feature +0 -27
- data/features/sinatra.feature +0 -29
- data/features/step_definitions/file_steps.rb +0 -10
- data/features/step_definitions/metal_steps.rb +0 -23
- data/features/step_definitions/rack_steps.rb +0 -23
- data/features/step_definitions/rails_application_steps.rb +0 -478
- data/features/step_definitions/rake_steps.rb +0 -17
- data/features/support/airbrake_shim.rb.template +0 -16
- data/features/support/env.rb +0 -18
- data/features/support/matchers.rb +0 -35
- data/features/support/rails.rb +0 -201
- data/features/support/rake/Rakefile +0 -68
- data/features/support/terminal.rb +0 -107
- data/features/user_informer.feature +0 -63
- data/generators/airbrake/airbrake_generator.rb +0 -94
- data/generators/airbrake/lib/insert_commands.rb +0 -34
- data/generators/airbrake/lib/rake_commands.rb +0 -24
- data/generators/airbrake/templates/airbrake_tasks.rake +0 -25
- data/generators/airbrake/templates/capistrano_hook.rb +0 -6
- data/generators/airbrake/templates/initializer.rb +0 -6
- data/install.rb +0 -1
- data/lib/airbrake/backtrace.rb +0 -108
- data/lib/airbrake/cli/client.rb +0 -68
- data/lib/airbrake/cli/options.rb +0 -41
- data/lib/airbrake/cli/printer.rb +0 -30
- data/lib/airbrake/cli/project.rb +0 -17
- data/lib/airbrake/cli/project_factory.rb +0 -36
- data/lib/airbrake/cli/runner.rb +0 -48
- data/lib/airbrake/cli/validator.rb +0 -8
- data/lib/airbrake/configuration.rb +0 -311
- data/lib/airbrake/extensions/blank.rb +0 -73
- data/lib/airbrake/notice.rb +0 -390
- data/lib/airbrake/rails/action_controller_catcher.rb +0 -30
- data/lib/airbrake/rails/controller_methods.rb +0 -87
- data/lib/airbrake/rails/error_lookup.rb +0 -33
- data/lib/airbrake/rails/javascript_notifier.rb +0 -47
- data/lib/airbrake/rails/middleware/exceptions_catcher.rb +0 -33
- data/lib/airbrake/rails3_tasks.rb +0 -98
- data/lib/airbrake/railtie.rb +0 -48
- data/lib/airbrake/rake_handler.rb +0 -71
- data/lib/airbrake/sender.rb +0 -128
- data/lib/airbrake/shared_tasks.rb +0 -47
- data/lib/airbrake/tasks.rb +0 -83
- data/lib/airbrake/user_informer.rb +0 -27
- data/lib/airbrake_tasks.rb +0 -64
- data/lib/rails/generators/airbrake/airbrake_generator.rb +0 -100
- data/lib/templates/javascript_notifier.erb +0 -15
- data/lib/templates/rescue.erb +0 -91
- data/rails/init.rb +0 -1
- data/resources/README.md +0 -34
- data/resources/ca-bundle.crt +0 -3376
- data/script/integration_test.rb +0 -38
- data/test/airbrake_2_3.xsd +0 -88
- data/test/airbrake_tasks_test.rb +0 -170
- data/test/backtrace_test.rb +0 -162
- data/test/capistrano_test.rb +0 -34
- data/test/catcher_test.rb +0 -333
- data/test/configuration_test.rb +0 -233
- data/test/helper.rb +0 -263
- data/test/javascript_notifier_test.rb +0 -51
- data/test/logger_test.rb +0 -79
- data/test/notice_test.rb +0 -490
- data/test/notifier_test.rb +0 -276
- data/test/rack_test.rb +0 -58
- data/test/rails_initializer_test.rb +0 -36
- data/test/recursion_test.rb +0 -10
- data/test/sender_test.rb +0 -288
- data/test/user_informer_test.rb +0 -29
data/lib/airbrake/rack.rb
CHANGED
@@ -1,54 +1,39 @@
|
|
1
|
-
|
2
|
-
# Middleware for Rack applications. Any errors raised by the upstream
|
3
|
-
# application will be delivered to Airbrake and re-raised.
|
4
|
-
#
|
5
|
-
# Synopsis:
|
6
|
-
#
|
7
|
-
# require 'rack'
|
8
|
-
# require 'airbrake'
|
9
|
-
#
|
10
|
-
# Airbrake.configure do |config|
|
11
|
-
# config.api_key = 'my_api_key'
|
12
|
-
# end
|
13
|
-
#
|
14
|
-
# app = Rack::Builder.app do
|
15
|
-
# run lambda { |env| raise "Rack down" }
|
16
|
-
# end
|
17
|
-
#
|
18
|
-
# use Airbrake::Rack
|
19
|
-
# run app
|
20
|
-
#
|
21
|
-
# Use a standard Airbrake.configure call to configure your api key.
|
22
|
-
class Rack
|
23
|
-
def initialize(app)
|
24
|
-
@app = app
|
25
|
-
end
|
1
|
+
# frozen_string_literal: true
|
26
2
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
3
|
+
require 'airbrake/rack/user'
|
4
|
+
require 'airbrake/rack/user_filter'
|
5
|
+
require 'airbrake/rack/context_filter'
|
6
|
+
require 'airbrake/rack/session_filter'
|
7
|
+
require 'airbrake/rack/http_params_filter'
|
8
|
+
require 'airbrake/rack/http_headers_filter'
|
9
|
+
require 'airbrake/rack/request_body_filter'
|
10
|
+
require 'airbrake/rack/route_filter'
|
11
|
+
require 'airbrake/rack/middleware'
|
12
|
+
require 'airbrake/rack/request_store'
|
13
|
+
require 'airbrake/rack/instrumentable'
|
34
14
|
|
35
|
-
|
36
|
-
|
37
|
-
|
15
|
+
module Airbrake
|
16
|
+
# Rack is a namespace for all Rack-related code.
|
17
|
+
module Rack
|
18
|
+
# @since v9.2.0
|
19
|
+
# @api public
|
20
|
+
def self.capture_timing(label)
|
21
|
+
return yield unless Airbrake::Config.instance.performance_stats
|
38
22
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
23
|
+
routes = Airbrake::Rack::RequestStore[:routes]
|
24
|
+
if !routes || routes.none?
|
25
|
+
result = yield
|
26
|
+
else
|
27
|
+
timed_trace = Airbrake::TimedTrace.span(label) do
|
28
|
+
result = yield
|
29
|
+
end
|
46
30
|
|
47
|
-
|
48
|
-
|
31
|
+
routes.each do |_route_path, params|
|
32
|
+
params[:groups].merge!(timed_trace.spans)
|
33
|
+
end
|
49
34
|
end
|
50
35
|
|
51
|
-
|
36
|
+
result
|
52
37
|
end
|
53
38
|
end
|
54
39
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Airbrake
|
4
|
+
module Rack
|
5
|
+
# Adds context (URL, User-Agent, framework version, controller and more).
|
6
|
+
#
|
7
|
+
# @since v5.7.0
|
8
|
+
class ContextFilter
|
9
|
+
# @return [Integer]
|
10
|
+
attr_reader :weight
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@weight = 99
|
14
|
+
end
|
15
|
+
|
16
|
+
# @see Airbrake::FilterChain#refine
|
17
|
+
def call(notice)
|
18
|
+
return unless (request = notice.stash[:rack_request])
|
19
|
+
|
20
|
+
context = notice[:context]
|
21
|
+
|
22
|
+
context[:url] = request.url
|
23
|
+
context[:userAddr] =
|
24
|
+
if request.respond_to?(:remote_ip)
|
25
|
+
request.remote_ip
|
26
|
+
else
|
27
|
+
request.ip
|
28
|
+
end
|
29
|
+
context[:userAgent] = request.user_agent
|
30
|
+
|
31
|
+
add_framework_version(context)
|
32
|
+
|
33
|
+
controller = request.env['action_controller.instance']
|
34
|
+
return unless controller
|
35
|
+
|
36
|
+
context[:component] = controller.controller_name
|
37
|
+
context[:action] = controller.action_name
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def add_framework_version(context)
|
43
|
+
if context.key?(:versions)
|
44
|
+
context[:versions].merge!(framework_version)
|
45
|
+
else
|
46
|
+
context[:versions] = framework_version
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def framework_version
|
51
|
+
@framework_version ||=
|
52
|
+
if defined?(::Rails) && ::Rails.respond_to?(:version)
|
53
|
+
{ 'rails' => ::Rails.version }
|
54
|
+
elsif defined?(::Sinatra)
|
55
|
+
{ 'sinatra' => Sinatra::VERSION }
|
56
|
+
else
|
57
|
+
{
|
58
|
+
'rack_version' => ::Rack.version,
|
59
|
+
'rack_release' => ::Rack.release,
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Airbrake
|
4
|
+
module Rack
|
5
|
+
# Adds HTTP request parameters.
|
6
|
+
#
|
7
|
+
# @since v5.7.0
|
8
|
+
class HttpHeadersFilter
|
9
|
+
# @return [Array<String>] the prefixes of the majority of HTTP headers in
|
10
|
+
# Rack (some prefixes match the header names for simplicity)
|
11
|
+
HTTP_HEADER_PREFIXES = %w[
|
12
|
+
HTTP_
|
13
|
+
CONTENT_TYPE
|
14
|
+
CONTENT_LENGTH
|
15
|
+
].freeze
|
16
|
+
|
17
|
+
# @return [Integer]
|
18
|
+
attr_reader :weight
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@weight = 98
|
22
|
+
end
|
23
|
+
|
24
|
+
# @see Airbrake::FilterChain#refine
|
25
|
+
def call(notice)
|
26
|
+
return unless (request = notice.stash[:rack_request])
|
27
|
+
|
28
|
+
http_headers = request.env.map.with_object({}) do |(key, value), headers|
|
29
|
+
if HTTP_HEADER_PREFIXES.any? { |prefix| key.to_s.start_with?(prefix) }
|
30
|
+
headers[key] = value
|
31
|
+
end
|
32
|
+
|
33
|
+
headers
|
34
|
+
end
|
35
|
+
|
36
|
+
notice[:context].merge!(
|
37
|
+
httpMethod: request.request_method,
|
38
|
+
referer: request.referer,
|
39
|
+
headers: http_headers,
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Airbrake
|
4
|
+
module Rack
|
5
|
+
# Adds HTTP request parameters.
|
6
|
+
#
|
7
|
+
# @since v5.7.0
|
8
|
+
class HttpParamsFilter
|
9
|
+
# @return [Integer]
|
10
|
+
attr_reader :weight
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@weight = 97
|
14
|
+
end
|
15
|
+
|
16
|
+
# @see Airbrake::FilterChain#refine
|
17
|
+
def call(notice)
|
18
|
+
return unless (request = notice.stash[:rack_request])
|
19
|
+
|
20
|
+
notice[:params].merge!(request.params)
|
21
|
+
|
22
|
+
rails_params = request.env['action_dispatch.request.parameters']
|
23
|
+
notice[:params].merge!(rails_params) if rails_params
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Airbrake
|
4
|
+
module Rack
|
5
|
+
# Instrumentable holds methods that simplify instrumenting Rack apps.
|
6
|
+
# @example
|
7
|
+
# class UsersController
|
8
|
+
# extend Airbrake::Rack::Instrumentable
|
9
|
+
#
|
10
|
+
# def index
|
11
|
+
# # ...
|
12
|
+
# end
|
13
|
+
# airbrake_capture_timing :index
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
# @since v9.2.0
|
18
|
+
module Instrumentable
|
19
|
+
def airbrake_capture_timing(method_name, label: method_name.to_s)
|
20
|
+
instrumentable = ::Airbrake::Rack::Instrumentable
|
21
|
+
if instrumentable.should_prepend?(self, method_name)
|
22
|
+
instrumentable.prepend_capture_timing(self, method_name, label)
|
23
|
+
else
|
24
|
+
instrumentable.chain_capture_timing(self, method_name, label)
|
25
|
+
end
|
26
|
+
method_name
|
27
|
+
end
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
def __airbrake_capture_timing_module__
|
31
|
+
# Module used to store prepended wrapper methods, saved as an instance
|
32
|
+
# variable so each target class/module gets its own module. This just
|
33
|
+
# a convenience to avoid prepending a lot of anonymous modules.
|
34
|
+
@__airbrake_capture_timing_module__ ||= ::Module.new
|
35
|
+
end
|
36
|
+
private :__airbrake_capture_timing_module__
|
37
|
+
|
38
|
+
# Using api private self methods so they don't get defined in the target
|
39
|
+
# class or module, but can still be called by the above method.
|
40
|
+
|
41
|
+
# @api private
|
42
|
+
def self.should_prepend?(klass, method_name)
|
43
|
+
# Don't chain already-prepended or operator methods.
|
44
|
+
klass.module_exec do
|
45
|
+
self_class_idx = ancestors.index(self)
|
46
|
+
method_owner_idx = ancestors.index(instance_method(method_name).owner)
|
47
|
+
method_owner_idx < self_class_idx || !(/\A\W/ =~ method_name).nil?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @api private
|
52
|
+
def self.prepend_capture_timing(klass, method_name, label)
|
53
|
+
args = method_signature
|
54
|
+
visibility = method_visibility(klass, method_name)
|
55
|
+
|
56
|
+
# Generate the wrapper method.
|
57
|
+
klass.module_exec do
|
58
|
+
mod = __airbrake_capture_timing_module__
|
59
|
+
mod.module_exec do
|
60
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
61
|
+
def #{method_name}(#{args})
|
62
|
+
Airbrake::Rack.capture_timing(#{label.to_s.inspect}) do
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
#{visibility} :#{method_name}
|
67
|
+
RUBY
|
68
|
+
end
|
69
|
+
prepend mod
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @api private
|
74
|
+
def self.chain_capture_timing(klass, method_name, label)
|
75
|
+
args = method_signature
|
76
|
+
visibility = method_visibility(klass, method_name)
|
77
|
+
|
78
|
+
# Generate the wrapper method.
|
79
|
+
aliased = method_name.to_s.sub(/([?!=])$/, '')
|
80
|
+
punctuation = Regexp.last_match(1)
|
81
|
+
wrapped_method_name = "#{aliased}_without_airbrake#{punctuation}"
|
82
|
+
needs_removal = method_needs_removal(klass, method_name)
|
83
|
+
klass.module_exec do
|
84
|
+
alias_method wrapped_method_name, method_name
|
85
|
+
remove_method method_name if needs_removal
|
86
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
87
|
+
def #{method_name}(#{args})
|
88
|
+
Airbrake::Rack.capture_timing(#{label.to_s.inspect}) do
|
89
|
+
__send__("#{aliased}_without_airbrake#{punctuation}", #{args})
|
90
|
+
end
|
91
|
+
end
|
92
|
+
#{visibility} :#{method_name}
|
93
|
+
RUBY
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# @api private
|
98
|
+
def self.method_visibility(klass, method_name)
|
99
|
+
klass.module_exec do
|
100
|
+
if protected_method_defined?(method_name)
|
101
|
+
"protected"
|
102
|
+
elsif private_method_defined?(method_name)
|
103
|
+
"private"
|
104
|
+
else
|
105
|
+
"public"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# @api private
|
111
|
+
# A method instead of a constant so it isn't accessible in the target.
|
112
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7")
|
113
|
+
def self.method_signature
|
114
|
+
"*args, **kw_args, &block"
|
115
|
+
end
|
116
|
+
else
|
117
|
+
def self.method_signature
|
118
|
+
"*args, &block"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# @api private
|
123
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.6")
|
124
|
+
def self.method_needs_removal(klass, method_name)
|
125
|
+
klass.method_defined?(method_name, false) ||
|
126
|
+
klass.private_method_defined?(method_name, false)
|
127
|
+
end
|
128
|
+
else
|
129
|
+
def self.method_needs_removal(klass, method_name)
|
130
|
+
klass.instance_methods(false).include?(method_name) ||
|
131
|
+
klass.private_instance_methods(false).include?(method_name)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Airbrake
|
4
|
+
module Rack
|
5
|
+
# Airbrake Rack middleware for Rails and Sinatra applications (or any other
|
6
|
+
# Rack-compliant app). Any errors raised by the upstream application will be
|
7
|
+
# delivered to Airbrake and re-raised.
|
8
|
+
#
|
9
|
+
# The middleware automatically sends information about the framework that
|
10
|
+
# uses it (name and version).
|
11
|
+
#
|
12
|
+
# For Rails apps the middleware collects route performance statistics.
|
13
|
+
class Middleware
|
14
|
+
def initialize(app)
|
15
|
+
@app = app
|
16
|
+
end
|
17
|
+
|
18
|
+
# Thread-safe {call!}.
|
19
|
+
#
|
20
|
+
# @param [Hash] env the Rack environment
|
21
|
+
# @see https://github.com/airbrake/airbrake/issues/904
|
22
|
+
def call(env)
|
23
|
+
dup.call!(env)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Rescues any exceptions, sends them to Airbrake and re-raises the
|
27
|
+
# exception. We also duplicate middleware to guarantee thread-safety.
|
28
|
+
#
|
29
|
+
# @param [Hash] env the Rack environment
|
30
|
+
def call!(env)
|
31
|
+
before_call(env)
|
32
|
+
|
33
|
+
begin
|
34
|
+
response = @app.call(env)
|
35
|
+
rescue Exception => ex # rubocop:disable Lint/RescueException
|
36
|
+
notify_airbrake(ex)
|
37
|
+
raise ex
|
38
|
+
end
|
39
|
+
|
40
|
+
exception = framework_exception(env)
|
41
|
+
notify_airbrake(exception) if exception
|
42
|
+
|
43
|
+
response
|
44
|
+
ensure
|
45
|
+
# Clear routes for the next request.
|
46
|
+
RequestStore.clear
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def before_call(env)
|
52
|
+
# Rails hooks such as ActionControllerRouteSubscriber rely on this.
|
53
|
+
RequestStore[:routes] = {}
|
54
|
+
RequestStore[:request] = find_request(env)
|
55
|
+
end
|
56
|
+
|
57
|
+
def find_request(env)
|
58
|
+
if defined?(ActionDispatch::Request)
|
59
|
+
ActionDispatch::Request.new(env)
|
60
|
+
elsif defined?(Sinatra::Request)
|
61
|
+
Sinatra::Request.new(env)
|
62
|
+
else
|
63
|
+
::Rack::Request.new(env)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def notify_airbrake(exception)
|
68
|
+
notice = Airbrake.build_notice(exception)
|
69
|
+
return unless notice
|
70
|
+
|
71
|
+
# ActionDispatch::Request correctly captures server port when using SSL:
|
72
|
+
# See: https://github.com/airbrake/airbrake/issues/802
|
73
|
+
notice.stash[:rack_request] = RequestStore[:request]
|
74
|
+
|
75
|
+
Airbrake.notify(notice)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Web framework middlewares often store rescued exceptions inside the
|
79
|
+
# Rack env, but Rack doesn't have a standard key for it:
|
80
|
+
#
|
81
|
+
# - Rails uses action_dispatch.exception: https://goo.gl/Kd694n
|
82
|
+
# - Sinatra uses sinatra.error: https://goo.gl/LLkVL9
|
83
|
+
# - Goliath uses rack.exception: https://goo.gl/i7e1nA
|
84
|
+
def framework_exception(env)
|
85
|
+
env['action_dispatch.exception'] ||
|
86
|
+
env['sinatra.error'] ||
|
87
|
+
env['rack.exception']
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
[
|
94
|
+
Airbrake::Rack::ContextFilter,
|
95
|
+
Airbrake::Rack::UserFilter,
|
96
|
+
Airbrake::Rack::SessionFilter,
|
97
|
+
Airbrake::Rack::HttpParamsFilter,
|
98
|
+
Airbrake::Rack::HttpHeadersFilter,
|
99
|
+
Airbrake::Rack::RouteFilter,
|
100
|
+
].each do |filter|
|
101
|
+
Airbrake.add_filter(filter.new)
|
102
|
+
end
|