airbrake 9.5.2 → 10.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/airbrake.rb +2 -0
- data/lib/airbrake/capistrano.rb +2 -0
- data/lib/airbrake/capistrano/capistrano2.rb +2 -0
- data/lib/airbrake/capistrano/capistrano3.rb +2 -0
- data/lib/airbrake/delayed_job.rb +24 -6
- data/lib/airbrake/logger.rb +2 -0
- data/lib/airbrake/rack.rb +2 -0
- data/lib/airbrake/rack/context_filter.rb +9 -2
- data/lib/airbrake/rack/http_headers_filter.rb +4 -2
- data/lib/airbrake/rack/http_params_filter.rb +2 -0
- data/lib/airbrake/rack/instrumentable.rb +112 -4
- data/lib/airbrake/rack/middleware.rb +3 -1
- data/lib/airbrake/rack/request_body_filter.rb +2 -0
- data/lib/airbrake/rack/request_store.rb +2 -0
- data/lib/airbrake/rack/route_filter.rb +5 -1
- data/lib/airbrake/rack/session_filter.rb +2 -0
- data/lib/airbrake/rack/user.rb +2 -0
- data/lib/airbrake/rack/user_filter.rb +2 -0
- data/lib/airbrake/rails.rb +3 -1
- data/lib/airbrake/rails/action_cable.rb +2 -0
- data/lib/airbrake/rails/action_cable/notify_callback.rb +2 -0
- data/lib/airbrake/rails/action_controller.rb +2 -0
- data/lib/airbrake/rails/action_controller_notify_subscriber.rb +4 -2
- data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +4 -1
- data/lib/airbrake/rails/action_controller_route_subscriber.rb +5 -11
- data/lib/airbrake/rails/active_job.rb +25 -0
- data/lib/airbrake/rails/active_record.rb +2 -0
- data/lib/airbrake/rails/active_record_subscriber.rb +5 -3
- data/lib/airbrake/rails/app.rb +43 -9
- data/lib/airbrake/rails/backtrace_cleaner.rb +2 -0
- data/lib/airbrake/rails/curb.rb +2 -0
- data/lib/airbrake/rails/event.rb +3 -5
- data/lib/airbrake/rails/excon_subscriber.rb +2 -0
- data/lib/airbrake/rails/http.rb +2 -0
- data/lib/airbrake/rails/http_client.rb +2 -0
- data/lib/airbrake/rails/net_http.rb +2 -0
- data/lib/airbrake/rails/railtie.rb +11 -9
- data/lib/airbrake/rails/typhoeus.rb +2 -0
- data/lib/airbrake/rake.rb +3 -1
- data/lib/airbrake/rake/tasks.rb +6 -4
- data/lib/airbrake/resque.rb +32 -0
- data/lib/airbrake/shoryuken.rb +17 -3
- data/lib/airbrake/sidekiq.rb +20 -13
- data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +2 -0
- data/lib/airbrake/sneakers.rb +38 -1
- data/lib/airbrake/version.rb +3 -1
- data/lib/generators/airbrake_generator.rb +2 -0
- data/lib/generators/airbrake_initializer.rb.erb +2 -0
- metadata +19 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6ebb0d64b92742b80afe65583bf19f6c3fc7352d146e95765b8c5b7d2d1949b
|
4
|
+
data.tar.gz: 2e02317eeb64c7f4ece9173b88af2033c13d630dc9072232d39a697495da3f19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b69a9609edd060362d33626f715696ce41a49f05a796ad314f7cb7258d3e7b03274ebeb7ef8c4c17fc004f64cdd56f3af51ba5c59f62acaeb2416ee7517d3af2
|
7
|
+
data.tar.gz: 99b1645d2b95c0d73d2bad8a2bc04960334e14e8d0d13f613d30f7666f250b05d5e0567944113302e8c6a6dc40a17fc8e897d6fc578af41af96426f07b79efc3
|
data/lib/airbrake.rb
CHANGED
data/lib/airbrake/capistrano.rb
CHANGED
data/lib/airbrake/delayed_job.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Delayed
|
2
4
|
module Plugins
|
3
5
|
# Provides integration with Delayed Job.
|
4
|
-
# rubocop:disable
|
6
|
+
# rubocop:disable Metrics/BlockLength
|
5
7
|
class Airbrake < ::Delayed::Plugin
|
6
8
|
callbacks do |lifecycle|
|
7
9
|
lifecycle.around(:invoke_job) do |job, *args, &block|
|
8
10
|
begin
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
timing = ::Airbrake::Benchmark.measure do
|
12
|
+
# Forward the call to the next callback in the callback chain
|
13
|
+
block.call(job, *args)
|
14
|
+
end
|
15
|
+
rescue Exception => exception # rubocop:disable Lint/RescueException
|
12
16
|
params = job.as_json
|
13
17
|
|
14
18
|
# If DelayedJob is used through ActiveJob, it contains extra info.
|
@@ -17,17 +21,31 @@ module Delayed
|
|
17
21
|
job_class = job.payload_object.job_data['job_class']
|
18
22
|
end
|
19
23
|
|
24
|
+
action = job_class || job.payload_object.class.name
|
25
|
+
|
20
26
|
::Airbrake.notify(exception, params) do |notice|
|
21
27
|
notice[:context][:component] = 'delayed_job'
|
22
|
-
notice[:context][:action] =
|
28
|
+
notice[:context][:action] = action
|
23
29
|
end
|
24
30
|
|
31
|
+
::Airbrake.notify_queue_sync(
|
32
|
+
queue: action,
|
33
|
+
error_count: 1,
|
34
|
+
timing: 0.01,
|
35
|
+
)
|
36
|
+
|
25
37
|
raise exception
|
38
|
+
else
|
39
|
+
::Airbrake.notify_queue_sync(
|
40
|
+
queue: job_class || job.payload_object.class.name,
|
41
|
+
error_count: 0,
|
42
|
+
timing: timing,
|
43
|
+
)
|
26
44
|
end
|
27
45
|
end
|
28
46
|
end
|
29
47
|
end
|
30
|
-
# rubocop:enable
|
48
|
+
# rubocop:enable Metrics/BlockLength
|
31
49
|
end
|
32
50
|
end
|
33
51
|
|
data/lib/airbrake/logger.rb
CHANGED
data/lib/airbrake/rack.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Rack
|
3
5
|
# Adds context (URL, User-Agent, framework version, controller and more).
|
@@ -18,7 +20,12 @@ module Airbrake
|
|
18
20
|
context = notice[:context]
|
19
21
|
|
20
22
|
context[:url] = request.url
|
21
|
-
context[:userAddr] =
|
23
|
+
context[:userAddr] =
|
24
|
+
if request.respond_to?(:remote_ip)
|
25
|
+
request.remote_ip
|
26
|
+
else
|
27
|
+
request.ip
|
28
|
+
end
|
22
29
|
context[:userAgent] = request.user_agent
|
23
30
|
|
24
31
|
add_framework_version(context)
|
@@ -49,7 +56,7 @@ module Airbrake
|
|
49
56
|
else
|
50
57
|
{
|
51
58
|
'rack_version' => ::Rack.version,
|
52
|
-
'rack_release' => ::Rack.release
|
59
|
+
'rack_release' => ::Rack.release,
|
53
60
|
}
|
54
61
|
end
|
55
62
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Rack
|
3
5
|
# Adds HTTP request parameters.
|
@@ -9,7 +11,7 @@ module Airbrake
|
|
9
11
|
HTTP_HEADER_PREFIXES = [
|
10
12
|
'HTTP_'.freeze,
|
11
13
|
'CONTENT_TYPE'.freeze,
|
12
|
-
'CONTENT_LENGTH'.freeze
|
14
|
+
'CONTENT_LENGTH'.freeze,
|
13
15
|
].freeze
|
14
16
|
|
15
17
|
# @return [Integer]
|
@@ -34,7 +36,7 @@ module Airbrake
|
|
34
36
|
notice[:context].merge!(
|
35
37
|
httpMethod: request.request_method,
|
36
38
|
referer: request.referer,
|
37
|
-
headers: http_headers
|
39
|
+
headers: http_headers,
|
38
40
|
)
|
39
41
|
end
|
40
42
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Rack
|
3
5
|
# Instrumentable holds methods that simplify instrumenting Rack apps.
|
@@ -15,14 +17,120 @@ module Airbrake
|
|
15
17
|
# @since v9.2.0
|
16
18
|
module Instrumentable
|
17
19
|
def airbrake_capture_timing(method_name, label: method_name.to_s)
|
18
|
-
|
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)
|
19
77
|
|
20
|
-
|
21
|
-
|
22
|
-
|
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".freeze
|
102
|
+
elsif private_method_defined?(method_name)
|
103
|
+
"private".freeze
|
104
|
+
else
|
105
|
+
"public".freeze
|
23
106
|
end
|
24
107
|
end
|
25
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".freeze
|
115
|
+
end
|
116
|
+
else
|
117
|
+
def self.method_signature
|
118
|
+
"*args, &block".freeze
|
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
|
26
134
|
end
|
27
135
|
end
|
28
136
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Rack
|
3
5
|
# Airbrake Rack middleware for Rails and Sinatra applications (or any other
|
@@ -94,7 +96,7 @@ end
|
|
94
96
|
Airbrake::Rack::SessionFilter,
|
95
97
|
Airbrake::Rack::HttpParamsFilter,
|
96
98
|
Airbrake::Rack::HttpHeadersFilter,
|
97
|
-
Airbrake::Rack::RouteFilter
|
99
|
+
Airbrake::Rack::RouteFilter,
|
98
100
|
].each do |filter|
|
99
101
|
Airbrake.add_filter(filter.new)
|
100
102
|
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'airbrake/rails/app'
|
4
|
+
|
1
5
|
module Airbrake
|
2
6
|
module Rack
|
3
7
|
# Adds route slugs to context/route.
|
@@ -24,7 +28,7 @@ module Airbrake
|
|
24
28
|
|
25
29
|
def rails_route(request)
|
26
30
|
return unless (route = Airbrake::Rails::App.recognize_route(request))
|
27
|
-
route.path
|
31
|
+
route.path
|
28
32
|
end
|
29
33
|
|
30
34
|
def sinatra_route(request)
|
data/lib/airbrake/rack/user.rb
CHANGED
data/lib/airbrake/rails.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'airbrake/rails/railtie'
|
2
4
|
|
3
5
|
module Airbrake
|
@@ -12,7 +14,7 @@ module Airbrake
|
|
12
14
|
|
13
15
|
# Rails.logger is not set in some Rake tasks such as
|
14
16
|
# 'airbrake:deploy'. In this case we use a sensible fallback.
|
15
|
-
level: (::Rails.logger ? ::Rails.logger.level : Logger::ERROR)
|
17
|
+
level: (::Rails.logger ? ::Rails.logger.level : Logger::ERROR),
|
16
18
|
)
|
17
19
|
end
|
18
20
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'airbrake/rails/event'
|
2
4
|
|
3
5
|
module Airbrake
|
@@ -18,8 +20,8 @@ module Airbrake
|
|
18
20
|
method: event.method,
|
19
21
|
route: route,
|
20
22
|
status_code: event.status_code,
|
21
|
-
|
22
|
-
|
23
|
+
timing: event.duration,
|
24
|
+
time: event.time,
|
23
25
|
)
|
24
26
|
end
|
25
27
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'airbrake/rails/event'
|
2
4
|
|
3
5
|
module Airbrake
|
@@ -20,7 +22,8 @@ module Airbrake
|
|
20
22
|
route: route,
|
21
23
|
response_type: event.response_type,
|
22
24
|
groups: groups,
|
23
|
-
|
25
|
+
timing: event.duration,
|
26
|
+
time: event.time,
|
24
27
|
}
|
25
28
|
|
26
29
|
Airbrake.notify_performance_breakdown(breakdown_info, stash)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'airbrake/rails/event'
|
2
4
|
require 'airbrake/rails/app'
|
3
5
|
|
@@ -14,24 +16,16 @@ module Airbrake
|
|
14
16
|
|
15
17
|
event = Airbrake::Rails::Event.new(*args)
|
16
18
|
route = Airbrake::Rails::App.recognize_route(
|
17
|
-
Airbrake::Rack::RequestStore[:request]
|
19
|
+
Airbrake::Rack::RequestStore[:request],
|
18
20
|
)
|
19
21
|
return unless route
|
20
22
|
|
21
|
-
routes[
|
23
|
+
routes[route.path] = {
|
22
24
|
method: event.method,
|
23
25
|
response_type: event.response_type,
|
24
|
-
groups: {}
|
26
|
+
groups: {},
|
25
27
|
}
|
26
28
|
end
|
27
|
-
|
28
|
-
def find_route_name(route)
|
29
|
-
if route.app.respond_to?(:app) && route.app.app.respond_to?(:engine_name)
|
30
|
-
"#{route.app.app.engine_name}##{route.path.spec}"
|
31
|
-
else
|
32
|
-
route.path.spec.to_s
|
33
|
-
end
|
34
|
-
end
|
35
29
|
end
|
36
30
|
end
|
37
31
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Rails
|
3
5
|
# Enables support for exceptions occurring in ActiveJob jobs.
|
@@ -23,10 +25,33 @@ module Airbrake
|
|
23
25
|
raise exception
|
24
26
|
end
|
25
27
|
|
28
|
+
def self.perform(job, block)
|
29
|
+
timing = Airbrake::Benchmark.measure do
|
30
|
+
block.call
|
31
|
+
end
|
32
|
+
rescue StandardError => exception
|
33
|
+
Airbrake.notify_queue_sync(
|
34
|
+
queue: job.class.name,
|
35
|
+
error_count: 1,
|
36
|
+
timing: 0.01,
|
37
|
+
)
|
38
|
+
raise exception
|
39
|
+
else
|
40
|
+
Airbrake.notify_queue_sync(
|
41
|
+
queue: job.class.name,
|
42
|
+
error_count: 0,
|
43
|
+
timing: timing,
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
26
47
|
included do
|
27
48
|
rescue_from(Exception) do |exception|
|
28
49
|
Airbrake::Rails::ActiveJob.notify_airbrake(exception, self)
|
29
50
|
end
|
51
|
+
|
52
|
+
around_perform do |job, block|
|
53
|
+
Airbrake::Rails::ActiveJob.perform(job, block)
|
54
|
+
end
|
30
55
|
end
|
31
56
|
end
|
32
57
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'airbrake/rails/event'
|
2
4
|
require 'airbrake/rails/backtrace_cleaner'
|
3
5
|
|
@@ -22,8 +24,8 @@ module Airbrake
|
|
22
24
|
func: frame[:function],
|
23
25
|
file: frame[:file],
|
24
26
|
line: frame[:line],
|
25
|
-
|
26
|
-
|
27
|
+
timing: event.duration,
|
28
|
+
time: event.time,
|
27
29
|
)
|
28
30
|
end
|
29
31
|
end
|
@@ -33,7 +35,7 @@ module Airbrake
|
|
33
35
|
def last_caller
|
34
36
|
exception = StandardError.new
|
35
37
|
exception.set_backtrace(
|
36
|
-
Airbrake::Rails::BacktraceCleaner.clean(Kernel.caller)
|
38
|
+
Airbrake::Rails::BacktraceCleaner.clean(Kernel.caller),
|
37
39
|
)
|
38
40
|
Airbrake::Backtrace.parse(exception).first || {}
|
39
41
|
end
|
data/lib/airbrake/rails/app.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Rails
|
3
5
|
# App is a wrapper around Rails.application.
|
@@ -5,18 +7,50 @@ module Airbrake
|
|
5
7
|
# @since v9.0.3
|
6
8
|
# @api private
|
7
9
|
class App
|
10
|
+
Route = Struct.new(:path)
|
11
|
+
|
12
|
+
# @param [] request
|
13
|
+
# @return [Airbrake::Rails::App::Route, nil]
|
8
14
|
def self.recognize_route(request)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
# Duplicate `request` because `recognize` *can* strip the request's
|
16
|
+
# `path_info`, which results in broken engine links (when the engine has
|
17
|
+
# an isolated namespace).
|
18
|
+
request_copy = request.dup
|
19
|
+
|
20
|
+
# We must search every engine individually to find a concrete route. If
|
21
|
+
# we rely only on the `Rails.application.routes.router`, then the
|
22
|
+
# recognize call would return the root route, neglecting PATH_INFO
|
23
|
+
# completely. For example:
|
24
|
+
# * a request is made to `marketing#pricing`
|
25
|
+
# * `Rails.application` recognizes it as `marketing#/` (incorrect)
|
26
|
+
# * `Marketing::Engine` recognizes it as `marketing#/pricing` (correct)
|
27
|
+
engines.each do |engine|
|
28
|
+
engine.routes.router.recognize(request_copy) do |route, _params|
|
29
|
+
path =
|
30
|
+
if engine == ::Rails.application
|
31
|
+
route.path.spec.to_s
|
32
|
+
else
|
33
|
+
"#{engine.engine_name}##{route.path.spec}"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Rails can recognize multiple routes for the given request. For
|
37
|
+
# example, if we visit /users/2/edit, then Rails sees these routes:
|
38
|
+
# * "/users/:id/edit(.:format)"
|
39
|
+
# * "/"
|
40
|
+
#
|
41
|
+
# We return the first route as, what it seems, the most optimal
|
42
|
+
# approach.
|
43
|
+
return Route.new(path)
|
44
|
+
end
|
18
45
|
end
|
46
|
+
|
47
|
+
nil
|
19
48
|
end
|
49
|
+
|
50
|
+
def self.engines
|
51
|
+
@engines ||= [*::Rails::Engine.subclasses, ::Rails.application]
|
52
|
+
end
|
53
|
+
private_class_method :engines
|
20
54
|
end
|
21
55
|
end
|
22
56
|
end
|
data/lib/airbrake/rails/curb.rb
CHANGED
data/lib/airbrake/rails/event.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Rails
|
3
5
|
# Event is a wrapper around ActiveSupport::Notifications::Event.
|
@@ -43,10 +45,6 @@ module Airbrake
|
|
43
45
|
@event.time
|
44
46
|
end
|
45
47
|
|
46
|
-
def end
|
47
|
-
@event.end
|
48
|
-
end
|
49
|
-
|
50
48
|
def groups
|
51
49
|
groups = {}
|
52
50
|
groups[:db] = db_runtime if db_runtime > 0
|
@@ -59,7 +57,7 @@ module Airbrake
|
|
59
57
|
|
60
58
|
if @event.payload[:exception]
|
61
59
|
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(
|
62
|
-
@event.payload[:exception].first
|
60
|
+
@event.payload[:exception].first,
|
63
61
|
)
|
64
62
|
status = 500 if status == 0
|
65
63
|
|
data/lib/airbrake/rails/http.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Rails
|
3
5
|
# This railtie works for any Rails application that supports railties (Rails
|
4
6
|
# 3.2+ apps). It makes Airbrake Ruby work with Rails and report errors
|
5
7
|
# occurring in the application automatically.
|
6
8
|
class Railtie < ::Rails::Railtie
|
7
|
-
initializer('airbrake.middleware') do |app|
|
9
|
+
initializer('airbrake.middleware', after: :load_config_initializers) do |app|
|
8
10
|
# Since Rails 3.2 the ActionDispatch::DebugExceptions middleware is
|
9
11
|
# responsible for logging exceptions and showing a debugging page in
|
10
12
|
# case the request is local. We want to insert our middleware after
|
@@ -16,20 +18,20 @@ module Airbrake
|
|
16
18
|
# exist in Rails 5 anymore.
|
17
19
|
app.config.middleware.insert_after(
|
18
20
|
ActionDispatch::DebugExceptions,
|
19
|
-
Airbrake::Rack::Middleware
|
21
|
+
Airbrake::Rack::Middleware,
|
20
22
|
)
|
21
23
|
elsif defined?(::ActiveRecord::ConnectionAdapters::ConnectionManagement)
|
22
24
|
# Insert after ConnectionManagement to avoid DB connection leakage:
|
23
25
|
# https://github.com/airbrake/airbrake/pull/568
|
24
26
|
app.config.middleware.insert_after(
|
25
27
|
::ActiveRecord::ConnectionAdapters::ConnectionManagement,
|
26
|
-
'Airbrake::Rack::Middleware'
|
28
|
+
'Airbrake::Rack::Middleware',
|
27
29
|
)
|
28
30
|
else
|
29
31
|
# Insert after DebugExceptions for apps without ActiveRecord.
|
30
32
|
app.config.middleware.insert_after(
|
31
33
|
ActionDispatch::DebugExceptions,
|
32
|
-
'Airbrake::Rack::Middleware'
|
34
|
+
'Airbrake::Rack::Middleware',
|
33
35
|
)
|
34
36
|
end
|
35
37
|
end
|
@@ -55,21 +57,21 @@ module Airbrake
|
|
55
57
|
require 'airbrake/rails/action_controller_route_subscriber'
|
56
58
|
ActiveSupport::Notifications.subscribe(
|
57
59
|
'start_processing.action_controller',
|
58
|
-
Airbrake::Rails::ActionControllerRouteSubscriber.new
|
60
|
+
Airbrake::Rails::ActionControllerRouteSubscriber.new,
|
59
61
|
)
|
60
62
|
|
61
63
|
# Send route stats.
|
62
64
|
require 'airbrake/rails/action_controller_notify_subscriber'
|
63
65
|
ActiveSupport::Notifications.subscribe(
|
64
66
|
'process_action.action_controller',
|
65
|
-
Airbrake::Rails::ActionControllerNotifySubscriber.new
|
67
|
+
Airbrake::Rails::ActionControllerNotifySubscriber.new,
|
66
68
|
)
|
67
69
|
|
68
70
|
# Send performance breakdown: where a request spends its time.
|
69
71
|
require 'airbrake/rails/action_controller_performance_breakdown_subscriber'
|
70
72
|
ActiveSupport::Notifications.subscribe(
|
71
73
|
'process_action.action_controller',
|
72
|
-
Airbrake::Rails::ActionControllerPerformanceBreakdownSubscriber.new
|
74
|
+
Airbrake::Rails::ActionControllerPerformanceBreakdownSubscriber.new,
|
73
75
|
)
|
74
76
|
|
75
77
|
require 'airbrake/rails/net_http' if defined?(Net) && defined?(Net::HTTP)
|
@@ -112,8 +114,8 @@ module Airbrake
|
|
112
114
|
# Filter out parameters from SQL body.
|
113
115
|
Airbrake.add_performance_filter(
|
114
116
|
Airbrake::Filters::SqlFilter.new(
|
115
|
-
::ActiveRecord::Base.connection_config[:adapter]
|
116
|
-
)
|
117
|
+
::ActiveRecord::Base.connection_config[:adapter],
|
118
|
+
),
|
117
119
|
)
|
118
120
|
end
|
119
121
|
end
|
data/lib/airbrake/rake.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This is not bulletproof, but if this file is executed before a task
|
2
4
|
# definition, we can grab tasks descriptions and locations.
|
3
5
|
# See: https://goo.gl/ksn6PE
|
@@ -30,7 +32,7 @@ module Rake
|
|
30
32
|
notice[:params].merge!(
|
31
33
|
rake_task: task_info,
|
32
34
|
execute_args: args,
|
33
|
-
argv: ARGV.join(' ')
|
35
|
+
argv: ARGV.join(' '),
|
34
36
|
)
|
35
37
|
|
36
38
|
Airbrake.notify_sync(notice)
|
data/lib/airbrake/rake/tasks.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'airbrake-ruby'
|
2
4
|
|
3
5
|
namespace :airbrake do
|
@@ -55,7 +57,7 @@ namespace :airbrake do
|
|
55
57
|
username: ENV['USERNAME'],
|
56
58
|
revision: ENV['REVISION'],
|
57
59
|
repository: ENV['REPOSITORY'],
|
58
|
-
version: ENV['VERSION']
|
60
|
+
version: ENV['VERSION'],
|
59
61
|
}
|
60
62
|
promise = Airbrake.notify_deploy(deploy_params)
|
61
63
|
promise.then do
|
@@ -97,14 +99,14 @@ namespace :airbrake do
|
|
97
99
|
end
|
98
100
|
end
|
99
101
|
|
100
|
-
url = "https://airbrake.io/api/v3/projects/#{id}/heroku-deploys?key=#{key}"
|
102
|
+
url = ["https://airbrake.io/api/v3/projects/#{id}/heroku-deploys?key=#{key}"]
|
101
103
|
url << "&environment=#{env}"
|
102
104
|
url << "&repository=#{repo}" unless repo.empty?
|
103
105
|
|
104
|
-
command = %(heroku addons:create deployhooks:http --url="#{url}")
|
106
|
+
command = [%(heroku addons:create deployhooks:http --url="#{url.join}")]
|
105
107
|
command << " --app #{app}" if app
|
106
108
|
|
107
|
-
puts "$ #{command}"
|
109
|
+
puts "$ #{command.join}"
|
108
110
|
Bundler.with_clean_env { puts `#{command}` }
|
109
111
|
end
|
110
112
|
end
|
data/lib/airbrake/resque.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Resque
|
2
4
|
module Failure
|
3
5
|
# Provides Resque integration with Airbrake.
|
@@ -27,3 +29,33 @@ module Resque
|
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
32
|
+
|
33
|
+
module Resque
|
34
|
+
# Measures elapsed time of a job and notifies Airbrake of the execution
|
35
|
+
# status.
|
36
|
+
#
|
37
|
+
# @since v9.6.0
|
38
|
+
class Job
|
39
|
+
# Store the original method to use it later.
|
40
|
+
alias perform_without_airbrake perform
|
41
|
+
|
42
|
+
def perform
|
43
|
+
timing = Airbrake::Benchmark.measure do
|
44
|
+
perform_without_airbrake
|
45
|
+
end
|
46
|
+
rescue StandardError => exception
|
47
|
+
Airbrake.notify_queue_sync(
|
48
|
+
queue: payload['class'],
|
49
|
+
error_count: 1,
|
50
|
+
timing: 0.01,
|
51
|
+
)
|
52
|
+
raise exception
|
53
|
+
else
|
54
|
+
Airbrake.notify_queue_sync(
|
55
|
+
queue: payload['class'],
|
56
|
+
error_count: 0,
|
57
|
+
timing: timing,
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/airbrake/shoryuken.rb
CHANGED
@@ -1,14 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Shoryuken
|
3
5
|
# Provides integration with Shoryuken.
|
4
6
|
class ErrorHandler
|
5
7
|
# rubocop:disable Lint/RescueException
|
6
8
|
def call(worker, queue, _sqs_msg, body)
|
7
|
-
|
9
|
+
timing = Airbrake::Benchmark.measure do
|
10
|
+
yield
|
11
|
+
end
|
8
12
|
rescue Exception => exception
|
9
13
|
notify_airbrake(exception, worker, queue, body)
|
10
|
-
|
14
|
+
Airbrake.notify_queue(
|
15
|
+
queue: worker.class.to_s,
|
16
|
+
error_count: 1,
|
17
|
+
timing: 0.01,
|
18
|
+
)
|
11
19
|
raise exception
|
20
|
+
else
|
21
|
+
Airbrake.notify_queue(
|
22
|
+
queue: worker.class.to_s,
|
23
|
+
error_count: 0,
|
24
|
+
timing: timing,
|
25
|
+
)
|
12
26
|
end
|
13
27
|
# rubocop:enable Lint/RescueException
|
14
28
|
|
@@ -24,7 +38,7 @@ module Airbrake
|
|
24
38
|
def notice_context(queue, body)
|
25
39
|
{
|
26
40
|
queue: queue,
|
27
|
-
body: body.is_a?(Array) ? { batch: body } : { body: body }
|
41
|
+
body: body.is_a?(Array) ? { batch: body } : { body: body },
|
28
42
|
}
|
29
43
|
end
|
30
44
|
end
|
data/lib/airbrake/sidekiq.rb
CHANGED
@@ -1,17 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'airbrake/sidekiq/retryable_jobs_filter'
|
2
4
|
|
3
5
|
module Airbrake
|
4
6
|
module Sidekiq
|
5
7
|
# Provides integration with Sidekiq v2+.
|
6
8
|
class ErrorHandler
|
7
|
-
# rubocop:disable Lint/RescueException
|
8
9
|
def call(_worker, context, _queue)
|
9
|
-
|
10
|
-
|
10
|
+
timing = Airbrake::Benchmark.measure do
|
11
|
+
yield
|
12
|
+
end
|
13
|
+
rescue Exception => exception # rubocop:disable Lint/RescueException
|
11
14
|
notify_airbrake(exception, context)
|
15
|
+
Airbrake.notify_queue(
|
16
|
+
queue: context['class'],
|
17
|
+
error_count: 1,
|
18
|
+
timing: 0.01,
|
19
|
+
)
|
12
20
|
raise exception
|
21
|
+
else
|
22
|
+
Airbrake.notify_queue(
|
23
|
+
queue: context['class'],
|
24
|
+
error_count: 0,
|
25
|
+
timing: timing,
|
26
|
+
)
|
13
27
|
end
|
14
|
-
# rubocop:enable Lint/RescueException
|
15
28
|
|
16
29
|
private
|
17
30
|
|
@@ -34,14 +47,8 @@ module Airbrake
|
|
34
47
|
end
|
35
48
|
end
|
36
49
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
chain.add(Airbrake::Sidekiq::ErrorHandler)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
else
|
44
|
-
Sidekiq.configure_server do |config|
|
45
|
-
config.error_handlers << Airbrake::Sidekiq::ErrorHandler.new.method(:notify_airbrake)
|
50
|
+
Sidekiq.configure_server do |config|
|
51
|
+
config.server_middleware do |chain|
|
52
|
+
chain.add(Airbrake::Sidekiq::ErrorHandler)
|
46
53
|
end
|
47
54
|
end
|
data/lib/airbrake/sneakers.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Sneakers
|
3
5
|
# Provides integration with Sneakers.
|
@@ -10,12 +12,15 @@ module Airbrake
|
|
10
12
|
# @see https://github.com/airbrake/airbrake/issues/850
|
11
13
|
IGNORED_KEYS = %i[delivery_tag consumer channel].freeze
|
12
14
|
|
13
|
-
|
15
|
+
# rubocop:disable Style/OptionalArguments
|
16
|
+
def call(exception, worker = nil, context)
|
17
|
+
# Later versions add a middle argument.
|
14
18
|
Airbrake.notify(exception, filter_context(context)) do |notice|
|
15
19
|
notice[:context][:component] = 'sneakers'
|
16
20
|
notice[:context][:action] = worker.class.to_s
|
17
21
|
end
|
18
22
|
end
|
23
|
+
# rubocop:enable Style/OptionalArguments
|
19
24
|
|
20
25
|
private
|
21
26
|
|
@@ -32,3 +37,35 @@ module Airbrake
|
|
32
37
|
end
|
33
38
|
|
34
39
|
Sneakers.error_reporters << Airbrake::Sneakers::ErrorReporter.new
|
40
|
+
|
41
|
+
module Sneakers
|
42
|
+
# @todo Migrate to Sneakers v2.12.0 middleware API when it's released
|
43
|
+
# @see https://github.com/jondot/sneakers/pull/364
|
44
|
+
module Worker
|
45
|
+
# Sneakers v2.7.0+ renamed `do_work` to `process_work`.
|
46
|
+
if method_defined?(:process_work)
|
47
|
+
alias process_work_without_airbrake process_work
|
48
|
+
else
|
49
|
+
alias process_work_without_airbrake do_work
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_work(delivery_info, metadata, msg, handler)
|
53
|
+
timing = Airbrake::Benchmark.measure do
|
54
|
+
process_work_without_airbrake(delivery_info, metadata, msg, handler)
|
55
|
+
end
|
56
|
+
rescue Exception => exception # rubocop:disable Lint/RescueException
|
57
|
+
Airbrake.notify_queue(
|
58
|
+
queue: self.class.to_s,
|
59
|
+
error_count: 1,
|
60
|
+
timing: 0.01,
|
61
|
+
)
|
62
|
+
raise exception
|
63
|
+
else
|
64
|
+
Airbrake.notify_queue(
|
65
|
+
queue: self.class.to_s,
|
66
|
+
error_count: 0,
|
67
|
+
timing: timing,
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/airbrake/version.rb
CHANGED
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:
|
4
|
+
version: 10.0.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:
|
11
|
+
date: 2020-01-29 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.13'
|
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.13'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,6 +254,20 @@ dependencies:
|
|
254
254
|
- - '='
|
255
255
|
- !ruby/object:Gem::Version
|
256
256
|
version: 1.9.0
|
257
|
+
- !ruby/object:Gem::Dependency
|
258
|
+
name: redis-namespace
|
259
|
+
requirement: !ruby/object:Gem::Requirement
|
260
|
+
requirements:
|
261
|
+
- - '='
|
262
|
+
- !ruby/object:Gem::Version
|
263
|
+
version: 1.6.0
|
264
|
+
type: :development
|
265
|
+
prerelease: false
|
266
|
+
version_requirements: !ruby/object:Gem::Requirement
|
267
|
+
requirements:
|
268
|
+
- - '='
|
269
|
+
- !ruby/object:Gem::Version
|
270
|
+
version: 1.6.0
|
257
271
|
- !ruby/object:Gem::Dependency
|
258
272
|
name: sidekiq
|
259
273
|
requirement: !ruby/object:Gem::Requirement
|
@@ -421,8 +435,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
421
435
|
- !ruby/object:Gem::Version
|
422
436
|
version: '0'
|
423
437
|
requirements: []
|
424
|
-
|
425
|
-
rubygems_version: 2.7.6.2
|
438
|
+
rubygems_version: 3.1.2
|
426
439
|
signing_key:
|
427
440
|
specification_version: 4
|
428
441
|
summary: Airbrake is an online tool that provides robust exception tracking in any
|