sentry-rails 5.9.0 → 5.26.0
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/.gitignore +1 -1
- data/Gemfile +40 -26
- data/README.md +1 -1
- data/Rakefile +13 -10
- data/app/jobs/sentry/send_event_job.rb +2 -1
- data/bin/console +1 -0
- data/lib/generators/sentry_generator.rb +31 -0
- data/lib/sentry/rails/action_cable.rb +12 -6
- data/lib/sentry/rails/active_job.rb +71 -10
- data/lib/sentry/rails/background_worker.rb +2 -0
- data/lib/sentry/rails/backtrace_cleaner.rb +7 -7
- data/lib/sentry/rails/breadcrumb/active_support_logger.rb +5 -7
- data/lib/sentry/rails/breadcrumb/monotonic_active_support_logger.rb +2 -0
- data/lib/sentry/rails/capture_exceptions.rb +25 -9
- data/lib/sentry/rails/configuration.rb +107 -18
- data/lib/sentry/rails/controller_methods.rb +2 -0
- data/lib/sentry/rails/controller_transaction.rb +9 -3
- data/lib/sentry/rails/engine.rb +2 -0
- data/lib/sentry/rails/error_subscriber.rb +9 -1
- data/lib/sentry/rails/instrument_payload_cleanup_helper.rb +2 -0
- data/lib/sentry/rails/overrides/streaming_reporter.rb +2 -0
- data/lib/sentry/rails/railtie.rb +17 -4
- data/lib/sentry/rails/rescued_exception_interceptor.rb +12 -1
- data/lib/sentry/rails/tracing/abstract_subscriber.rb +2 -1
- data/lib/sentry/rails/tracing/action_controller_subscriber.rb +6 -2
- data/lib/sentry/rails/tracing/action_view_subscriber.rb +11 -2
- data/lib/sentry/rails/tracing/active_record_subscriber.rb +89 -7
- data/lib/sentry/rails/tracing/active_storage_subscriber.rb +17 -4
- data/lib/sentry/rails/tracing/active_support_subscriber.rb +63 -0
- data/lib/sentry/rails/tracing.rb +2 -0
- data/lib/sentry/rails/version.rb +3 -1
- data/lib/sentry/rails.rb +2 -0
- data/lib/sentry-rails.rb +2 -0
- data/sentry-rails.gemspec +14 -6
- metadata +14 -14
- data/CODE_OF_CONDUCT.md +0 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8136167d60f6ee67885cdde939a5aa1e29f0e9f9bc1bd64b0ff4aecc29a477a9
|
4
|
+
data.tar.gz: d03846dced0b11fbe03df3b3386c01e2d4ff84d5cfc64dcaf33612f82f2de69a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0900b1dd825499e01d9a5ce77c71bc7821581420abbb60ea8123fcdafed8d7fd9db53b8fb31bdcbbe445e95583c9b477b47f15bdeb58bc3988c54289f328d1bb'
|
7
|
+
data.tar.gz: 356eb3d7a526cb1bcd4ee56c3b32201fbbbfe58b0f6ea2cb8152fd7d732964522dea8bc83e08411271fc531c92a5cc9185b2a17dfd50d06153a1ca0f9a6ba87a
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -1,48 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
git_source(:github) { |name| "https://github.com/#{name}.git" }
|
3
5
|
|
6
|
+
eval_gemfile "../Gemfile"
|
7
|
+
|
4
8
|
# Specify your gem's dependencies in sentry-ruby.gemspec
|
5
9
|
gemspec
|
6
10
|
gem "sentry-ruby", path: "../sentry-ruby"
|
7
11
|
|
12
|
+
platform :jruby do
|
13
|
+
gem "activerecord-jdbcmysql-adapter"
|
14
|
+
gem "jdbc-sqlite3"
|
15
|
+
end
|
16
|
+
|
17
|
+
ruby_version = Gem::Version.new(RUBY_VERSION)
|
18
|
+
|
8
19
|
rails_version = ENV["RAILS_VERSION"]
|
9
|
-
rails_version = "
|
20
|
+
rails_version = "8.0.0" if rails_version.nil?
|
10
21
|
rails_version = Gem::Version.new(rails_version)
|
11
22
|
|
12
|
-
gem
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
gem "sqlite3", "~> 1.
|
23
|
+
gem "rails", "~> #{rails_version}"
|
24
|
+
|
25
|
+
if rails_version >= Gem::Version.new("8.0.0")
|
26
|
+
gem "rspec-rails"
|
27
|
+
gem "sqlite3", "~> 2.1.1", platform: :ruby
|
28
|
+
elsif rails_version >= Gem::Version.new("7.1.0")
|
29
|
+
gem "rspec-rails"
|
30
|
+
gem "sqlite3", "~> 1.7.3", platform: :ruby
|
31
|
+
elsif rails_version >= Gem::Version.new("6.1.0")
|
32
|
+
gem "rspec-rails", "~> 4.0"
|
33
|
+
|
34
|
+
if ruby_version >= Gem::Version.new("2.7.0")
|
35
|
+
gem "sqlite3", "~> 1.7.3", platform: :ruby
|
36
|
+
else
|
37
|
+
gem "sqlite3", "~> 1.6.9", platform: :ruby
|
38
|
+
end
|
17
39
|
else
|
18
|
-
gem "
|
40
|
+
gem "rspec-rails", "~> 4.0"
|
41
|
+
gem "psych", "~> 3.0.0"
|
42
|
+
|
43
|
+
if rails_version >= Gem::Version.new("6.0.0")
|
44
|
+
gem "sqlite3", "~> 1.4.0", platform: :ruby
|
45
|
+
else
|
46
|
+
gem "sqlite3", "~> 1.3.0", platform: :ruby
|
47
|
+
end
|
19
48
|
end
|
20
49
|
|
21
|
-
if
|
22
|
-
|
23
|
-
|
24
|
-
gem "
|
50
|
+
if ruby_version < Gem::Version.new("2.5.0")
|
51
|
+
# https://github.com/flavorjones/loofah/pull/267
|
52
|
+
# loofah changed the required ruby version in a patch so we need to explicitly pin it
|
53
|
+
gem "loofah", "2.20.0"
|
25
54
|
end
|
26
55
|
|
27
56
|
gem "mini_magick"
|
28
57
|
|
29
58
|
gem "sprockets-rails"
|
30
59
|
|
31
|
-
gem "sidekiq"
|
32
|
-
|
33
|
-
gem "rspec", "~> 3.0"
|
34
|
-
gem "rspec-retry"
|
35
|
-
gem "rspec-rails", "~> 4.0"
|
36
|
-
gem 'simplecov'
|
37
|
-
gem "simplecov-cobertura", "~> 1.4"
|
38
|
-
gem "rexml"
|
39
|
-
|
40
|
-
gem "rake", "~> 12.0"
|
41
|
-
|
42
|
-
gem "object_tracer"
|
43
|
-
gem "debug", github: "ruby/debug", platform: :ruby if RUBY_VERSION.to_f >= 2.6
|
44
|
-
gem "pry"
|
45
|
-
|
46
60
|
gem "benchmark-ips"
|
47
61
|
gem "benchmark_driver"
|
48
62
|
gem "benchmark-ipsa"
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
|
12
12
|
|
13
13
|
[](https://rubygems.org/gems/sentry-rails)
|
14
|
-

|
15
15
|
[](https://codecov.io/gh/getsentry/sentry-ruby/branch/master)
|
16
16
|
[](https://rubygems.org/gems/sentry-rails/)
|
17
17
|
[](https://dependabot.com/compatibility-score.html?dependency-name=sentry-rails&package-manager=bundler&version-scheme=semver)
|
data/Rakefile
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "bundler/gem_tasks"
|
2
|
-
|
4
|
+
require_relative "../lib/sentry/test/rake_tasks"
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
6
|
+
Sentry::Test::RakeTasks.define_spec_tasks(
|
7
|
+
spec_pattern: "spec/sentry/**/*_spec.rb",
|
8
|
+
spec_rspec_opts: "--order rand --format progress",
|
9
|
+
isolated_specs_pattern: "spec/isolated/**/*_spec.rb",
|
10
|
+
isolated_rspec_opts: "--format progress"
|
11
|
+
)
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
end
|
13
|
+
Sentry::Test::RakeTasks.define_versioned_specs_task(
|
14
|
+
rspec_opts: "--order rand --format progress"
|
15
|
+
)
|
13
16
|
|
14
|
-
task :
|
17
|
+
task default: [:spec, :"spec:versioned", :"spec:isolated"]
|
data/bin/console
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/base"
|
4
|
+
|
5
|
+
class SentryGenerator < ::Rails::Generators::Base
|
6
|
+
class_option :dsn, type: :string, desc: "Sentry DSN"
|
7
|
+
|
8
|
+
class_option :inject_meta, type: :boolean, default: true, desc: "Inject meta tag into layout"
|
9
|
+
|
10
|
+
def copy_initializer_file
|
11
|
+
dsn = options[:dsn] ? "'#{options[:dsn]}'" : "ENV['SENTRY_DSN']"
|
12
|
+
|
13
|
+
create_file "config/initializers/sentry.rb", <<~RUBY
|
14
|
+
# frozen_string_literal: true
|
15
|
+
|
16
|
+
Sentry.init do |config|
|
17
|
+
config.breadcrumbs_logger = [:active_support_logger]
|
18
|
+
config.dsn = #{dsn}
|
19
|
+
config.traces_sample_rate = 1.0
|
20
|
+
end
|
21
|
+
RUBY
|
22
|
+
end
|
23
|
+
|
24
|
+
def inject_code_into_layout
|
25
|
+
return unless options[:inject_meta]
|
26
|
+
|
27
|
+
inject_into_file "app/views/layouts/application.html.erb", before: "</head>\n" do
|
28
|
+
" <%= Sentry.get_trace_propagation_meta.html_safe %>\n "
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
module Rails
|
3
5
|
module ActionCableExtensions
|
4
6
|
class ErrorHandler
|
5
|
-
OP_NAME = "websocket.server"
|
7
|
+
OP_NAME = "websocket.server"
|
8
|
+
SPAN_ORIGIN = "auto.http.rails.actioncable"
|
6
9
|
|
7
10
|
class << self
|
8
11
|
def capture(connection, transaction_name:, extra_context: nil, &block)
|
@@ -33,11 +36,14 @@ module Sentry
|
|
33
36
|
end
|
34
37
|
|
35
38
|
def start_transaction(env, scope)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
options = {
|
40
|
+
name: scope.transaction_name,
|
41
|
+
source: scope.transaction_source,
|
42
|
+
op: OP_NAME,
|
43
|
+
origin: SPAN_ORIGIN
|
44
|
+
}
|
45
|
+
|
46
|
+
transaction = Sentry.continue_trace(env, **options)
|
41
47
|
Sentry.start_transaction(transaction: transaction, **options)
|
42
48
|
end
|
43
49
|
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
|
1
5
|
module Sentry
|
2
6
|
module Rails
|
3
7
|
module ActiveJobExtensions
|
@@ -16,7 +20,12 @@ module Sentry
|
|
16
20
|
end
|
17
21
|
|
18
22
|
class SentryReporter
|
19
|
-
OP_NAME = "queue.active_job"
|
23
|
+
OP_NAME = "queue.active_job"
|
24
|
+
SPAN_ORIGIN = "auto.queue.active_job"
|
25
|
+
|
26
|
+
EVENT_HANDLERS = {
|
27
|
+
"enqueue_retry.active_job" => :retry_handler
|
28
|
+
}
|
20
29
|
|
21
30
|
class << self
|
22
31
|
def record(job, &block)
|
@@ -27,7 +36,12 @@ module Sentry
|
|
27
36
|
if job.is_a?(::Sentry::SendEventJob)
|
28
37
|
nil
|
29
38
|
else
|
30
|
-
Sentry.start_transaction(
|
39
|
+
Sentry.start_transaction(
|
40
|
+
name: scope.transaction_name,
|
41
|
+
source: scope.transaction_source,
|
42
|
+
op: OP_NAME,
|
43
|
+
origin: SPAN_ORIGIN
|
44
|
+
)
|
31
45
|
end
|
32
46
|
|
33
47
|
scope.set_span(transaction) if transaction
|
@@ -38,19 +52,54 @@ module Sentry
|
|
38
52
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
39
53
|
finish_sentry_transaction(transaction, 500)
|
40
54
|
|
41
|
-
|
42
|
-
|
43
|
-
extra: sentry_context(job),
|
44
|
-
tags: {
|
45
|
-
job_id: job.job_id,
|
46
|
-
provider_job_id: job.provider_job_id
|
47
|
-
}
|
48
|
-
)
|
55
|
+
capture_exception(job, e)
|
56
|
+
|
49
57
|
raise
|
50
58
|
end
|
51
59
|
end
|
52
60
|
end
|
53
61
|
|
62
|
+
def capture_exception(job, e)
|
63
|
+
Sentry::Rails.capture_exception(
|
64
|
+
e,
|
65
|
+
extra: sentry_context(job),
|
66
|
+
tags: {
|
67
|
+
job_id: job.job_id,
|
68
|
+
provider_job_id: job.provider_job_id
|
69
|
+
}
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
def register_event_handlers
|
74
|
+
EVENT_HANDLERS.each do |name, handler|
|
75
|
+
subscribers << ActiveSupport::Notifications.subscribe(name) do |*args|
|
76
|
+
public_send(handler, *args)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def detach_event_handlers
|
82
|
+
subscribers.each do |subscriber|
|
83
|
+
ActiveSupport::Notifications.unsubscribe(subscriber)
|
84
|
+
end
|
85
|
+
subscribers.clear
|
86
|
+
end
|
87
|
+
|
88
|
+
# This handler does not capture error unless `active_job_report_on_retry_error` is true
|
89
|
+
def retry_handler(*args)
|
90
|
+
handle_error_event(*args) do |job, error|
|
91
|
+
return if !Sentry.initialized? || job.already_supported_by_sentry_integration?
|
92
|
+
return unless Sentry.configuration.rails.active_job_report_on_retry_error
|
93
|
+
|
94
|
+
capture_exception(job, error)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def handle_error_event(*args)
|
99
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
100
|
+
yield(event.payload[:job], event.payload[:error])
|
101
|
+
end
|
102
|
+
|
54
103
|
def finish_sentry_transaction(transaction, status)
|
55
104
|
return unless transaction
|
56
105
|
|
@@ -71,6 +120,12 @@ module Sentry
|
|
71
120
|
|
72
121
|
def sentry_serialize_arguments(argument)
|
73
122
|
case argument
|
123
|
+
when Range
|
124
|
+
if (argument.begin || argument.end).is_a?(ActiveSupport::TimeWithZone)
|
125
|
+
argument.to_s
|
126
|
+
else
|
127
|
+
argument.map { |v| sentry_serialize_arguments(v) }
|
128
|
+
end
|
74
129
|
when Hash
|
75
130
|
argument.transform_values { |v| sentry_serialize_arguments(v) }
|
76
131
|
when Array, Enumerable
|
@@ -81,6 +136,12 @@ module Sentry
|
|
81
136
|
argument
|
82
137
|
end
|
83
138
|
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def subscribers
|
143
|
+
@__subscribers__ ||= Set.new
|
144
|
+
end
|
84
145
|
end
|
85
146
|
end
|
86
147
|
end
|
@@ -1,21 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/backtrace_cleaner"
|
2
4
|
require "active_support/core_ext/string/access"
|
3
5
|
|
4
6
|
module Sentry
|
5
7
|
module Rails
|
6
8
|
class BacktraceCleaner < ActiveSupport::BacktraceCleaner
|
7
|
-
APP_DIRS_PATTERN = /\A(?:\.\/)?(?:app|config|lib|test|\(\w*\))
|
8
|
-
RENDER_TEMPLATE_PATTERN = /:in
|
9
|
+
APP_DIRS_PATTERN = /\A(?:\.\/)?(?:app|config|lib|test|\(\w*\))/
|
10
|
+
RENDER_TEMPLATE_PATTERN = /:in (?:`|').*_\w+_{2,3}\d+_\d+'/
|
9
11
|
|
10
12
|
def initialize
|
11
13
|
super
|
12
|
-
#
|
14
|
+
# We don't want any default silencers because they're too aggressive
|
13
15
|
remove_silencers!
|
16
|
+
# We don't want any default filters because Rails 7.2 starts shortening the paths. See #2472
|
17
|
+
remove_filters!
|
14
18
|
|
15
|
-
@root = "#{Sentry.configuration.project_root}/"
|
16
|
-
add_filter do |line|
|
17
|
-
line.start_with?(@root) ? line.from(@root.size) : line
|
18
|
-
end
|
19
19
|
add_filter do |line|
|
20
20
|
if line =~ RENDER_TEMPLATE_PATTERN
|
21
21
|
line.sub(RENDER_TEMPLATE_PATTERN, "")
|
@@ -1,20 +1,16 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Sentry
|
4
4
|
module Rails
|
5
5
|
module Breadcrumb
|
6
6
|
module ActiveSupportLogger
|
7
7
|
class << self
|
8
|
-
include InstrumentPayloadCleanupHelper
|
9
|
-
|
10
8
|
def add(name, started, _finished, _unique_id, data)
|
11
9
|
# skip Rails' internal events
|
12
10
|
return if name.start_with?("!")
|
13
11
|
|
14
12
|
if data.is_a?(Hash)
|
15
|
-
|
16
|
-
data = data.dup
|
17
|
-
cleanup_data(data)
|
13
|
+
data = data.slice(*@allowed_keys[name])
|
18
14
|
end
|
19
15
|
|
20
16
|
crumb = Sentry::Breadcrumb.new(
|
@@ -25,7 +21,9 @@ module Sentry
|
|
25
21
|
Sentry.add_breadcrumb(crumb)
|
26
22
|
end
|
27
23
|
|
28
|
-
def inject
|
24
|
+
def inject(allowed_keys)
|
25
|
+
@allowed_keys = allowed_keys
|
26
|
+
|
29
27
|
@subscriber = ::ActiveSupport::Notifications.subscribe(/.*/) do |name, started, finished, unique_id, data|
|
30
28
|
# we only record events that has a started timestamp
|
31
29
|
if started.is_a?(Time)
|
@@ -1,6 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
module Rails
|
3
5
|
class CaptureExceptions < Sentry::Rack::CaptureExceptions
|
6
|
+
RAILS_7_1 = Gem::Version.new(::Rails.version) >= Gem::Version.new("7.1.0.alpha")
|
7
|
+
SPAN_ORIGIN = "auto.http.rails"
|
8
|
+
|
4
9
|
def initialize(_)
|
5
10
|
super
|
6
11
|
|
@@ -17,32 +22,43 @@ module Sentry
|
|
17
22
|
end
|
18
23
|
|
19
24
|
def transaction_op
|
20
|
-
"http.server"
|
25
|
+
"http.server"
|
21
26
|
end
|
22
27
|
|
23
28
|
def capture_exception(exception, env)
|
24
|
-
request = ActionDispatch::Request.new(env)
|
25
|
-
|
26
29
|
# the exception will be swallowed by ShowExceptions middleware
|
27
|
-
return if
|
30
|
+
return if show_exceptions?(exception, env) && !Sentry.configuration.rails.report_rescued_exceptions
|
31
|
+
|
28
32
|
Sentry::Rails.capture_exception(exception).tap do |event|
|
29
33
|
env[ERROR_EVENT_ID_KEY] = event.event_id if event
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
33
37
|
def start_transaction(env, scope)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
+
options = {
|
39
|
+
name: scope.transaction_name,
|
40
|
+
source: scope.transaction_source,
|
41
|
+
op: transaction_op,
|
42
|
+
origin: SPAN_ORIGIN
|
43
|
+
}
|
38
44
|
|
39
45
|
if @assets_regexp && scope.transaction_name.match?(@assets_regexp)
|
40
46
|
options.merge!(sampled: false)
|
41
47
|
end
|
42
48
|
|
43
|
-
transaction = Sentry
|
49
|
+
transaction = Sentry.continue_trace(env, **options)
|
44
50
|
Sentry.start_transaction(transaction: transaction, custom_sampling_context: { env: env }, **options)
|
45
51
|
end
|
52
|
+
|
53
|
+
def show_exceptions?(exception, env)
|
54
|
+
request = ActionDispatch::Request.new(env)
|
55
|
+
|
56
|
+
if RAILS_7_1
|
57
|
+
ActionDispatch::ExceptionWrapper.new(nil, exception).show?(request)
|
58
|
+
else
|
59
|
+
request.show_exceptions?
|
60
|
+
end
|
61
|
+
end
|
46
62
|
end
|
47
63
|
end
|
48
64
|
end
|