airbrake 9.3.0 → 13.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/airbrake/capistrano/capistrano2.rb +3 -1
- data/lib/airbrake/capistrano/capistrano3.rb +3 -1
- data/lib/airbrake/capistrano.rb +2 -0
- data/lib/airbrake/delayed_job.rb +31 -15
- data/lib/airbrake/logger.rb +5 -1
- data/lib/airbrake/rack/context_filter.rb +13 -2
- data/lib/airbrake/rack/http_headers_filter.rb +7 -5
- data/lib/airbrake/rack/http_params_filter.rb +2 -0
- data/lib/airbrake/rack/instrumentable.rb +116 -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 +9 -11
- data/lib/airbrake/rack/session_filter.rb +2 -0
- data/lib/airbrake/rack/user.rb +9 -1
- data/lib/airbrake/rack/user_filter.rb +2 -0
- data/lib/airbrake/rack.rb +4 -0
- data/lib/airbrake/rails/action_cable/notify_callback.rb +2 -0
- data/lib/airbrake/rails/action_cable.rb +21 -17
- data/lib/airbrake/rails/action_controller.rb +9 -4
- data/lib/airbrake/rails/action_controller_notify_subscriber.rb +6 -2
- data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +6 -1
- data/lib/airbrake/rails/action_controller_route_subscriber.rb +8 -15
- data/lib/airbrake/rails/active_job.rb +25 -8
- data/lib/airbrake/rails/active_record.rb +2 -0
- data/lib/airbrake/rails/active_record_subscriber.rb +7 -3
- data/lib/airbrake/rails/app.rb +64 -19
- data/lib/airbrake/rails/backtrace_cleaner.rb +13 -0
- data/lib/airbrake/rails/curb.rb +19 -22
- data/lib/airbrake/rails/event.rb +26 -8
- data/lib/airbrake/rails/excon_subscriber.rb +4 -0
- data/lib/airbrake/rails/http.rb +13 -7
- data/lib/airbrake/rails/http_client.rb +12 -6
- data/lib/airbrake/rails/net_http.rb +14 -6
- data/lib/airbrake/rails/railtie.rb +54 -0
- data/lib/airbrake/rails/railties/action_controller_tie.rb +90 -0
- data/lib/airbrake/rails/railties/active_record_tie.rb +74 -0
- data/lib/airbrake/rails/railties/middleware_tie.rb +62 -0
- data/lib/airbrake/rails/typhoeus.rb +11 -7
- data/lib/airbrake/rails.rb +14 -135
- data/lib/airbrake/rake/tasks.rb +15 -13
- data/lib/airbrake/rake.rb +49 -46
- data/lib/airbrake/resque.rb +33 -0
- data/lib/airbrake/shoryuken.rb +16 -4
- data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +9 -1
- data/lib/airbrake/sidekiq.rb +22 -16
- data/lib/airbrake/sneakers.rb +39 -1
- data/lib/airbrake/version.rb +3 -1
- data/lib/airbrake.rb +2 -0
- data/lib/generators/airbrake_generator.rb +5 -6
- data/lib/generators/airbrake_initializer.rb.erb +67 -65
- metadata +53 -97
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Airbrake
|
4
|
+
module Rails
|
5
|
+
module Railties
|
6
|
+
# Ties Airbrake Rails Middleware with Rails (error sending).
|
7
|
+
#
|
8
|
+
# Since Rails 3.2 the ActionDispatch::DebugExceptions middleware is
|
9
|
+
# responsible for logging exceptions and showing a debugging page in case
|
10
|
+
# the request is local. We want to insert our middleware after
|
11
|
+
# DebugExceptions, so we don't notify Airbrake about local requests.
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
# @since v13.0.1
|
15
|
+
class MiddlewareTie
|
16
|
+
def initialize(app)
|
17
|
+
@app = app
|
18
|
+
@middleware = app.config.middleware
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
return tie_rails_5_or_above if ::Rails.version.to_i >= 5
|
23
|
+
|
24
|
+
if defined?(::ActiveRecord::ConnectionAdapters::ConnectionManagement)
|
25
|
+
return tie_rails_4_or_below_with_active_record
|
26
|
+
end
|
27
|
+
|
28
|
+
tie_rails_4_or_below_without_active_record
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Avoid the warning about deprecated strings.
|
34
|
+
# Insert after DebugExceptions, since ConnectionManagement doesn't
|
35
|
+
# exist in Rails 5 anymore.
|
36
|
+
def tie_rails_5_or_above
|
37
|
+
@middleware.insert_after(
|
38
|
+
ActionDispatch::DebugExceptions,
|
39
|
+
Airbrake::Rack::Middleware,
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Insert after ConnectionManagement to avoid DB connection leakage:
|
44
|
+
# https://github.com/airbrake/airbrake/pull/568
|
45
|
+
def tie_rails_4_or_below_with_active_record
|
46
|
+
@middleware.insert_after(
|
47
|
+
::ActiveRecord::ConnectionAdapters::ConnectionManagement,
|
48
|
+
'Airbrake::Rack::Middleware',
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Insert after DebugExceptions for apps without ActiveRecord.
|
53
|
+
def tie_rails_4_or_below_without_active_record
|
54
|
+
@middleware.insert_after(
|
55
|
+
ActionDispatch::DebugExceptions,
|
56
|
+
'Airbrake::Rack::Middleware',
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -1,12 +1,16 @@
|
|
1
|
-
|
2
|
-
# Monkey-patch to measure request timing.
|
3
|
-
class Request
|
4
|
-
alias run_without_airbrake run
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
module Airbrake
|
4
|
+
module Rails
|
5
|
+
# Allow measuring request timing.
|
6
|
+
module TyphoeusRequest
|
7
|
+
def run
|
8
|
+
Airbrake::Rack.capture_timing(:http) do
|
9
|
+
super
|
10
|
+
end
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
15
|
+
|
16
|
+
Typhoeus::Request.prepend(Airbrake::Rails::TyphoeusRequest)
|
data/lib/airbrake/rails.rb
CHANGED
@@ -1,140 +1,19 @@
|
|
1
|
-
|
2
|
-
module Rails
|
3
|
-
# This railtie works for any Rails application that supports railties (Rails
|
4
|
-
# 3.2+ apps). It makes Airbrake Ruby work with Rails and report errors
|
5
|
-
# occurring in the application automatically.
|
6
|
-
class Railtie < ::Rails::Railtie
|
7
|
-
initializer('airbrake.middleware') do |app|
|
8
|
-
# Since Rails 3.2 the ActionDispatch::DebugExceptions middleware is
|
9
|
-
# responsible for logging exceptions and showing a debugging page in
|
10
|
-
# case the request is local. We want to insert our middleware after
|
11
|
-
# DebugExceptions, so we don't notify Airbrake about local requests.
|
12
|
-
|
13
|
-
if ::Rails.version.to_i >= 5
|
14
|
-
# Avoid the warning about deprecated strings.
|
15
|
-
# Insert after DebugExceptions, since ConnectionManagement doesn't
|
16
|
-
# exist in Rails 5 anymore.
|
17
|
-
app.config.middleware.insert_after(
|
18
|
-
ActionDispatch::DebugExceptions,
|
19
|
-
Airbrake::Rack::Middleware
|
20
|
-
)
|
21
|
-
elsif defined?(::ActiveRecord::ConnectionAdapters::ConnectionManagement)
|
22
|
-
# Insert after ConnectionManagement to avoid DB connection leakage:
|
23
|
-
# https://github.com/airbrake/airbrake/pull/568
|
24
|
-
app.config.middleware.insert_after(
|
25
|
-
::ActiveRecord::ConnectionAdapters::ConnectionManagement,
|
26
|
-
'Airbrake::Rack::Middleware'
|
27
|
-
)
|
28
|
-
else
|
29
|
-
# Insert after DebugExceptions for apps without ActiveRecord.
|
30
|
-
app.config.middleware.insert_after(
|
31
|
-
ActionDispatch::DebugExceptions,
|
32
|
-
'Airbrake::Rack::Middleware'
|
33
|
-
)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
rake_tasks do
|
38
|
-
# Report exceptions occurring in Rake tasks.
|
39
|
-
require 'airbrake/rake'
|
40
|
-
|
41
|
-
# Defines tasks such as `airbrake:test` & `airbrake:deploy`.
|
42
|
-
require 'airbrake/rake/tasks'
|
43
|
-
end
|
44
|
-
|
45
|
-
# rubocop:disable Metrics/BlockLength
|
46
|
-
initializer('airbrake.action_controller') do
|
47
|
-
ActiveSupport.on_load(:action_controller) do
|
48
|
-
# Patches ActionController with methods that allow us to retrieve
|
49
|
-
# interesting request data. Appends that information to notices.
|
50
|
-
require 'airbrake/rails/action_controller'
|
51
|
-
include Airbrake::Rails::ActionController
|
52
|
-
|
53
|
-
if Airbrake::Config.instance.performance_stats
|
54
|
-
# Cache route information for the duration of the request.
|
55
|
-
require 'airbrake/rails/action_controller_route_subscriber'
|
56
|
-
ActiveSupport::Notifications.subscribe(
|
57
|
-
'start_processing.action_controller',
|
58
|
-
Airbrake::Rails::ActionControllerRouteSubscriber.new
|
59
|
-
)
|
60
|
-
|
61
|
-
# Send route stats.
|
62
|
-
require 'airbrake/rails/action_controller_notify_subscriber'
|
63
|
-
ActiveSupport::Notifications.subscribe(
|
64
|
-
'process_action.action_controller',
|
65
|
-
Airbrake::Rails::ActionControllerNotifySubscriber.new
|
66
|
-
)
|
67
|
-
|
68
|
-
# Send performance breakdown: where a request spends its time.
|
69
|
-
require 'airbrake/rails/action_controller_performance_breakdown_subscriber'
|
70
|
-
ActiveSupport::Notifications.subscribe(
|
71
|
-
'process_action.action_controller',
|
72
|
-
Airbrake::Rails::ActionControllerPerformanceBreakdownSubscriber.new
|
73
|
-
)
|
74
|
-
|
75
|
-
require 'airbrake/rails/net_http' if defined?(Net) && defined?(Net::HTTP)
|
76
|
-
|
77
|
-
if defined?(Curl) && defined?(Curl::CURB_VERSION)
|
78
|
-
require 'airbrake/rails/curb'
|
79
|
-
end
|
1
|
+
# frozen_string_literal: true
|
80
2
|
|
81
|
-
|
82
|
-
require 'airbrake/rails/http_client' if defined?(HTTPClient)
|
83
|
-
require 'airbrake/rails/typhoeus' if defined?(Typhoeus)
|
3
|
+
require 'airbrake/rails/railtie'
|
84
4
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
# Reports exceptions occurring in some bugged ActiveRecord callbacks.
|
98
|
-
# Applicable only to the versions of Rails lower than 4.2.
|
99
|
-
require 'airbrake/rails/active_record'
|
100
|
-
include Airbrake::Rails::ActiveRecord
|
101
|
-
|
102
|
-
if defined?(ActiveRecord) && Airbrake::Config.instance.performance_stats
|
103
|
-
# Send SQL queries.
|
104
|
-
require 'airbrake/rails/active_record_subscriber'
|
105
|
-
ActiveSupport::Notifications.subscribe(
|
106
|
-
'sql.active_record', Airbrake::Rails::ActiveRecordSubscriber.new
|
107
|
-
)
|
108
|
-
|
109
|
-
# Filter out parameters from SQL body.
|
110
|
-
Airbrake.add_performance_filter(
|
111
|
-
Airbrake::Filters::SqlFilter.new(
|
112
|
-
::ActiveRecord::Base.connection_config[:adapter]
|
113
|
-
)
|
114
|
-
)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
initializer('airbrake.active_job') do
|
120
|
-
ActiveSupport.on_load(:active_job) do
|
121
|
-
# Reports exceptions occurring in ActiveJob jobs.
|
122
|
-
require 'airbrake/rails/active_job'
|
123
|
-
include Airbrake::Rails::ActiveJob
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
initializer('airbrake.action_cable') do
|
128
|
-
ActiveSupport.on_load(:action_cable) do
|
129
|
-
# Reports exceptions occurring in ActionCable connections.
|
130
|
-
require 'airbrake/rails/action_cable'
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
runner do
|
135
|
-
at_exit do
|
136
|
-
Airbrake.notify_sync($ERROR_INFO) if $ERROR_INFO
|
137
|
-
end
|
5
|
+
module Airbrake
|
6
|
+
# Rails namespace holds all Rails-related functionality.
|
7
|
+
module Rails
|
8
|
+
def self.logger
|
9
|
+
# Rails.logger is not set in some Rake tasks such as
|
10
|
+
# 'airbrake:deploy'. In this case we use a sensible fallback.
|
11
|
+
level = (::Rails.logger ? ::Rails.logger.level : Logger::ERROR)
|
12
|
+
|
13
|
+
if ENV['RAILS_LOG_TO_STDOUT'].present?
|
14
|
+
Logger.new($stdout, level: level)
|
15
|
+
else
|
16
|
+
Logger.new(::Rails.root.join('log', 'airbrake.log'), level: level)
|
138
17
|
end
|
139
18
|
end
|
140
19
|
end
|
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
|
@@ -51,11 +53,11 @@ namespace :airbrake do
|
|
51
53
|
raise Airbrake::Error, 'airbrake-ruby is not configured' unless Airbrake.configured?
|
52
54
|
|
53
55
|
deploy_params = {
|
54
|
-
environment: ENV
|
55
|
-
username: ENV
|
56
|
-
revision: ENV
|
57
|
-
repository: ENV
|
58
|
-
version: ENV
|
56
|
+
environment: ENV.fetch('ENVIRONMENT', nil),
|
57
|
+
username: ENV.fetch('USERNAME', nil),
|
58
|
+
revision: ENV.fetch('REVISION', nil),
|
59
|
+
repository: ENV.fetch('REPOSITORY', nil),
|
60
|
+
version: ENV.fetch('VERSION', nil),
|
59
61
|
}
|
60
62
|
promise = Airbrake.notify_deploy(deploy_params)
|
61
63
|
promise.then do
|
@@ -66,10 +68,10 @@ namespace :airbrake do
|
|
66
68
|
|
67
69
|
desc 'Install a Heroku deploy hook to notify Airbrake of deploys'
|
68
70
|
task :install_heroku_deploy_hook do
|
69
|
-
app = ENV
|
71
|
+
app = ENV.fetch('HEROKU_APP', nil)
|
70
72
|
|
71
73
|
config = Bundler.with_clean_env do
|
72
|
-
`heroku config --shell#{
|
74
|
+
`heroku config --shell#{" --app #{app}" if app}`
|
73
75
|
end
|
74
76
|
|
75
77
|
heroku_env = config.each_line.with_object({}) do |line, h|
|
@@ -83,11 +85,11 @@ namespace :airbrake do
|
|
83
85
|
|
84
86
|
unless (env = heroku_env['RAILS_ENV'])
|
85
87
|
env = 'production'
|
86
|
-
puts "Airbrake couldn't identify your app's environment,
|
87
|
-
" environment will be used."
|
88
|
+
puts "Airbrake couldn't identify your app's environment, " \
|
89
|
+
"so the '#{env}' environment will be used."
|
88
90
|
end
|
89
91
|
|
90
|
-
unless (repo = ENV
|
92
|
+
unless (repo = ENV.fetch('REPOSITORY_URL', nil))
|
91
93
|
repo = `git remote get-url origin 2>/dev/null`.chomp
|
92
94
|
if repo.empty?
|
93
95
|
puts "Airbrake couldn't identify your app's repository."
|
@@ -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/rake.rb
CHANGED
@@ -1,63 +1,66 @@
|
|
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
|
4
6
|
Rake::TaskManager.record_task_metadata = true
|
5
7
|
|
6
|
-
module
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
# rubocop:enable Lint/RescueException
|
8
|
+
module Airbrake
|
9
|
+
module Rake
|
10
|
+
# Redefine +Rake::Task#execute+, so it can report errors to Airbrake.
|
11
|
+
module Task
|
12
|
+
# A wrapper around the original +#execute+, that catches all errors and
|
13
|
+
# notifies Airbrake.
|
14
|
+
#
|
15
|
+
# rubocop:disable Lint/RescueException
|
16
|
+
def execute(args = nil)
|
17
|
+
super(args)
|
18
|
+
rescue Exception => ex
|
19
|
+
notify_airbrake(ex, args)
|
20
|
+
raise ex
|
21
|
+
end
|
22
|
+
# rubocop:enable Lint/RescueException
|
23
23
|
|
24
|
-
|
24
|
+
private
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
def notify_airbrake(exception, args)
|
27
|
+
notice = Airbrake.build_notice(exception)
|
28
|
+
notice[:context][:component] = 'rake'
|
29
|
+
notice[:context][:action] = name
|
30
|
+
notice[:params].merge!(
|
31
|
+
rake_task: task_info,
|
32
|
+
execute_args: args,
|
33
|
+
argv: ARGV.join(' '),
|
34
|
+
)
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
Airbrake.notify_sync(notice)
|
37
|
+
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize
|
40
|
+
def task_info
|
41
|
+
info = {}
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
info[:name] = name
|
44
|
+
info[:timestamp] = timestamp.to_s
|
45
|
+
info[:investigation] = investigation
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
info[:full_comment] = full_comment if full_comment
|
48
|
+
info[:arg_names] = arg_names if arg_names.any?
|
49
|
+
info[:arg_description] = arg_description if arg_description
|
50
|
+
info[:locations] = locations if locations.any?
|
51
|
+
info[:sources] = sources if sources.any?
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
if prerequisite_tasks.any?
|
54
|
+
info[:prerequisite_tasks] = prerequisite_tasks.map do |p|
|
55
|
+
p.__send__(:task_info)
|
56
|
+
end
|
56
57
|
end
|
57
|
-
end
|
58
58
|
|
59
|
-
|
59
|
+
info
|
60
|
+
end
|
61
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize
|
60
62
|
end
|
61
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize
|
62
63
|
end
|
63
64
|
end
|
65
|
+
|
66
|
+
Rake::Task.prepend(Airbrake::Rake::Task)
|
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,34 @@ module Resque
|
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
32
|
+
|
33
|
+
module Airbrake
|
34
|
+
module Resque
|
35
|
+
# Measures elapsed time of a job and notifies Airbrake of the execution
|
36
|
+
# status.
|
37
|
+
#
|
38
|
+
# @since v9.6.0
|
39
|
+
module Job
|
40
|
+
def perform
|
41
|
+
timing = Airbrake::Benchmark.measure do
|
42
|
+
super
|
43
|
+
end
|
44
|
+
rescue StandardError => exception
|
45
|
+
Airbrake.notify_queue_sync(
|
46
|
+
queue: payload['class'],
|
47
|
+
error_count: 1,
|
48
|
+
timing: 0.01,
|
49
|
+
)
|
50
|
+
raise exception
|
51
|
+
else
|
52
|
+
Airbrake.notify_queue_sync(
|
53
|
+
queue: payload['class'],
|
54
|
+
error_count: 0,
|
55
|
+
timing: timing,
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Resque::Job.prepend(Airbrake::Resque::Job)
|
data/lib/airbrake/shoryuken.rb
CHANGED
@@ -1,14 +1,26 @@
|
|
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
|
-
def call(worker, queue, _sqs_msg, body)
|
7
|
-
|
8
|
+
def call(worker, queue, _sqs_msg, body, &block)
|
9
|
+
timing = Airbrake::Benchmark.measure(&block)
|
8
10
|
rescue Exception => exception
|
9
11
|
notify_airbrake(exception, worker, queue, body)
|
10
|
-
|
12
|
+
Airbrake.notify_queue(
|
13
|
+
queue: worker.class.to_s,
|
14
|
+
error_count: 1,
|
15
|
+
timing: 0.01,
|
16
|
+
)
|
11
17
|
raise exception
|
18
|
+
else
|
19
|
+
Airbrake.notify_queue(
|
20
|
+
queue: worker.class.to_s,
|
21
|
+
error_count: 0,
|
22
|
+
timing: timing,
|
23
|
+
)
|
12
24
|
end
|
13
25
|
# rubocop:enable Lint/RescueException
|
14
26
|
|
@@ -24,7 +36,7 @@ module Airbrake
|
|
24
36
|
def notice_context(queue, body)
|
25
37
|
{
|
26
38
|
queue: queue,
|
27
|
-
body: body.is_a?(Array) ? { batch: body } : { body: body }
|
39
|
+
body: body.is_a?(Array) ? { batch: body } : { body: body },
|
28
40
|
}
|
29
41
|
end
|
30
42
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Airbrake
|
2
4
|
module Sidekiq
|
3
5
|
# Filter that can ignore notices from jobs that failed but will be retried
|
@@ -13,6 +15,10 @@ module Airbrake
|
|
13
15
|
DEFAULT_MAX_RETRY_ATTEMPTS = ::Sidekiq::JobRetry::DEFAULT_MAX_RETRY_ATTEMPTS
|
14
16
|
end
|
15
17
|
|
18
|
+
def initialize(max_retries: nil)
|
19
|
+
@max_retries = max_retries
|
20
|
+
end
|
21
|
+
|
16
22
|
def call(notice)
|
17
23
|
job = notice[:params][:job]
|
18
24
|
|
@@ -30,7 +36,9 @@ module Airbrake
|
|
30
36
|
end
|
31
37
|
|
32
38
|
def max_attempts_for(job)
|
33
|
-
if
|
39
|
+
if @max_retries
|
40
|
+
@max_retries
|
41
|
+
elsif job['retry'].is_a?(Integer)
|
34
42
|
job['retry']
|
35
43
|
else
|
36
44
|
max_retries
|
data/lib/airbrake/sidekiq.rb
CHANGED
@@ -1,22 +1,33 @@
|
|
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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
rescue Exception => exception
|
9
|
+
def call(_worker, context, _queue, &block)
|
10
|
+
timing = Airbrake::Benchmark.measure(&block)
|
11
|
+
rescue Exception => exception # rubocop:disable Lint/RescueException
|
11
12
|
notify_airbrake(exception, context)
|
13
|
+
Airbrake.notify_queue(
|
14
|
+
queue: context['class'],
|
15
|
+
error_count: 1,
|
16
|
+
timing: 0.01,
|
17
|
+
)
|
12
18
|
raise exception
|
19
|
+
else
|
20
|
+
Airbrake.notify_queue(
|
21
|
+
queue: context['class'],
|
22
|
+
error_count: 0,
|
23
|
+
timing: timing,
|
24
|
+
)
|
13
25
|
end
|
14
|
-
# rubocop:enable Lint/RescueException
|
15
26
|
|
16
27
|
private
|
17
28
|
|
18
29
|
def notify_airbrake(exception, context)
|
19
|
-
Airbrake.notify(exception, context) do |notice|
|
30
|
+
Airbrake.notify(exception, job: context) do |notice|
|
20
31
|
notice[:context][:component] = 'sidekiq'
|
21
32
|
notice[:context][:action] = action(context)
|
22
33
|
end
|
@@ -25,23 +36,18 @@ module Airbrake
|
|
25
36
|
# @return [String] job's name. When ActiveJob is present, retrieve
|
26
37
|
# job_class. When used directly, use worker's name
|
27
38
|
def action(context)
|
28
|
-
klass = context['class'] || context[:job] && context[:job]['class']
|
39
|
+
klass = context['class'] || (context[:job] && context[:job]['class'])
|
29
40
|
return klass unless context[:job] && context[:job]['args'].first.is_a?(Hash)
|
30
41
|
return klass unless (job_class = context[:job]['args'].first['job_class'])
|
42
|
+
|
31
43
|
job_class
|
32
44
|
end
|
33
45
|
end
|
34
46
|
end
|
35
47
|
end
|
36
48
|
|
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)
|
49
|
+
Sidekiq.configure_server do |config|
|
50
|
+
config.server_middleware do |chain|
|
51
|
+
chain.add(Airbrake::Sidekiq::ErrorHandler)
|
46
52
|
end
|
47
53
|
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,17 +12,21 @@ 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
|
|
22
27
|
def filter_context(context)
|
23
28
|
return context unless context[:delivery_info]
|
29
|
+
|
24
30
|
h = context.dup
|
25
31
|
h[:delivery_info] = context[:delivery_info].reject do |k, _v|
|
26
32
|
IGNORED_KEYS.include?(k)
|
@@ -32,3 +38,35 @@ module Airbrake
|
|
32
38
|
end
|
33
39
|
|
34
40
|
Sneakers.error_reporters << Airbrake::Sneakers::ErrorReporter.new
|
41
|
+
|
42
|
+
module Airbrake
|
43
|
+
module Sneakers
|
44
|
+
# @todo Migrate to Sneakers v2.12.0 middleware API when it's released
|
45
|
+
# @see https://github.com/jondot/sneakers/pull/364
|
46
|
+
module Worker
|
47
|
+
# Sneakers v2.7.0+ renamed `do_work` to `process_work`.
|
48
|
+
define_method(
|
49
|
+
::Sneakers::Worker.method_defined?(:process_work) ? :process_work : :do_work,
|
50
|
+
) do |delivery_info, metadata, msg, handler|
|
51
|
+
timing = Airbrake::Benchmark.measure do
|
52
|
+
super(delivery_info, metadata, msg, handler)
|
53
|
+
end
|
54
|
+
rescue Exception => exception # rubocop:disable Lint/RescueException
|
55
|
+
Airbrake.notify_queue(
|
56
|
+
queue: self.class.to_s,
|
57
|
+
error_count: 1,
|
58
|
+
timing: 0.01,
|
59
|
+
)
|
60
|
+
raise exception
|
61
|
+
else
|
62
|
+
Airbrake.notify_queue(
|
63
|
+
queue: self.class.to_s,
|
64
|
+
error_count: 0,
|
65
|
+
timing: timing,
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
Sneakers::Worker.prepend(Airbrake::Sneakers::Worker)
|
data/lib/airbrake/version.rb
CHANGED