airbrake 9.5.0 → 11.0.1

Sign up to get free protection for your applications and to get access to all the features.
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