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.
- checksums.yaml +4 -4
- 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 +30 -30
- data/lib/airbrake/logger.rb +5 -1
- data/lib/airbrake/rack/context_filter.rb +12 -6
- data/lib/airbrake/rack/http_headers_filter.rb +6 -4
- data/lib/airbrake/rack/http_params_filter.rb +2 -0
- data/lib/airbrake/rack/instrumentable.rb +116 -4
- data/lib/airbrake/rack/middleware.rb +2 -0
- 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 +5 -1
- data/lib/airbrake/rack/session_filter.rb +2 -0
- data/lib/airbrake/rack/user.rb +4 -0
- 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 +5 -0
- data/lib/airbrake/rails/action_controller_notify_subscriber.rb +4 -0
- data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +4 -0
- data/lib/airbrake/rails/action_controller_route_subscriber.rb +4 -0
- data/lib/airbrake/rails/active_job.rb +4 -10
- data/lib/airbrake/rails/active_record.rb +2 -0
- data/lib/airbrake/rails/active_record_subscriber.rb +4 -0
- data/lib/airbrake/rails/app.rb +24 -0
- data/lib/airbrake/rails/backtrace_cleaner.rb +13 -0
- data/lib/airbrake/rails/curb.rb +19 -22
- data/lib/airbrake/rails/event.rb +16 -2
- 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 +8 -98
- 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 +8 -8
- data/lib/airbrake/rake/tasks.rb +15 -13
- data/lib/airbrake/rake.rb +49 -46
- data/lib/airbrake/resque.rb +28 -25
- data/lib/airbrake/shoryuken.rb +4 -4
- data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +2 -0
- data/lib/airbrake/sidekiq.rb +7 -6
- data/lib/airbrake/sneakers.rb +34 -28
- 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 +52 -139
data/lib/airbrake/rails/app.rb
CHANGED
@@ -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
|
data/lib/airbrake/rails/curb.rb
CHANGED
@@ -1,35 +1,32 @@
|
|
1
|
-
|
2
|
-
# Monkey-patch to measure request timing.
|
3
|
-
class Easy
|
4
|
-
alias http_without_airbrake http
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
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)
|
data/lib/airbrake/rails/event.rb
CHANGED
@@ -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 = "*/*"
|
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
|
-
|
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
|
|
data/lib/airbrake/rails/http.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
|
-
|
2
|
-
# Monkey-patch to measure request timing.
|
3
|
-
class Client
|
4
|
-
alias perform_without_airbrake perform
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
#
|
2
|
-
class HTTPClient
|
3
|
-
alias do_get_without_airbrake do_get_block
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
#
|
2
|
-
Net::HTTP.class_eval do
|
3
|
-
alias_method :request_without_airbrake, :request
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
9
|
-
|
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
|
-
|
48
|
-
|
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
|
-
|
97
|
-
|
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
|
-
|
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,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(
|
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
|