airbrake 9.5.0 → 11.0.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake.rb +2 -0
  3. data/lib/airbrake/capistrano.rb +2 -0
  4. data/lib/airbrake/capistrano/capistrano2.rb +2 -0
  5. data/lib/airbrake/capistrano/capistrano3.rb +3 -1
  6. data/lib/airbrake/delayed_job.rb +24 -6
  7. data/lib/airbrake/logger.rb +2 -0
  8. data/lib/airbrake/rack.rb +4 -0
  9. data/lib/airbrake/rack/context_filter.rb +9 -2
  10. data/lib/airbrake/rack/http_headers_filter.rb +7 -5
  11. data/lib/airbrake/rack/http_params_filter.rb +2 -0
  12. data/lib/airbrake/rack/instrumentable.rb +112 -4
  13. data/lib/airbrake/rack/middleware.rb +3 -1
  14. data/lib/airbrake/rack/request_body_filter.rb +2 -0
  15. data/lib/airbrake/rack/request_store.rb +2 -0
  16. data/lib/airbrake/rack/route_filter.rb +8 -10
  17. data/lib/airbrake/rack/session_filter.rb +2 -0
  18. data/lib/airbrake/rack/user.rb +4 -0
  19. data/lib/airbrake/rack/user_filter.rb +2 -0
  20. data/lib/airbrake/rails.rb +8 -8
  21. data/lib/airbrake/rails/action_cable.rb +2 -0
  22. data/lib/airbrake/rails/action_cable/notify_callback.rb +2 -0
  23. data/lib/airbrake/rails/action_controller.rb +5 -0
  24. data/lib/airbrake/rails/action_controller_notify_subscriber.rb +6 -2
  25. data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +6 -1
  26. data/lib/airbrake/rails/action_controller_route_subscriber.rb +8 -21
  27. data/lib/airbrake/rails/active_job.rb +25 -8
  28. data/lib/airbrake/rails/active_record.rb +2 -0
  29. data/lib/airbrake/rails/active_record_subscriber.rb +7 -3
  30. data/lib/airbrake/rails/app.rb +60 -25
  31. data/lib/airbrake/rails/backtrace_cleaner.rb +13 -0
  32. data/lib/airbrake/rails/curb.rb +19 -22
  33. data/lib/airbrake/rails/event.rb +4 -6
  34. data/lib/airbrake/rails/excon_subscriber.rb +4 -0
  35. data/lib/airbrake/rails/http.rb +2 -0
  36. data/lib/airbrake/rails/http_client.rb +12 -6
  37. data/lib/airbrake/rails/net_http.rb +14 -6
  38. data/lib/airbrake/rails/railtie.rb +55 -45
  39. data/lib/airbrake/rails/typhoeus.rb +11 -7
  40. data/lib/airbrake/rake.rb +3 -1
  41. data/lib/airbrake/rake/tasks.rb +7 -5
  42. data/lib/airbrake/resque.rb +32 -0
  43. data/lib/airbrake/shoryuken.rb +17 -3
  44. data/lib/airbrake/sidekiq.rb +22 -14
  45. data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +2 -0
  46. data/lib/airbrake/sneakers.rb +39 -1
  47. data/lib/airbrake/version.rb +3 -1
  48. data/lib/generators/airbrake_generator.rb +2 -0
  49. data/lib/generators/airbrake_initializer.rb.erb +5 -3
  50. metadata +61 -90
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'airbrake/rails/event'
2
4
 
3
5
  module Airbrake
@@ -6,6 +8,8 @@ module Airbrake
6
8
  # @since v9.2.0
7
9
  class Excon
8
10
  def call(*args)
11
+ return unless Airbrake::Config.instance.performance_stats
12
+
9
13
  routes = Airbrake::Rack::RequestStore[:routes]
10
14
  return if !routes || routes.none?
11
15
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HTTP
2
4
  # Monkey-patch to measure request timing.
3
5
  class Client
@@ -1,10 +1,16 @@
1
- # Monkey-patch to measure request timing.
2
- class HTTPClient
3
- alias do_get_without_airbrake do_get_block
1
+ # frozen_string_literal: true
4
2
 
5
- def do_get_block(request, proxy, connection, &block)
6
- Airbrake::Rack.capture_timing(:http) do
7
- do_get_without_airbrake(request, proxy, connection, &block)
3
+ module Airbrake
4
+ module Rails
5
+ # Allows measuring request timing.
6
+ module HTTPClient
7
+ def do_get_block(request, proxy, connection, &block)
8
+ Airbrake::Rack.capture_timing(:http) do
9
+ super(request, proxy, connection, &block)
10
+ end
11
+ end
8
12
  end
9
13
  end
10
14
  end
15
+
16
+ HTTPClient.prepend(Airbrake::Rails::HTTPClient)
@@ -1,10 +1,18 @@
1
- # Monkey-patch Net::HTTP to benchmark it.
2
- Net::HTTP.class_eval do
3
- alias_method :request_without_airbrake, :request
1
+ # frozen_string_literal: true
4
2
 
5
- def request(request, *args, &block)
6
- Airbrake::Rack.capture_timing(:http) do
7
- request_without_airbrake(request, *args, &block)
3
+ module Airbrake
4
+ module Rails
5
+ # Monkey-patch Net::HTTP to benchmark it.
6
+ # @api private
7
+ # @since v10.0.2
8
+ module NetHttp
9
+ def request(request, *args, &block)
10
+ Airbrake::Rack.capture_timing(:http) do
11
+ super(request, *args, &block)
12
+ end
13
+ end
8
14
  end
9
15
  end
10
16
  end
17
+
18
+ Net::HTTP.prepend(Airbrake::Rails::NetHttp)
@@ -1,8 +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.
8
+ #
9
+ # rubocop:disable Metrics/BlockLength
6
10
  class Railtie < ::Rails::Railtie
7
11
  initializer('airbrake.middleware') do |app|
8
12
  # Since Rails 3.2 the ActionDispatch::DebugExceptions middleware is
@@ -16,20 +20,20 @@ module Airbrake
16
20
  # exist in Rails 5 anymore.
17
21
  app.config.middleware.insert_after(
18
22
  ActionDispatch::DebugExceptions,
19
- Airbrake::Rack::Middleware
23
+ Airbrake::Rack::Middleware,
20
24
  )
21
25
  elsif defined?(::ActiveRecord::ConnectionAdapters::ConnectionManagement)
22
26
  # Insert after ConnectionManagement to avoid DB connection leakage:
23
27
  # https://github.com/airbrake/airbrake/pull/568
24
28
  app.config.middleware.insert_after(
25
29
  ::ActiveRecord::ConnectionAdapters::ConnectionManagement,
26
- 'Airbrake::Rack::Middleware'
30
+ 'Airbrake::Rack::Middleware',
27
31
  )
28
32
  else
29
33
  # Insert after DebugExceptions for apps without ActiveRecord.
30
34
  app.config.middleware.insert_after(
31
35
  ActionDispatch::DebugExceptions,
32
- 'Airbrake::Rack::Middleware'
36
+ 'Airbrake::Rack::Middleware',
33
37
  )
34
38
  end
35
39
  end
@@ -42,7 +46,6 @@ module Airbrake
42
46
  require 'airbrake/rake/tasks'
43
47
  end
44
48
 
45
- # rubocop:disable Metrics/BlockLength
46
49
  initializer('airbrake.action_controller') do
47
50
  ActiveSupport.on_load(:action_controller, run_once: true) do
48
51
  # Patches ActionController with methods that allow us to retrieve
@@ -50,56 +53,52 @@ module Airbrake
50
53
  require 'airbrake/rails/action_controller'
51
54
  include Airbrake::Rails::ActionController
52
55
 
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
- )
56
+ # Cache route information for the duration of the request.
57
+ require 'airbrake/rails/action_controller_route_subscriber'
58
+ ActiveSupport::Notifications.subscribe(
59
+ 'start_processing.action_controller',
60
+ Airbrake::Rails::ActionControllerRouteSubscriber.new,
61
+ )
74
62
 
75
- require 'airbrake/rails/net_http' if defined?(Net) && defined?(Net::HTTP)
63
+ # Send route stats.
64
+ require 'airbrake/rails/action_controller_notify_subscriber'
65
+ ActiveSupport::Notifications.subscribe(
66
+ 'process_action.action_controller',
67
+ Airbrake::Rails::ActionControllerNotifySubscriber.new,
68
+ )
76
69
 
77
- if defined?(Curl) && defined?(Curl::CURB_VERSION)
78
- require 'airbrake/rails/curb'
79
- end
70
+ # Send performance breakdown: where a request spends its time.
71
+ require 'airbrake/rails/action_controller_performance_breakdown_subscriber'
72
+ ActiveSupport::Notifications.subscribe(
73
+ 'process_action.action_controller',
74
+ Airbrake::Rails::ActionControllerPerformanceBreakdownSubscriber.new,
75
+ )
80
76
 
81
- require 'airbrake/rails/http' if defined?(HTTP) && defined?(HTTP::Client)
82
- require 'airbrake/rails/http_client' if defined?(HTTPClient)
83
- require 'airbrake/rails/typhoeus' if defined?(Typhoeus)
77
+ require 'airbrake/rails/net_http' if defined?(Net) && defined?(Net::HTTP)
78
+ require 'airbrake/rails/curb' if defined?(Curl) && defined?(Curl::CURB_VERSION)
79
+ require 'airbrake/rails/http' if defined?(HTTP) && defined?(HTTP::Client)
80
+ require 'airbrake/rails/http_client' if defined?(HTTPClient)
81
+ require 'airbrake/rails/typhoeus' if defined?(Typhoeus)
84
82
 
85
- if defined?(Excon)
86
- require 'airbrake/rails/excon_subscriber'
87
- ActiveSupport::Notifications.subscribe(/excon/, Airbrake::Rails::Excon.new)
88
- ::Excon.defaults[:instrumentor] = ActiveSupport::Notifications
89
- end
83
+ if defined?(Excon)
84
+ require 'airbrake/rails/excon_subscriber'
85
+ ActiveSupport::Notifications.subscribe(/excon/, Airbrake::Rails::Excon.new)
86
+ ::Excon.defaults[:instrumentor] = ActiveSupport::Notifications
90
87
  end
91
88
  end
92
89
  end
93
- # rubocop:enable Metrics/BlockLength
94
90
 
95
91
  initializer('airbrake.active_record') do
96
92
  ActiveSupport.on_load(:active_record, run_once: true) do
97
93
  # Reports exceptions occurring in some bugged ActiveRecord callbacks.
98
94
  # Applicable only to the versions of Rails lower than 4.2.
99
- require 'airbrake/rails/active_record'
100
- include Airbrake::Rails::ActiveRecord
95
+ if defined?(::Rails) &&
96
+ Gem::Version.new(::Rails.version) <= Gem::Version.new('4.2')
97
+ require 'airbrake/rails/active_record'
98
+ include Airbrake::Rails::ActiveRecord
99
+ end
101
100
 
102
- if defined?(ActiveRecord) && Airbrake::Config.instance.query_stats
101
+ if defined?(ActiveRecord)
103
102
  # Send SQL queries.
104
103
  require 'airbrake/rails/active_record_subscriber'
105
104
  ActiveSupport::Notifications.subscribe(
@@ -107,11 +106,21 @@ module Airbrake
107
106
  )
108
107
 
109
108
  # Filter out parameters from SQL body.
110
- Airbrake.add_performance_filter(
111
- Airbrake::Filters::SqlFilter.new(
112
- ::ActiveRecord::Base.connection_config[:adapter]
109
+ if ::ActiveRecord::Base.respond_to?(:connection_db_config)
110
+ # Rails 6.1+ deprecates "connection_config" in favor of
111
+ # "connection_db_config", so we need an updated call.
112
+ Airbrake.add_performance_filter(
113
+ Airbrake::Filters::SqlFilter.new(
114
+ ::ActiveRecord::Base.connection_db_config.configuration_hash[:adapter],
115
+ ),
113
116
  )
114
- )
117
+ else
118
+ Airbrake.add_performance_filter(
119
+ Airbrake::Filters::SqlFilter.new(
120
+ ::ActiveRecord::Base.connection_config[:adapter],
121
+ ),
122
+ )
123
+ end
115
124
  end
116
125
  end
117
126
  end
@@ -137,5 +146,6 @@ module Airbrake
137
146
  end
138
147
  end
139
148
  end
149
+ # rubocop:enable Metrics/BlockLength
140
150
  end
141
151
  end
@@ -1,12 +1,16 @@
1
- module Typhoeus
2
- # Monkey-patch to measure request timing.
3
- class Request
4
- alias run_without_airbrake run
1
+ # frozen_string_literal: true
5
2
 
6
- def run
7
- Airbrake::Rack.capture_timing(:http) do
8
- run_without_airbrake
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)
@@ -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)
@@ -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
@@ -69,7 +71,7 @@ namespace :airbrake do
69
71
  app = ENV['HEROKU_APP']
70
72
 
71
73
  config = Bundler.with_clean_env do
72
- `heroku config --shell#{ " --app #{app}" if app }`
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|
@@ -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
@@ -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
@@ -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
- yield
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
@@ -1,22 +1,35 @@
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
- yield
10
- rescue Exception => exception
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
 
18
31
  def notify_airbrake(exception, context)
19
- Airbrake.notify(exception, context) do |notice|
32
+ Airbrake.notify(exception, job: context) do |notice|
20
33
  notice[:context][:component] = 'sidekiq'
21
34
  notice[:context][:action] = action(context)
22
35
  end
@@ -28,20 +41,15 @@ module Airbrake
28
41
  klass = context['class'] || context[:job] && context[:job]['class']
29
42
  return klass unless context[:job] && context[:job]['args'].first.is_a?(Hash)
30
43
  return klass unless (job_class = context[:job]['args'].first['job_class'])
44
+
31
45
  job_class
32
46
  end
33
47
  end
34
48
  end
35
49
  end
36
50
 
37
- if Sidekiq::VERSION < '3'
38
- Sidekiq.configure_server do |config|
39
- config.server_middleware do |chain|
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)
51
+ Sidekiq.configure_server do |config|
52
+ config.server_middleware do |chain|
53
+ chain.add(Airbrake::Sidekiq::ErrorHandler)
46
54
  end
47
55
  end