airbrake 9.4.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 +5 -5
  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 +9 -1
  19. data/lib/airbrake/rack/user_filter.rb +2 -0
  20. data/lib/airbrake/rails.rb +14 -135
  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 +9 -4
  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 -15
  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 +64 -19
  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 +13 -7
  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 +151 -0
  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 +6 -12
  50. metadata +62 -76
@@ -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)
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airbrake
4
+ module Rails
5
+ # This railtie works for any Rails application that supports railties (Rails
6
+ # 3.2+ apps). It makes Airbrake Ruby work with Rails and report errors
7
+ # occurring in the application automatically.
8
+ #
9
+ # rubocop:disable Metrics/BlockLength
10
+ class Railtie < ::Rails::Railtie
11
+ initializer('airbrake.middleware') do |app|
12
+ # Since Rails 3.2 the ActionDispatch::DebugExceptions middleware is
13
+ # responsible for logging exceptions and showing a debugging page in
14
+ # case the request is local. We want to insert our middleware after
15
+ # DebugExceptions, so we don't notify Airbrake about local requests.
16
+
17
+ if ::Rails.version.to_i >= 5
18
+ # Avoid the warning about deprecated strings.
19
+ # Insert after DebugExceptions, since ConnectionManagement doesn't
20
+ # exist in Rails 5 anymore.
21
+ app.config.middleware.insert_after(
22
+ ActionDispatch::DebugExceptions,
23
+ Airbrake::Rack::Middleware,
24
+ )
25
+ elsif defined?(::ActiveRecord::ConnectionAdapters::ConnectionManagement)
26
+ # Insert after ConnectionManagement to avoid DB connection leakage:
27
+ # https://github.com/airbrake/airbrake/pull/568
28
+ app.config.middleware.insert_after(
29
+ ::ActiveRecord::ConnectionAdapters::ConnectionManagement,
30
+ 'Airbrake::Rack::Middleware',
31
+ )
32
+ else
33
+ # Insert after DebugExceptions for apps without ActiveRecord.
34
+ app.config.middleware.insert_after(
35
+ ActionDispatch::DebugExceptions,
36
+ 'Airbrake::Rack::Middleware',
37
+ )
38
+ end
39
+ end
40
+
41
+ rake_tasks do
42
+ # Report exceptions occurring in Rake tasks.
43
+ require 'airbrake/rake'
44
+
45
+ # Defines tasks such as `airbrake:test` & `airbrake:deploy`.
46
+ require 'airbrake/rake/tasks'
47
+ end
48
+
49
+ initializer('airbrake.action_controller') do
50
+ ActiveSupport.on_load(:action_controller, run_once: true) do
51
+ # Patches ActionController with methods that allow us to retrieve
52
+ # interesting request data. Appends that information to notices.
53
+ require 'airbrake/rails/action_controller'
54
+ include Airbrake::Rails::ActionController
55
+
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
+ )
62
+
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
+ )
69
+
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
+ )
76
+
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)
82
+
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
87
+ end
88
+ end
89
+ end
90
+
91
+ initializer('airbrake.active_record') do
92
+ ActiveSupport.on_load(:active_record, run_once: true) do
93
+ # Reports exceptions occurring in some bugged ActiveRecord callbacks.
94
+ # Applicable only to the versions of Rails lower than 4.2.
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
100
+
101
+ if defined?(ActiveRecord)
102
+ # Send SQL queries.
103
+ require 'airbrake/rails/active_record_subscriber'
104
+ ActiveSupport::Notifications.subscribe(
105
+ 'sql.active_record', Airbrake::Rails::ActiveRecordSubscriber.new
106
+ )
107
+
108
+ # Filter out parameters from SQL body.
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
+ ),
116
+ )
117
+ else
118
+ Airbrake.add_performance_filter(
119
+ Airbrake::Filters::SqlFilter.new(
120
+ ::ActiveRecord::Base.connection_config[:adapter],
121
+ ),
122
+ )
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ initializer('airbrake.active_job') do
129
+ ActiveSupport.on_load(:active_job, run_once: true) do
130
+ # Reports exceptions occurring in ActiveJob jobs.
131
+ require 'airbrake/rails/active_job'
132
+ include Airbrake::Rails::ActiveJob
133
+ end
134
+ end
135
+
136
+ initializer('airbrake.action_cable') do
137
+ ActiveSupport.on_load(:action_cable, run_once: true) do
138
+ # Reports exceptions occurring in ActionCable connections.
139
+ require 'airbrake/rails/action_cable'
140
+ end
141
+ end
142
+
143
+ runner do
144
+ at_exit do
145
+ Airbrake.notify_sync($ERROR_INFO) if $ERROR_INFO
146
+ end
147
+ end
148
+ end
149
+ # rubocop:enable Metrics/BlockLength
150
+ end
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)
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)
@@ -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