airbrake 10.0.0 → 13.0.3

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake/capistrano/capistrano2.rb +3 -1
  3. data/lib/airbrake/capistrano/capistrano3.rb +3 -1
  4. data/lib/airbrake/capistrano.rb +2 -0
  5. data/lib/airbrake/delayed_job.rb +30 -30
  6. data/lib/airbrake/logger.rb +5 -1
  7. data/lib/airbrake/rack/context_filter.rb +12 -6
  8. data/lib/airbrake/rack/http_headers_filter.rb +6 -4
  9. data/lib/airbrake/rack/http_params_filter.rb +2 -0
  10. data/lib/airbrake/rack/instrumentable.rb +116 -4
  11. data/lib/airbrake/rack/middleware.rb +2 -0
  12. data/lib/airbrake/rack/request_body_filter.rb +2 -0
  13. data/lib/airbrake/rack/request_store.rb +2 -0
  14. data/lib/airbrake/rack/route_filter.rb +5 -1
  15. data/lib/airbrake/rack/session_filter.rb +2 -0
  16. data/lib/airbrake/rack/user.rb +4 -0
  17. data/lib/airbrake/rack/user_filter.rb +2 -0
  18. data/lib/airbrake/rack.rb +4 -0
  19. data/lib/airbrake/rails/action_cable/notify_callback.rb +2 -0
  20. data/lib/airbrake/rails/action_cable.rb +21 -17
  21. data/lib/airbrake/rails/action_controller.rb +5 -0
  22. data/lib/airbrake/rails/action_controller_notify_subscriber.rb +4 -0
  23. data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +4 -0
  24. data/lib/airbrake/rails/action_controller_route_subscriber.rb +4 -0
  25. data/lib/airbrake/rails/active_job.rb +4 -10
  26. data/lib/airbrake/rails/active_record.rb +2 -0
  27. data/lib/airbrake/rails/active_record_subscriber.rb +4 -0
  28. data/lib/airbrake/rails/app.rb +24 -0
  29. data/lib/airbrake/rails/backtrace_cleaner.rb +13 -0
  30. data/lib/airbrake/rails/curb.rb +19 -22
  31. data/lib/airbrake/rails/event.rb +16 -2
  32. data/lib/airbrake/rails/excon_subscriber.rb +4 -0
  33. data/lib/airbrake/rails/http.rb +13 -7
  34. data/lib/airbrake/rails/http_client.rb +12 -6
  35. data/lib/airbrake/rails/net_http.rb +14 -6
  36. data/lib/airbrake/rails/railtie.rb +8 -98
  37. data/lib/airbrake/rails/railties/action_controller_tie.rb +90 -0
  38. data/lib/airbrake/rails/railties/active_record_tie.rb +74 -0
  39. data/lib/airbrake/rails/railties/middleware_tie.rb +62 -0
  40. data/lib/airbrake/rails/typhoeus.rb +11 -7
  41. data/lib/airbrake/rails.rb +8 -8
  42. data/lib/airbrake/rake/tasks.rb +15 -13
  43. data/lib/airbrake/rake.rb +49 -46
  44. data/lib/airbrake/resque.rb +28 -25
  45. data/lib/airbrake/shoryuken.rb +4 -4
  46. data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +2 -0
  47. data/lib/airbrake/sidekiq.rb +7 -6
  48. data/lib/airbrake/sneakers.rb +34 -28
  49. data/lib/airbrake/version.rb +3 -1
  50. data/lib/airbrake.rb +2 -0
  51. data/lib/generators/airbrake_generator.rb +5 -6
  52. data/lib/generators/airbrake_initializer.rb.erb +67 -65
  53. metadata +52 -139
@@ -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.
@@ -9,12 +11,19 @@ module Airbrake
9
11
 
10
12
  # @param [] request
11
13
  # @return [Airbrake::Rails::App::Route, nil]
14
+ # rubocop:disable Metrics/AbcSize
12
15
  def self.recognize_route(request)
13
16
  # Duplicate `request` because `recognize` *can* strip the request's
14
17
  # `path_info`, which results in broken engine links (when the engine has
15
18
  # an isolated namespace).
16
19
  request_copy = request.dup
17
20
 
21
+ # Save original script name because `router.recognize(request)` mutates
22
+ # it. It's a Rails bug. More info in:
23
+ # * https://github.com/airbrake/airbrake/issues/1072
24
+ # * https://github.com/rails/rails/issues/31152
25
+ original_script_name = request.env['SCRIPT_NAME']
26
+
18
27
  # We must search every engine individually to find a concrete route. If
19
28
  # we rely only on the `Rails.application.routes.router`, then the
20
29
  # recognize call would return the root route, neglecting PATH_INFO
@@ -24,6 +33,20 @@ module Airbrake
24
33
  # * `Marketing::Engine` recognizes it as `marketing#/pricing` (correct)
25
34
  engines.each do |engine|
26
35
  engine.routes.router.recognize(request_copy) do |route, _params|
36
+ # Restore original script name. Remove this code when/if the Rails
37
+ # bug is fixed: https://github.com/airbrake/airbrake/issues/1072
38
+ request.env['SCRIPT_NAME'] = original_script_name
39
+
40
+ # Skip "catch-all" routes such as:
41
+ # get '*path => 'pages#about'
42
+ #
43
+ # Ideally, we should be using `route.glob?` but in Rails 7+ this
44
+ # call would fail with a `NoMethodError`. This is because in
45
+ # Rails 7+ the AST for the route is not kept in memory anymore.
46
+ #
47
+ # See: https://github.com/rails/rails/pull/43006#discussion_r783895766
48
+ next if route.path.spec.any?(ActionDispatch::Journey::Nodes::Star)
49
+
27
50
  path =
28
51
  if engine == ::Rails.application
29
52
  route.path.spec.to_s
@@ -44,6 +67,7 @@ module Airbrake
44
67
 
45
68
  nil
46
69
  end
70
+ # rubocop:enable Metrics/AbcSize
47
71
 
48
72
  def self.engines
49
73
  @engines ||= [*::Rails::Engine.subclasses, ::Rails.application]
@@ -1,10 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Airbrake
2
4
  module Rails
3
5
  # BacktraceCleaner is a wrapper around Rails.backtrace_cleaner.
4
6
  class BacktraceCleaner
7
+ # @return [Regexp]
8
+ AIRBRAKE_FRAME_PATTERN = %r{/airbrake/lib/airbrake/}.freeze
9
+
5
10
  def self.clean(backtrace)
6
11
  ::Rails.backtrace_cleaner.clean(backtrace).first(1)
7
12
  end
8
13
  end
9
14
  end
10
15
  end
16
+
17
+ if defined?(Rails)
18
+ # Silence own frames to let the cleaner proceed to the next line (and probably
19
+ # find the correct call-site coming from the app code rather this library).
20
+ Rails.backtrace_cleaner.add_silencer do |line|
21
+ line =~ Airbrake::Rails::BacktraceCleaner::AIRBRAKE_FRAME_PATTERN
22
+ end
23
+ end
@@ -1,35 +1,32 @@
1
- module Curl
2
- # Monkey-patch to measure request timing.
3
- class Easy
4
- alias http_without_airbrake http
1
+ # frozen_string_literal: true
5
2
 
6
- def http(verb)
7
- Airbrake::Rack.capture_timing(:http) do
8
- http_without_airbrake(verb)
3
+ module Airbrake
4
+ module Rails
5
+ # Allows measuring request timing.
6
+ module CurlEasy
7
+ def http(verb)
8
+ Airbrake::Rack.capture_timing(:http) do
9
+ super(verb)
10
+ end
9
11
  end
10
- end
11
12
 
12
- alias perform_without_airbrake perform
13
-
14
- def perform(&block)
15
- Airbrake::Rack.capture_timing(:http) do
16
- perform_without_airbrake(&block)
13
+ def perform(&block)
14
+ Airbrake::Rack.capture_timing(:http) do
15
+ super(&block)
16
+ end
17
17
  end
18
18
  end
19
- end
20
- end
21
-
22
- module Curl
23
- # Monkey-patch to measure request timing.
24
- class Multi
25
- class << self
26
- alias http_without_airbrake http
27
19
 
20
+ # Allows measuring request timing.
21
+ module CurlMulti
28
22
  def http(urls_with_config, multi_options = {}, &block)
29
23
  Airbrake::Rack.capture_timing(:http) do
30
- http_without_airbrake(urls_with_config, multi_options, &block)
24
+ super(urls_with_config, multi_options, &block)
31
25
  end
32
26
  end
33
27
  end
34
28
  end
35
29
  end
30
+
31
+ Curl::Easy.prepend(Airbrake::Rails::CurlEasy)
32
+ Curl::Multi.singleton_class.prepend(Airbrake::Rails::CurlMulti)
@@ -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.
@@ -6,12 +8,16 @@ module Airbrake
6
8
  # @api private
7
9
  class Event
8
10
  # @see https://github.com/rails/rails/issues/8987
9
- HTML_RESPONSE_WILDCARD = "*/*".freeze
11
+ HTML_RESPONSE_WILDCARD = "*/*"
12
+
13
+ # @return [Integer]
14
+ MILLISECOND = 1000
10
15
 
11
16
  include Airbrake::Loggable
12
17
 
13
18
  def initialize(*args)
14
19
  @event = ActiveSupport::Notifications::Event.new(*args)
20
+ @rails_7_or_greater = ::Rails::VERSION::MAJOR >= 7
15
21
  end
16
22
 
17
23
  def method
@@ -40,7 +46,15 @@ module Airbrake
40
46
  end
41
47
 
42
48
  def time
43
- @event.time
49
+ # On Rails 7+ `ActiveSupport::Notifications::Event#time` returns an
50
+ # instance of Float. It represents monotonic time in milliseconds.
51
+ # Airbrake Ruby expects that the provided time is in seconds. Hence,
52
+ # we need to convert it from milliseconds to seconds. In the
53
+ # versions below Rails 7, time is an instance of Time.
54
+ #
55
+ # Relevant commit:
56
+ # https://github.com/rails/rails/commit/81d0dc90becfe0b8e7f7f26beb66c25d84b8ec7f
57
+ @rails_7_or_greater ? @event.time / MILLISECOND : @event.time
44
58
  end
45
59
 
46
60
  def groups
@@ -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,12 +1,18 @@
1
- module HTTP
2
- # Monkey-patch to measure request timing.
3
- class Client
4
- alias perform_without_airbrake perform
1
+ # frozen_string_literal: true
5
2
 
6
- def perform(request, options)
7
- Airbrake::Rack.capture_timing(:http) do
8
- perform_without_airbrake(request, options)
3
+ module Airbrake
4
+ module Rails
5
+ # Monkey-patch to measure request timing.
6
+ # @api private
7
+ # @since v11.0.2
8
+ module HTTP
9
+ def perform(request, options)
10
+ Airbrake::Rack.capture_timing(:http) do
11
+ super(request, options)
12
+ end
9
13
  end
10
14
  end
11
15
  end
12
16
  end
17
+
18
+ HTTP::Client.prepend(Airbrake::Rails::HTTP)
@@ -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,3 +1,5 @@
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
@@ -5,33 +7,8 @@ module Airbrake
5
7
  # occurring in the application automatically.
6
8
  class Railtie < ::Rails::Railtie
7
9
  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
10
+ require 'airbrake/rails/railties/middleware_tie'
11
+ Railties::MiddlewareTie.new(app).call
35
12
  end
36
13
 
37
14
  rake_tasks do
@@ -42,81 +19,14 @@ module Airbrake
42
19
  require 'airbrake/rake/tasks'
43
20
  end
44
21
 
45
- # rubocop:disable Metrics/BlockLength
46
22
  initializer('airbrake.action_controller') do
47
- ActiveSupport.on_load(:action_controller, run_once: true) 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
80
-
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)
84
-
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
90
- end
91
- end
23
+ require 'airbrake/rails/railties/action_controller_tie'
24
+ Railties::ActionControllerTie.new.call
92
25
  end
93
- # rubocop:enable Metrics/BlockLength
94
26
 
95
27
  initializer('airbrake.active_record') do
96
- ActiveSupport.on_load(:active_record, run_once: true) do
97
- # Reports exceptions occurring in some bugged ActiveRecord callbacks.
98
- # Applicable only to the versions of Rails lower than 4.2.
99
- if defined?(::Rails) &&
100
- Gem::Version.new(::Rails.version) <= Gem::Version.new('4.2')
101
- require 'airbrake/rails/active_record'
102
- include Airbrake::Rails::ActiveRecord
103
- end
104
-
105
- if defined?(ActiveRecord) && Airbrake::Config.instance.query_stats
106
- # Send SQL queries.
107
- require 'airbrake/rails/active_record_subscriber'
108
- ActiveSupport::Notifications.subscribe(
109
- 'sql.active_record', Airbrake::Rails::ActiveRecordSubscriber.new
110
- )
111
-
112
- # Filter out parameters from SQL body.
113
- Airbrake.add_performance_filter(
114
- Airbrake::Filters::SqlFilter.new(
115
- ::ActiveRecord::Base.connection_config[:adapter],
116
- ),
117
- )
118
- end
119
- end
28
+ require 'airbrake/rails/railties/active_record_tie'
29
+ Railties::ActiveRecordTie.new.call
120
30
  end
121
31
 
122
32
  initializer('airbrake.active_job') do
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'airbrake/rails/action_controller'
4
+ require 'airbrake/rails/action_controller_route_subscriber'
5
+ require 'airbrake/rails/action_controller_notify_subscriber'
6
+ require 'airbrake/rails/action_controller_performance_breakdown_subscriber'
7
+
8
+ module Airbrake
9
+ module Rails
10
+ module Railties
11
+ # Ties Airbrake APM (routes) and HTTP clients with Rails.
12
+ #
13
+ # @api private
14
+ # @since v13.0.1
15
+ class ActionControllerTie
16
+ def initialize
17
+ @route_subscriber = Airbrake::Rails::ActionControllerRouteSubscriber.new
18
+ @notify_subscriber = Airbrake::Rails::ActionControllerNotifySubscriber.new
19
+ @performance_breakdown_subscriber =
20
+ Airbrake::Rails::ActionControllerPerformanceBreakdownSubscriber.new
21
+ end
22
+
23
+ def call
24
+ ActiveSupport.on_load(:action_controller, run_once: true, yield: self) do
25
+ # Patches ActionController with methods that allow us to retrieve
26
+ # interesting request data. Appends that information to notices.
27
+ ::ActionController::Base.include(Airbrake::Rails::ActionController)
28
+
29
+ tie_routes_apm
30
+ tie_http_integrations
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def tie_routes_apm
37
+ [
38
+ # Cache route information for the duration of the request.
39
+ ['start_processing.action_controller', @route_subscriber],
40
+
41
+ # Send route stats.
42
+ ['process_action.action_controller', @notify_subscriber],
43
+
44
+ # Send performance breakdown: where a request spends its time.
45
+ ['process_action.action_controller', @performance_breakdown_subscriber],
46
+ ].each do |(event, callback)|
47
+ ActiveSupport::Notifications.subscribe(event, callback)
48
+ end
49
+ end
50
+
51
+ def tie_http_integrations
52
+ tie_net_http
53
+ tie_curl
54
+ tie_http
55
+ tie_http_client
56
+ tie_typhoeus
57
+ tie_excon
58
+ end
59
+
60
+ def tie_net_http
61
+ require 'airbrake/rails/net_http' if defined?(Net) && defined?(Net::HTTP)
62
+ end
63
+
64
+ def tie_curl
65
+ require 'airbrake/rails/curb' if defined?(Curl) && defined?(Curl::CURB_VERSION)
66
+ end
67
+
68
+ def tie_http
69
+ require 'airbrake/rails/http' if defined?(HTTP) && defined?(HTTP::Client)
70
+ end
71
+
72
+ def tie_http_client
73
+ require 'airbrake/rails/http_client' if defined?(HTTPClient)
74
+ end
75
+
76
+ def tie_typhoeus
77
+ require 'airbrake/rails/typhoeus' if defined?(Typhoeus)
78
+ end
79
+
80
+ def tie_excon
81
+ return unless defined?(Excon)
82
+
83
+ require 'airbrake/rails/excon_subscriber'
84
+ ActiveSupport::Notifications.subscribe(/excon/, Airbrake::Rails::Excon.new)
85
+ ::Excon.defaults[:instrumentor] = ActiveSupport::Notifications
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'airbrake/rails/active_record'
4
+ require 'airbrake/rails/active_record_subscriber'
5
+
6
+ module Airbrake
7
+ module Rails
8
+ module Railties
9
+ # Ties Airbrake APM (queries) with Rails.
10
+ #
11
+ # @api private
12
+ # @since v13.0.1
13
+ class ActiveRecordTie
14
+ def initialize
15
+ @active_record_subscriber = Airbrake::Rails::ActiveRecordSubscriber.new
16
+ end
17
+
18
+ def call
19
+ ActiveSupport.on_load(:active_record, run_once: true, yield: self) do
20
+ tie_activerecord_callback_fix
21
+ tie_activerecord_apm
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def tie_activerecord_callback_fix
28
+ # Reports exceptions occurring in some bugged ActiveRecord callbacks.
29
+ # Applicable only to the versions of Rails lower than 4.2.
30
+ return unless defined?(::Rails)
31
+ return if Gem::Version.new(::Rails.version) > Gem::Version.new('4.2')
32
+
33
+ ActiveRecord::Base.include(Airbrake::Rails::ActiveRecord)
34
+ end
35
+
36
+ def tie_activerecord_apm
37
+ # Some Rails apps don't use ActiveRecord.
38
+ return unless defined?(::ActiveRecord)
39
+
40
+ # However, some dependencies might still require it, so we need an
41
+ # extra check. Apps that don't need ActiveRecord will likely have no
42
+ # AR configurations defined. We will skip APM integration in that
43
+ # case. See: https://github.com/airbrake/airbrake/issues/1222
44
+ configurations = ::ActiveRecord::Base.configurations
45
+ return unless configurations.any?
46
+
47
+ # Send SQL queries.
48
+ ActiveSupport::Notifications.subscribe(
49
+ 'sql.active_record',
50
+ @active_record_subscriber,
51
+ )
52
+
53
+ # Filter out parameters from SQL body.
54
+ sql_filter = Airbrake::Filters::SqlFilter.new(
55
+ detect_activerecord_adapter(configurations),
56
+ )
57
+ Airbrake.add_performance_filter(sql_filter)
58
+ end
59
+
60
+ # Rails 6+ introduces the `configs_for` API instead of the deprecated
61
+ # `#[]`, so we need an updated call.
62
+ def detect_activerecord_adapter(configurations)
63
+ unless configurations.respond_to?(:configs_for)
64
+ return configurations[::Rails.env]['adapter']
65
+ end
66
+
67
+ cfg = configurations.configs_for(env_name: ::Rails.env).first
68
+ # Rails 7+ API : Rails 6 API.
69
+ cfg.respond_to?(:adapter) ? cfg.adapter : cfg.config['adapter']
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -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
- 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,19 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'airbrake/rails/railtie'
2
4
 
3
5
  module Airbrake
4
6
  # Rails namespace holds all Rails-related functionality.
5
7
  module Rails
6
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
+
7
13
  if ENV['RAILS_LOG_TO_STDOUT'].present?
8
- Logger.new(STDOUT, level: ::Rails.logger.level)
14
+ Logger.new($stdout, level: level)
9
15
  else
10
- Logger.new(
11
- ::Rails.root.join('log', 'airbrake.log'),
12
-
13
- # Rails.logger is not set in some Rake tasks such as
14
- # 'airbrake:deploy'. In this case we use a sensible fallback.
15
- level: (::Rails.logger ? ::Rails.logger.level : Logger::ERROR),
16
- )
16
+ Logger.new(::Rails.root.join('log', 'airbrake.log'), level: level)
17
17
  end
18
18
  end
19
19
  end