airbrake 10.0.2 → 13.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/airbrake/capistrano/capistrano2.rb +1 -1
- data/lib/airbrake/capistrano/capistrano3.rb +1 -1
- data/lib/airbrake/delayed_job.rb +28 -30
- data/lib/airbrake/logger.rb +3 -1
- data/lib/airbrake/rack/context_filter.rb +10 -6
- data/lib/airbrake/rack/http_headers_filter.rb +4 -4
- data/lib/airbrake/rack/instrumentable.rb +9 -5
- data/lib/airbrake/rack/route_filter.rb +3 -1
- data/lib/airbrake/rack/user.rb +2 -0
- data/lib/airbrake/rack.rb +2 -0
- data/lib/airbrake/rails/action_cable.rb +19 -17
- data/lib/airbrake/rails/action_controller.rb +3 -0
- data/lib/airbrake/rails/action_controller_notify_subscriber.rb +2 -0
- data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +2 -0
- data/lib/airbrake/rails/action_controller_route_subscriber.rb +2 -0
- data/lib/airbrake/rails/active_job.rb +2 -2
- data/lib/airbrake/rails/active_record_subscriber.rb +2 -0
- data/lib/airbrake/rails/app.rb +22 -0
- data/lib/airbrake/rails/backtrace_cleaner.rb +11 -0
- data/lib/airbrake/rails/curb.rb +18 -23
- data/lib/airbrake/rails/event.rb +14 -2
- data/lib/airbrake/rails/excon_subscriber.rb +2 -0
- data/lib/airbrake/rails/http.rb +12 -8
- data/lib/airbrake/rails/http_client.rb +11 -7
- data/lib/airbrake/rails/railtie.rb +7 -99
- 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 +10 -8
- data/lib/airbrake/rails.rb +6 -8
- data/lib/airbrake/rake/tasks.rb +10 -10
- data/lib/airbrake/rake.rb +47 -46
- data/lib/airbrake/resque.rb +26 -25
- data/lib/airbrake/shoryuken.rb +2 -4
- data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +14 -8
- data/lib/airbrake/sidekiq.rb +5 -6
- data/lib/airbrake/sneakers.rb +28 -27
- data/lib/airbrake/version.rb +1 -1
- data/lib/generators/airbrake_generator.rb +3 -6
- data/lib/generators/airbrake_initializer.rb.erb +65 -65
- metadata +52 -138
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f91f4d04951002ed983c872b4d6042c1cc4c01ae609d3969b4b7e9b344bdf12
|
4
|
+
data.tar.gz: 58ee6fd62567a65f7df5178f6d0d9e6bd9cd58e9debbf62d9d75fa741b20b6d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b464a25e936fafa269f35bb5c19ed6134ba65f4184f9d76e5f5a349370e1277dc71418393c21a8427dcecc572aabaa941a5ae41dbbfa1547fa280d1416fc630
|
7
|
+
data.tar.gz: a78fdeaba2521c51e47b4f9bbee5674b1d3228e25345e7d20cac5c3186c856c6c860a5daee82adc32f8001bce3b6422be50c31dbba32912f43dd535ba1dc965b
|
@@ -21,7 +21,7 @@ module Airbrake
|
|
21
21
|
RAILS_ENV=#{fetch(:rails_env, nil)} \
|
22
22
|
|
23
23
|
bundle exec rake airbrake:deploy \
|
24
|
-
USERNAME=#{Shellwords.shellescape(ENV
|
24
|
+
USERNAME=#{Shellwords.shellescape(ENV.fetch('USER', nil) || ENV.fetch('USERNAME', nil))} \
|
25
25
|
ENVIRONMENT=#{fetch(:airbrake_env, fetch(:rails_env, 'production'))} \
|
26
26
|
REVISION=#{current_revision.strip} \
|
27
27
|
REPOSITORY=#{repository} \
|
data/lib/airbrake/delayed_job.rb
CHANGED
@@ -7,41 +7,39 @@ module Delayed
|
|
7
7
|
class Airbrake < ::Delayed::Plugin
|
8
8
|
callbacks do |lifecycle|
|
9
9
|
lifecycle.around(:invoke_job) do |job, *args, &block|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
params = job.as_json
|
10
|
+
timing = ::Airbrake::Benchmark.measure do
|
11
|
+
# Forward the call to the next callback in the callback chain
|
12
|
+
block.call(job, *args)
|
13
|
+
end
|
14
|
+
rescue Exception => exception # rubocop:disable Lint/RescueException
|
15
|
+
params = job.as_json
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
# If DelayedJob is used through ActiveJob, it contains extra info.
|
18
|
+
if job.payload_object.respond_to?(:job_data)
|
19
|
+
params[:active_job] = job.payload_object.job_data
|
20
|
+
job_class = job.payload_object.job_data['job_class']
|
21
|
+
end
|
23
22
|
|
24
|
-
|
23
|
+
action = job_class || job.payload_object.class.name
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
::Airbrake.notify(exception, params) do |notice|
|
26
|
+
notice[:context][:component] = 'delayed_job'
|
27
|
+
notice[:context][:action] = action
|
28
|
+
end
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
::Airbrake.notify_queue(
|
31
|
+
queue: action,
|
32
|
+
error_count: 1,
|
33
|
+
timing: 0.01,
|
34
|
+
)
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
36
|
+
raise exception
|
37
|
+
else
|
38
|
+
::Airbrake.notify_queue(
|
39
|
+
queue: job_class || job.payload_object.class.name,
|
40
|
+
error_count: 0,
|
41
|
+
timing: timing,
|
42
|
+
)
|
45
43
|
end
|
46
44
|
end
|
47
45
|
end
|
data/lib/airbrake/logger.rb
CHANGED
@@ -9,7 +9,7 @@ module Airbrake
|
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
# # Create a logger like you normally do and decorate it.
|
12
|
-
# logger = Airbrake::AirbrakeLogger.new(Logger.new(
|
12
|
+
# logger = Airbrake::AirbrakeLogger.new(Logger.new($stdout))
|
13
13
|
#
|
14
14
|
# # Just use the logger like you normally do.
|
15
15
|
# logger.fatal('oops')
|
@@ -24,6 +24,8 @@ module Airbrake
|
|
24
24
|
attr_reader :airbrake_level
|
25
25
|
|
26
26
|
def initialize(logger)
|
27
|
+
super
|
28
|
+
|
27
29
|
__setobj__(logger)
|
28
30
|
@airbrake_notifier = Airbrake
|
29
31
|
self.level = logger.level
|
@@ -20,14 +20,9 @@ module Airbrake
|
|
20
20
|
context = notice[:context]
|
21
21
|
|
22
22
|
context[:url] = request.url
|
23
|
-
context[:userAddr] =
|
24
|
-
if request.respond_to?(:remote_ip)
|
25
|
-
request.remote_ip
|
26
|
-
else
|
27
|
-
request.ip
|
28
|
-
end
|
29
23
|
context[:userAgent] = request.user_agent
|
30
24
|
|
25
|
+
add_ip(context, request)
|
31
26
|
add_framework_version(context)
|
32
27
|
|
33
28
|
controller = request.env['action_controller.instance']
|
@@ -60,6 +55,15 @@ module Airbrake
|
|
60
55
|
}
|
61
56
|
end
|
62
57
|
end
|
58
|
+
|
59
|
+
def add_ip(context, request)
|
60
|
+
context[:userAddr] =
|
61
|
+
if request.respond_to?(:remote_ip)
|
62
|
+
request.remote_ip
|
63
|
+
else
|
64
|
+
request.ip
|
65
|
+
end
|
66
|
+
end
|
63
67
|
end
|
64
68
|
end
|
65
69
|
end
|
@@ -8,10 +8,10 @@ module Airbrake
|
|
8
8
|
class HttpHeadersFilter
|
9
9
|
# @return [Array<String>] the prefixes of the majority of HTTP headers in
|
10
10
|
# Rack (some prefixes match the header names for simplicity)
|
11
|
-
HTTP_HEADER_PREFIXES = [
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
HTTP_HEADER_PREFIXES = %w[
|
12
|
+
HTTP_
|
13
|
+
CONTENT_TYPE
|
14
|
+
CONTENT_LENGTH
|
15
15
|
].freeze
|
16
16
|
|
17
17
|
# @return [Integer]
|
@@ -57,6 +57,7 @@ module Airbrake
|
|
57
57
|
klass.module_exec do
|
58
58
|
mod = __airbrake_capture_timing_module__
|
59
59
|
mod.module_exec do
|
60
|
+
# rubocop:disable Style/DocumentDynamicEvalDefinition
|
60
61
|
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
61
62
|
def #{method_name}(#{args})
|
62
63
|
Airbrake::Rack.capture_timing(#{label.to_s.inspect}) do
|
@@ -65,6 +66,7 @@ module Airbrake
|
|
65
66
|
end
|
66
67
|
#{visibility} :#{method_name}
|
67
68
|
RUBY
|
69
|
+
# rubocop:enable Style/DocumentDynamicEvalDefinition
|
68
70
|
end
|
69
71
|
prepend mod
|
70
72
|
end
|
@@ -83,6 +85,7 @@ module Airbrake
|
|
83
85
|
klass.module_exec do
|
84
86
|
alias_method wrapped_method_name, method_name
|
85
87
|
remove_method method_name if needs_removal
|
88
|
+
# rubocop:disable Style/DocumentDynamicEvalDefinition
|
86
89
|
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
87
90
|
def #{method_name}(#{args})
|
88
91
|
Airbrake::Rack.capture_timing(#{label.to_s.inspect}) do
|
@@ -91,6 +94,7 @@ module Airbrake
|
|
91
94
|
end
|
92
95
|
#{visibility} :#{method_name}
|
93
96
|
RUBY
|
97
|
+
# rubocop:enable Style/DocumentDynamicEvalDefinition
|
94
98
|
end
|
95
99
|
end
|
96
100
|
|
@@ -98,11 +102,11 @@ module Airbrake
|
|
98
102
|
def self.method_visibility(klass, method_name)
|
99
103
|
klass.module_exec do
|
100
104
|
if protected_method_defined?(method_name)
|
101
|
-
"protected"
|
105
|
+
"protected"
|
102
106
|
elsif private_method_defined?(method_name)
|
103
|
-
"private"
|
107
|
+
"private"
|
104
108
|
else
|
105
|
-
"public"
|
109
|
+
"public"
|
106
110
|
end
|
107
111
|
end
|
108
112
|
end
|
@@ -111,11 +115,11 @@ module Airbrake
|
|
111
115
|
# A method instead of a constant so it isn't accessible in the target.
|
112
116
|
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7")
|
113
117
|
def self.method_signature
|
114
|
-
"*args, **kw_args, &block"
|
118
|
+
"*args, **kw_args, &block"
|
115
119
|
end
|
116
120
|
else
|
117
121
|
def self.method_signature
|
118
|
-
"*args, &block"
|
122
|
+
"*args, &block"
|
119
123
|
end
|
120
124
|
end
|
121
125
|
|
@@ -28,12 +28,14 @@ module Airbrake
|
|
28
28
|
|
29
29
|
def rails_route(request)
|
30
30
|
return unless (route = Airbrake::Rails::App.recognize_route(request))
|
31
|
+
|
31
32
|
route.path
|
32
33
|
end
|
33
34
|
|
34
35
|
def sinatra_route(request)
|
35
36
|
return unless (route = request.env['sinatra.route'])
|
36
|
-
|
37
|
+
|
38
|
+
route.split.drop(1).join(' ')
|
37
39
|
end
|
38
40
|
|
39
41
|
def action_dispatch_request?(request)
|
data/lib/airbrake/rack/user.rb
CHANGED
@@ -28,6 +28,7 @@ module Airbrake
|
|
28
28
|
controller = rack_env['action_controller.instance']
|
29
29
|
return unless controller.respond_to?(:current_user, true)
|
30
30
|
return unless [-1, 0].include?(controller.method(:current_user).arity)
|
31
|
+
|
31
32
|
begin
|
32
33
|
controller.__send__(:current_user)
|
33
34
|
rescue Exception => _e # rubocop:disable Lint/RescueException
|
@@ -59,6 +60,7 @@ module Airbrake
|
|
59
60
|
# try methods with no arguments or with variable number of arguments,
|
60
61
|
# where none of them are required
|
61
62
|
return unless @user.method(key).arity.between?(-1, 0)
|
63
|
+
|
62
64
|
String(@user.__send__(key))
|
63
65
|
end
|
64
66
|
|
data/lib/airbrake/rack.rb
CHANGED
@@ -10,26 +10,28 @@ require 'airbrake/rails/action_cable/notify_callback'
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
module
|
14
|
-
module
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
module Airbrake
|
14
|
+
module ActionCable
|
15
|
+
module Channel
|
16
|
+
# @since v8.3.0
|
17
|
+
# @api private
|
18
|
+
# @see https://github.com/rails/rails/blob/master/actioncable/lib/action_cable/channel/base.rb
|
19
|
+
module Base
|
20
|
+
def perform_action(*args, &block)
|
21
|
+
super(*args, &block)
|
22
|
+
rescue Exception => ex # rubocop:disable Lint/RescueException
|
23
|
+
Airbrake.notify(ex) do |notice|
|
24
|
+
notice.stash[:action_cable_connection] = connection
|
25
|
+
notice[:context][:component] = self.class
|
26
|
+
notice[:context][:action] = args.first['action']
|
27
|
+
notice[:params].merge!(args.first)
|
28
|
+
end
|
20
29
|
|
21
|
-
|
22
|
-
perform_action_without_airbrake(*args, &block)
|
23
|
-
rescue Exception => ex # rubocop:disable Lint/RescueException
|
24
|
-
Airbrake.notify(ex) do |notice|
|
25
|
-
notice.stash[:action_cable_connection] = connection
|
26
|
-
notice[:context][:component] = self.class
|
27
|
-
notice[:context][:action] = args.first['action']
|
28
|
-
notice[:params].merge!(args.first)
|
30
|
+
raise ex
|
29
31
|
end
|
30
|
-
|
31
|
-
raise ex
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
+
|
37
|
+
ActionCable::Channel::Base.prepend(Airbrake::ActionCable::Channel::Base)
|
@@ -14,6 +14,7 @@ module Airbrake
|
|
14
14
|
# @see Airbrake#notify, #notify_airbrake_sync
|
15
15
|
def notify_airbrake(exception, params = {}, &block)
|
16
16
|
return unless (notice = build_notice(exception, params))
|
17
|
+
|
17
18
|
Airbrake.notify(notice, params, &block)
|
18
19
|
end
|
19
20
|
|
@@ -22,6 +23,7 @@ module Airbrake
|
|
22
23
|
# @see Airbrake#notify_sync, #notify_airbrake
|
23
24
|
def notify_airbrake_sync(exception, params = {}, &block)
|
24
25
|
return unless (notice = build_notice(exception, params))
|
26
|
+
|
25
27
|
Airbrake.notify_sync(notice, params, &block)
|
26
28
|
end
|
27
29
|
|
@@ -29,6 +31,7 @@ module Airbrake
|
|
29
31
|
# @return [Airbrake::Notice] the notice with information from the Rack env
|
30
32
|
def build_notice(exception, params = {})
|
31
33
|
return unless (notice = Airbrake.build_notice(exception, params))
|
34
|
+
|
32
35
|
notice.stash[:rack_request] = request
|
33
36
|
notice
|
34
37
|
end
|
@@ -11,6 +11,8 @@ module Airbrake
|
|
11
11
|
# @since v8.0.0
|
12
12
|
class ActionControllerRouteSubscriber
|
13
13
|
def call(*args)
|
14
|
+
return unless Airbrake::Config.instance.performance_stats
|
15
|
+
|
14
16
|
# We don't track routeless events.
|
15
17
|
return unless (routes = Airbrake::Rack::RequestStore[:routes])
|
16
18
|
|
@@ -22,14 +22,14 @@ module Airbrake
|
|
22
22
|
block.call
|
23
23
|
end
|
24
24
|
rescue StandardError => exception
|
25
|
-
Airbrake.
|
25
|
+
Airbrake.notify_queue(
|
26
26
|
queue: job.class.name,
|
27
27
|
error_count: 1,
|
28
28
|
timing: 0.01,
|
29
29
|
)
|
30
30
|
raise exception
|
31
31
|
else
|
32
|
-
Airbrake.
|
32
|
+
Airbrake.notify_queue(
|
33
33
|
queue: job.class.name,
|
34
34
|
error_count: 0,
|
35
35
|
timing: timing,
|
data/lib/airbrake/rails/app.rb
CHANGED
@@ -11,12 +11,19 @@ module Airbrake
|
|
11
11
|
|
12
12
|
# @param [] request
|
13
13
|
# @return [Airbrake::Rails::App::Route, nil]
|
14
|
+
# rubocop:disable Metrics/AbcSize
|
14
15
|
def self.recognize_route(request)
|
15
16
|
# Duplicate `request` because `recognize` *can* strip the request's
|
16
17
|
# `path_info`, which results in broken engine links (when the engine has
|
17
18
|
# an isolated namespace).
|
18
19
|
request_copy = request.dup
|
19
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
|
+
|
20
27
|
# We must search every engine individually to find a concrete route. If
|
21
28
|
# we rely only on the `Rails.application.routes.router`, then the
|
22
29
|
# recognize call would return the root route, neglecting PATH_INFO
|
@@ -26,6 +33,20 @@ module Airbrake
|
|
26
33
|
# * `Marketing::Engine` recognizes it as `marketing#/pricing` (correct)
|
27
34
|
engines.each do |engine|
|
28
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
|
+
|
29
50
|
path =
|
30
51
|
if engine == ::Rails.application
|
31
52
|
route.path.spec.to_s
|
@@ -46,6 +67,7 @@ module Airbrake
|
|
46
67
|
|
47
68
|
nil
|
48
69
|
end
|
70
|
+
# rubocop:enable Metrics/AbcSize
|
49
71
|
|
50
72
|
def self.engines
|
51
73
|
@engines ||= [*::Rails::Engine.subclasses, ::Rails.application]
|
@@ -4,9 +4,20 @@ module Airbrake
|
|
4
4
|
module Rails
|
5
5
|
# BacktraceCleaner is a wrapper around Rails.backtrace_cleaner.
|
6
6
|
class BacktraceCleaner
|
7
|
+
# @return [Regexp]
|
8
|
+
AIRBRAKE_FRAME_PATTERN = %r{/airbrake/lib/airbrake/}.freeze
|
9
|
+
|
7
10
|
def self.clean(backtrace)
|
8
11
|
::Rails.backtrace_cleaner.clean(backtrace).first(1)
|
9
12
|
end
|
10
13
|
end
|
11
14
|
end
|
12
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,37 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
11
11
|
end
|
12
|
-
end
|
13
|
-
|
14
|
-
alias perform_without_airbrake perform
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
def perform(&block)
|
14
|
+
Airbrake::Rack.capture_timing(:http) do
|
15
|
+
super(&block)
|
16
|
+
end
|
19
17
|
end
|
20
18
|
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
module Curl
|
25
|
-
# Monkey-patch to measure request timing.
|
26
|
-
class Multi
|
27
|
-
class << self
|
28
|
-
alias http_without_airbrake http
|
29
19
|
|
20
|
+
# Allows measuring request timing.
|
21
|
+
module CurlMulti
|
30
22
|
def http(urls_with_config, multi_options = {}, &block)
|
31
23
|
Airbrake::Rack.capture_timing(:http) do
|
32
|
-
|
24
|
+
super(urls_with_config, multi_options, &block)
|
33
25
|
end
|
34
26
|
end
|
35
27
|
end
|
36
28
|
end
|
37
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
@@ -8,12 +8,16 @@ module Airbrake
|
|
8
8
|
# @api private
|
9
9
|
class Event
|
10
10
|
# @see https://github.com/rails/rails/issues/8987
|
11
|
-
HTML_RESPONSE_WILDCARD = "*/*"
|
11
|
+
HTML_RESPONSE_WILDCARD = "*/*"
|
12
|
+
|
13
|
+
# @return [Integer]
|
14
|
+
MILLISECOND = 1000
|
12
15
|
|
13
16
|
include Airbrake::Loggable
|
14
17
|
|
15
18
|
def initialize(*args)
|
16
19
|
@event = ActiveSupport::Notifications::Event.new(*args)
|
20
|
+
@rails_7_or_greater = ::Rails::VERSION::MAJOR >= 7
|
17
21
|
end
|
18
22
|
|
19
23
|
def method
|
@@ -42,7 +46,15 @@ module Airbrake
|
|
42
46
|
end
|
43
47
|
|
44
48
|
def time
|
45
|
-
|
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
|
46
58
|
end
|
47
59
|
|
48
60
|
def groups
|
data/lib/airbrake/rails/http.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
17
|
+
|
18
|
+
HTTP::Client.prepend(Airbrake::Rails::HTTP)
|
@@ -1,12 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
15
|
+
|
16
|
+
HTTPClient.prepend(Airbrake::Rails::HTTPClient)
|