sentry-rails 4.8.1 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5457a6fe448b94ade0388542ea975187fb7dd532d5a4ee3ec8caf65b6b2d785d
4
- data.tar.gz: a4d537a4d7c3ddebc41afdb1e00187c5a776bfa269c4342f802cc1252146d4f6
3
+ metadata.gz: a6ab84e3b98547af93706b752c0242271cc0fc684269deb3bda71318b03536a0
4
+ data.tar.gz: 324b90217b7331cb38267ccdd39c07d9a87abf52880d40741ea0435e26dec621
5
5
  SHA512:
6
- metadata.gz: 6aff15bc8465765af61e404ea7a709057531a12d018fd93624fa7f470e5d7c2c51c5105c4ef63225ec66a867b54cab57e0d8b40046f145d1a43d7b641c454a58
7
- data.tar.gz: e597ec4f143aca81cc4b3bf5aa47315eb84f02df0f93a4d402b701dfe32a811dcc2eba7c437bde430cd21d2fea98eae3ee4c3f324dedc24a63941b06bdcf82bb
6
+ metadata.gz: 153d75c83b8756638f554c0a8de42154ff1e76e13725fee6a1c576bb936b1df0ac6f84968eb5bd6da1c3348052b491355aa67f233c97db8979a0f534ee65d53d
7
+ data.tar.gz: af6b9717fee9623f8923df70aa52a1b898a9296d2a28f8624f8d1358ad0569213cdb2fd34add7742509b5e247292c6a318541c329bfa0ae64c4fda578260682c
data/.gitignore CHANGED
@@ -5,7 +5,7 @@
5
5
  /doc/
6
6
  /pkg/
7
7
  /spec/reports/
8
- /spec/support/test_rails_app/db
8
+ /spec/dummy/test_rails_app/db
9
9
  /tmp/
10
10
 
11
11
  # rspec failure tracking
data/Gemfile CHANGED
@@ -5,18 +5,24 @@ gemspec
5
5
  gem "sentry-ruby", path: "../sentry-ruby"
6
6
 
7
7
  rails_version = ENV["RAILS_VERSION"]
8
- rails_version = "6.1.0" if rails_version.nil?
8
+ rails_version = "7.0.0" if rails_version.nil?
9
+ rails_version = Gem::Version.new(rails_version)
9
10
 
10
11
  gem 'activerecord-jdbcmysql-adapter', platform: :jruby
11
12
  gem "jdbc-sqlite3", platform: :jruby
12
13
 
13
- if rails_version.to_f < 6
14
+ if rails_version < Gem::Version.new("6.0.0")
14
15
  gem "sqlite3", "~> 1.3.0", platform: :ruby
15
16
  else
16
17
  gem "sqlite3", platform: :ruby
17
18
  end
18
19
 
19
- gem "rails", "~> #{rails_version}"
20
+ if rails_version >= Gem::Version.new("7.0.0")
21
+ gem "rails", github: "rails/rails", branch: "7-0-stable"
22
+ else
23
+ gem "rails", "~> #{rails_version}"
24
+ end
25
+
20
26
  gem "sprockets-rails"
21
27
 
22
28
  gem "sidekiq"
@@ -16,8 +16,8 @@ if defined?(ActiveJob)
16
16
  discard_on ActiveJob::DeserializationError
17
17
  else
18
18
  # mimic what discard_on does for Rails 5.0
19
- rescue_from ActiveJob::DeserializationError do
20
- logger.error "Discarded #{self.class} due to a #{exception}. The original exception was #{error.cause.inspect}."
19
+ rescue_from ActiveJob::DeserializationError do |exception|
20
+ logger.error "Discarded #{self.class} due to a #{exception}. The original exception was #{exception.cause.inspect}."
21
21
  end
22
22
  end
23
23
 
@@ -0,0 +1,96 @@
1
+ module Sentry
2
+ module Rails
3
+ module ActionCableExtensions
4
+ class ErrorHandler
5
+ class << self
6
+ def capture(connection, transaction_name:, extra_context: nil, &block)
7
+ return block.call unless Sentry.initialized?
8
+ # ActionCable's ConnectionStub (for testing) doesn't implement the exact same interfaces as Connection::Base.
9
+ # One thing that's missing is `env`. So calling `connection.env` direclty will fail in test environments when `stub_connection` is used.
10
+ # See https://github.com/getsentry/sentry-ruby/pull/1684 for more information.
11
+ env = connection.respond_to?(:env) ? connection.env : {}
12
+
13
+ Sentry.with_scope do |scope|
14
+ scope.set_rack_env(env)
15
+ scope.set_context("action_cable", extra_context) if extra_context
16
+ scope.set_transaction_name(transaction_name)
17
+ transaction = start_transaction(env, scope.transaction_name)
18
+ scope.set_span(transaction) if transaction
19
+
20
+ begin
21
+ block.call
22
+ finish_transaction(transaction, 200)
23
+ rescue Exception => e # rubocop:disable Lint/RescueException
24
+ Sentry::Rails.capture_exception(e)
25
+ finish_transaction(transaction, 500)
26
+
27
+ raise
28
+ end
29
+ end
30
+ end
31
+
32
+ def start_transaction(env, transaction_name)
33
+ sentry_trace = env["HTTP_SENTRY_TRACE"]
34
+ options = { name: transaction_name, op: "rails.action_cable".freeze }
35
+ transaction = Sentry::Transaction.from_sentry_trace(sentry_trace, **options) if sentry_trace
36
+ Sentry.start_transaction(transaction: transaction, **options)
37
+ end
38
+
39
+ def finish_transaction(transaction, status_code)
40
+ return unless transaction
41
+
42
+ transaction.set_http_status(status_code)
43
+ transaction.finish
44
+ end
45
+ end
46
+ end
47
+
48
+ module Connection
49
+ private
50
+
51
+ def handle_open
52
+ ErrorHandler.capture(self, transaction_name: "#{self.class.name}#connect") do
53
+ super
54
+ end
55
+ end
56
+
57
+ def handle_close
58
+ ErrorHandler.capture(self, transaction_name: "#{self.class.name}#disconnect") do
59
+ super
60
+ end
61
+ end
62
+ end
63
+
64
+ module Channel
65
+ module Subscriptions
66
+ def self.included(base)
67
+ base.class_eval do
68
+ set_callback :subscribe, :around, ->(_, block) { sentry_capture(:subscribed, &block) }, prepend: true
69
+ set_callback :unsubscribe, :around, ->(_, block) { sentry_capture(:unsubscribed, &block) }, prepend: true
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def sentry_capture(hook, &block)
76
+ extra_context = { params: params }
77
+
78
+ ErrorHandler.capture(connection, transaction_name: "#{self.class.name}##{hook}", extra_context: extra_context, &block)
79
+ end
80
+ end
81
+
82
+ module Actions
83
+ private
84
+
85
+ def dispatch_action(action, data)
86
+ extra_context = { params: params, data: data }
87
+
88
+ ErrorHandler.capture(connection, transaction_name: "#{self.class.name}##{action}", extra_context: extra_context) do
89
+ super
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,79 +1,86 @@
1
1
  module Sentry
2
2
  module Rails
3
3
  module ActiveJobExtensions
4
- def self.included(base)
5
- base.class_eval do
6
- around_perform do |job, block|
7
- if Sentry.initialized?
8
- if already_supported_by_specific_integration?(job)
9
- block.call
10
- else
11
- Sentry.with_scope do |scope|
12
- capture_and_reraise_with_sentry(job, scope, block)
13
- end
14
- end
15
- else
16
- block.call
17
- end
4
+ def perform_now
5
+ if !Sentry.initialized? || already_supported_by_sentry_integration?
6
+ super
7
+ else
8
+ SentryReporter.record(self) do
9
+ super
18
10
  end
19
11
  end
20
12
  end
21
13
 
22
- def capture_and_reraise_with_sentry(job, scope, block)
23
- scope.set_transaction_name(job.class.name)
24
- transaction =
25
- if job.is_a?(::Sentry::SendEventJob)
26
- nil
27
- else
28
- Sentry.start_transaction(name: scope.transaction_name, op: "active_job")
29
- end
14
+ def already_supported_by_sentry_integration?
15
+ Sentry.configuration.rails.skippable_job_adapters.include?(self.class.queue_adapter.class.to_s)
16
+ end
30
17
 
31
- scope.set_span(transaction) if transaction
18
+ class SentryReporter
19
+ class << self
20
+ def record(job, &block)
21
+ Sentry.with_scope do |scope|
22
+ begin
23
+ scope.set_transaction_name(job.class.name)
24
+ transaction =
25
+ if job.is_a?(::Sentry::SendEventJob)
26
+ nil
27
+ else
28
+ Sentry.start_transaction(name: scope.transaction_name, op: "active_job")
29
+ end
32
30
 
33
- block.call
31
+ scope.set_span(transaction) if transaction
34
32
 
35
- finish_transaction(transaction, 200)
36
- rescue Exception => e # rubocop:disable Lint/RescueException
37
- rescue_handler_result = rescue_with_handler(e)
38
- finish_transaction(transaction, 500)
39
- return rescue_handler_result if rescue_handler_result
33
+ yield.tap do
34
+ finish_sentry_transaction(transaction, 200)
35
+ end
36
+ rescue Exception => e # rubocop:disable Lint/RescueException
37
+ finish_sentry_transaction(transaction, 500)
40
38
 
41
- Sentry::Rails.capture_exception(
42
- e,
43
- extra: sentry_context(job),
44
- tags: {
45
- job_id: job.job_id,
46
- provider_job_id: job.provider_job_id
47
- }
48
- )
49
- raise e
50
- end
39
+ Sentry::Rails.capture_exception(
40
+ e,
41
+ extra: sentry_context(job),
42
+ tags: {
43
+ job_id: job.job_id,
44
+ provider_job_id: job.provider_job_id
45
+ }
46
+ )
47
+ raise
48
+ end
49
+ end
50
+ end
51
51
 
52
- def finish_transaction(transaction, status)
53
- return unless transaction
52
+ def finish_sentry_transaction(transaction, status)
53
+ return unless transaction
54
54
 
55
- transaction.set_http_status(status)
56
- transaction.finish
57
- end
55
+ transaction.set_http_status(status)
56
+ transaction.finish
57
+ end
58
58
 
59
- def already_supported_by_specific_integration?(job)
60
- Sentry.configuration.rails.skippable_job_adapters.include?(job.class.queue_adapter.class.to_s)
61
- end
59
+ def sentry_context(job)
60
+ {
61
+ active_job: job.class.name,
62
+ arguments: sentry_serialize_arguments(job.arguments),
63
+ scheduled_at: job.scheduled_at,
64
+ job_id: job.job_id,
65
+ provider_job_id: job.provider_job_id,
66
+ locale: job.locale
67
+ }
68
+ end
62
69
 
63
- def sentry_context(job)
64
- {
65
- active_job: job.class.name,
66
- arguments: job.arguments,
67
- scheduled_at: job.scheduled_at,
68
- job_id: job.job_id,
69
- provider_job_id: job.provider_job_id,
70
- locale: job.locale
71
- }
70
+ def sentry_serialize_arguments(argument)
71
+ case argument
72
+ when Hash
73
+ argument.transform_values { |v| sentry_serialize_arguments(v) }
74
+ when Array, Enumerable
75
+ argument.map { |v| sentry_serialize_arguments(v) }
76
+ when ->(v) { v.respond_to?(:to_global_id) }
77
+ argument.to_global_id.to_s rescue argument
78
+ else
79
+ argument
80
+ end
81
+ end
82
+ end
72
83
  end
73
84
  end
74
85
  end
75
86
  end
76
-
77
- class ActiveJob::Base
78
- include Sentry::Rails::ActiveJobExtensions
79
- end
@@ -0,0 +1,11 @@
1
+ module Sentry
2
+ module Rails
3
+ # This is not a user-facing class. You should use it with Rails 7.0's error reporter feature and its interfaces.
4
+ # See https://github.com/rails/rails/blob/main/activesupport/lib/active_support/error_reporter.rb for more information.
5
+ class ErrorSubscriber
6
+ def report(error, handled:, severity:, context:)
7
+ Sentry::Rails.capture_exception(error, level: severity, contexts: { "rails.error" => context }, tags: { handled: handled })
8
+ end
9
+ end
10
+ end
11
+ end
@@ -22,6 +22,19 @@ module Sentry
22
22
  end
23
23
  end
24
24
 
25
+ initializer "sentry.extend_action_cable", before: :eager_load! do |app|
26
+ ActiveSupport.on_load(:action_cable_connection) do
27
+ require "sentry/rails/action_cable"
28
+ prepend Sentry::Rails::ActionCableExtensions::Connection
29
+ end
30
+
31
+ ActiveSupport.on_load(:action_cable_channel) do
32
+ require "sentry/rails/action_cable"
33
+ include Sentry::Rails::ActionCableExtensions::Channel::Subscriptions
34
+ prepend Sentry::Rails::ActionCableExtensions::Channel::Actions
35
+ end
36
+ end
37
+
25
38
  config.after_initialize do |app|
26
39
  next unless Sentry.initialized?
27
40
 
@@ -33,6 +46,8 @@ module Sentry
33
46
  setup_backtrace_cleanup_callback
34
47
  inject_breadcrumbs_logger
35
48
  activate_tracing
49
+
50
+ register_error_subscriber(app) if ::Rails.version.to_f >= 7.0
36
51
  end
37
52
 
38
53
  runner do
@@ -102,5 +117,10 @@ module Sentry
102
117
  Sentry::Rails::Tracing.patch_active_support_notifications
103
118
  end
104
119
  end
120
+
121
+ def register_error_subscriber(app)
122
+ require "sentry/rails/error_subscriber"
123
+ app.executor.error_reporter.subscribe(Sentry::Rails::ErrorSubscriber.new)
124
+ end
105
125
  end
106
126
  end
@@ -5,10 +5,11 @@ module Sentry
5
5
  module Tracing
6
6
  class ActionViewSubscriber < AbstractSubscriber
7
7
  EVENT_NAMES = ["render_template.action_view"].freeze
8
+ SPAN_PREFIX = "template.".freeze
8
9
 
9
10
  def self.subscribe!
10
11
  subscribe_to_event(EVENT_NAMES) do |event_name, duration, payload|
11
- record_on_current_span(op: event_name, start_timestamp: payload[START_TIMESTAMP_NAME], description: payload[:identifier], duration: duration)
12
+ record_on_current_span(op: SPAN_PREFIX + event_name, start_timestamp: payload[START_TIMESTAMP_NAME], description: payload[:identifier], duration: duration)
12
13
  end
13
14
  end
14
15
  end
@@ -5,13 +5,14 @@ module Sentry
5
5
  module Tracing
6
6
  class ActiveRecordSubscriber < AbstractSubscriber
7
7
  EVENT_NAMES = ["sql.active_record"].freeze
8
+ SPAN_PREFIX = "db.".freeze
8
9
  EXCLUDED_EVENTS = ["SCHEMA", "TRANSACTION"].freeze
9
10
 
10
11
  def self.subscribe!
11
12
  subscribe_to_event(EVENT_NAMES) do |event_name, duration, payload|
12
13
  next if EXCLUDED_EVENTS.include? payload[:name]
13
14
 
14
- record_on_current_span(op: event_name, start_timestamp: payload[START_TIMESTAMP_NAME], description: payload[:sql], duration: duration) do |span|
15
+ record_on_current_span(op: SPAN_PREFIX + event_name, start_timestamp: payload[START_TIMESTAMP_NAME], description: payload[:sql], duration: duration) do |span|
15
16
  span.set_data(:connection_id, payload[:connection_id])
16
17
  end
17
18
  end
@@ -1,5 +1,5 @@
1
1
  module Sentry
2
2
  module Rails
3
- VERSION = "4.8.1"
3
+ VERSION = "5.2.0"
4
4
  end
5
5
  end
data/sentry-rails.gemspec CHANGED
@@ -23,5 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
 
25
25
  spec.add_dependency "railties", ">= 5.0"
26
- spec.add_dependency "sentry-ruby-core", "~> 4.8.1"
26
+ spec.add_dependency "sentry-ruby-core", "~> 5.2.0"
27
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.8.1
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-22 00:00:00.000000000 Z
11
+ date: 2022-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 4.8.1
33
+ version: 5.2.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 4.8.1
40
+ version: 5.2.0
41
41
  description: A gem that provides Rails integration for the Sentry error logger
42
42
  email: accounts@sentry.io
43
43
  executables: []
@@ -60,6 +60,7 @@ files:
60
60
  - bin/setup
61
61
  - lib/sentry-rails.rb
62
62
  - lib/sentry/rails.rb
63
+ - lib/sentry/rails/action_cable.rb
63
64
  - lib/sentry/rails/active_job.rb
64
65
  - lib/sentry/rails/background_worker.rb
65
66
  - lib/sentry/rails/backtrace_cleaner.rb
@@ -70,6 +71,7 @@ files:
70
71
  - lib/sentry/rails/controller_methods.rb
71
72
  - lib/sentry/rails/controller_transaction.rb
72
73
  - lib/sentry/rails/engine.rb
74
+ - lib/sentry/rails/error_subscriber.rb
73
75
  - lib/sentry/rails/instrument_payload_cleanup_helper.rb
74
76
  - lib/sentry/rails/overrides/streaming_reporter.rb
75
77
  - lib/sentry/rails/railtie.rb