sentry-rails 5.3.0 → 5.8.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: c10021ca91c13dc4b34f024269a01974d75e8971b72b027f497c7c3c248ba448
4
- data.tar.gz: e4daa4206bd67b93787a7b08653808d72f7e1f667caab27f2382496e9dec474b
3
+ metadata.gz: 7338e366bfa078e533320c9d9fcac994ca4202104a3a3efb2069644d4ac80e9c
4
+ data.tar.gz: 27b90498fc73e7884ffcdea4733244723fa0e6f8a48d3322f9e7a91b25f8b73b
5
5
  SHA512:
6
- metadata.gz: 18b27b1e7b1acc3facd390069f7cd62ef434bd94b5dee2cd440f6f29cfb7b3411193c7425851116aaa199394f57df93c3d1be4c634e8d9a985786342a7ca6745
7
- data.tar.gz: f4a3c87c7b053b9e3c0adaffa620570b0d92be984d8c2337df552fcab1a9cae1b34c299f3bdb5506106037d960f35b8cc8f51a9f3b73d8666e2ee0ae02634055
6
+ metadata.gz: 7c67ec56cf2d1cd69d8808f7a83ce2af69fea58781fff3c5979bac4005ea077451b9682e6e45b1b8333d9d1b42cb29690dc53cc59b6baef4ba2ef47895bd0bb0
7
+ data.tar.gz: 1ec19c91b4d6e7bd2255c2f73ad12f035d90433a1d36a6fbba4f7ec21cbe6d5694b9ec44690ac22411003ab2e6948b9a56da8ba441123a84daa1d4b477266a51
data/Gemfile CHANGED
@@ -18,12 +18,14 @@ else
18
18
  gem "sqlite3", platform: :ruby
19
19
  end
20
20
 
21
- if rails_version >= Gem::Version.new("7.0.0")
22
- gem "rails", github: "rails/rails", branch: "7-0-stable"
21
+ if rails_version > Gem::Version.new("7.0.0")
22
+ gem "rails", github: "rails/rails"
23
23
  else
24
24
  gem "rails", "~> #{rails_version}"
25
25
  end
26
26
 
27
+ gem "mini_magick"
28
+
27
29
  gem "sprockets-rails"
28
30
 
29
31
  gem "sidekiq"
@@ -2,6 +2,8 @@ module Sentry
2
2
  module Rails
3
3
  module ActionCableExtensions
4
4
  class ErrorHandler
5
+ OP_NAME = "websocket.server".freeze
6
+
5
7
  class << self
6
8
  def capture(connection, transaction_name:, extra_context: nil, &block)
7
9
  return block.call unless Sentry.initialized?
@@ -13,13 +15,14 @@ module Sentry
13
15
  Sentry.with_scope do |scope|
14
16
  scope.set_rack_env(env)
15
17
  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_transaction_name(transaction_name, source: :view)
19
+ transaction = start_transaction(env, scope)
18
20
  scope.set_span(transaction) if transaction
19
21
 
20
22
  begin
21
- block.call
23
+ result = block.call
22
24
  finish_transaction(transaction, 200)
25
+ result
23
26
  rescue Exception => e # rubocop:disable Lint/RescueException
24
27
  Sentry::Rails.capture_exception(e)
25
28
  finish_transaction(transaction, 500)
@@ -29,10 +32,12 @@ module Sentry
29
32
  end
30
33
  end
31
34
 
32
- def start_transaction(env, transaction_name)
35
+ def start_transaction(env, scope)
33
36
  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
37
+ baggage = env["HTTP_BAGGAGE"]
38
+
39
+ options = { name: scope.transaction_name, source: scope.transaction_source, op: OP_NAME }
40
+ transaction = Sentry::Transaction.from_sentry_trace(sentry_trace, baggage: baggage, **options) if sentry_trace
36
41
  Sentry.start_transaction(transaction: transaction, **options)
37
42
  end
38
43
 
@@ -16,16 +16,18 @@ module Sentry
16
16
  end
17
17
 
18
18
  class SentryReporter
19
+ OP_NAME = "queue.active_job".freeze
20
+
19
21
  class << self
20
22
  def record(job, &block)
21
23
  Sentry.with_scope do |scope|
22
24
  begin
23
- scope.set_transaction_name(job.class.name)
25
+ scope.set_transaction_name(job.class.name, source: :task)
24
26
  transaction =
25
27
  if job.is_a?(::Sentry::SendEventJob)
26
28
  nil
27
29
  else
28
- Sentry.start_transaction(name: scope.transaction_name, op: "active_job")
30
+ Sentry.start_transaction(name: scope.transaction_name, source: scope.transaction_source, op: OP_NAME)
29
31
  end
30
32
 
31
33
  scope.set_span(transaction) if transaction
@@ -1,14 +1,12 @@
1
1
  module Sentry
2
2
  class BackgroundWorker
3
3
  def _perform(&block)
4
+ block.call
5
+ ensure
4
6
  # some applications have partial or even no AR connection
5
7
  if ActiveRecord::Base.connected?
6
8
  # make sure the background worker returns AR connection if it accidentally acquire one during serialization
7
- ActiveRecord::Base.connection_pool.with_connection do
8
- block.call
9
- end
10
- else
11
- block.call
9
+ ActiveRecord::Base.connection_pool.release_connection
12
10
  end
13
11
  end
14
12
  end
@@ -1,11 +1,11 @@
1
1
  module Sentry
2
2
  module Rails
3
3
  class CaptureExceptions < Sentry::Rack::CaptureExceptions
4
- def initialize(app)
4
+ def initialize(_)
5
5
  super
6
6
 
7
- if defined?(::Sprockets::Rails)
8
- @assets_regex = %r(\A/{0,2}#{::Rails.application.config.assets.prefix})
7
+ if Sentry.initialized?
8
+ @assets_regexp = Sentry.configuration.rails.assets_regexp
9
9
  end
10
10
  end
11
11
 
@@ -17,28 +17,30 @@ module Sentry
17
17
  end
18
18
 
19
19
  def transaction_op
20
- "rails.request".freeze
20
+ "http.server".freeze
21
21
  end
22
22
 
23
- def capture_exception(exception)
24
- current_scope = Sentry.get_current_scope
23
+ def capture_exception(exception, env)
24
+ request = ActionDispatch::Request.new(env)
25
25
 
26
- if original_transaction = current_scope.rack_env["sentry.original_transaction"]
27
- current_scope.set_transaction_name(original_transaction)
26
+ # the exception will be swallowed by ShowExceptions middleware
27
+ return if request.show_exceptions? && !Sentry.configuration.rails.report_rescued_exceptions
28
+ Sentry::Rails.capture_exception(exception).tap do |event|
29
+ env[ERROR_EVENT_ID_KEY] = event.event_id if event
28
30
  end
29
-
30
- Sentry::Rails.capture_exception(exception)
31
31
  end
32
32
 
33
33
  def start_transaction(env, scope)
34
34
  sentry_trace = env["HTTP_SENTRY_TRACE"]
35
- options = { name: scope.transaction_name, op: transaction_op }
35
+ baggage = env["HTTP_BAGGAGE"]
36
+
37
+ options = { name: scope.transaction_name, source: scope.transaction_source, op: transaction_op }
36
38
 
37
- if @assets_regex && scope.transaction_name.match?(@assets_regex)
39
+ if @assets_regexp && scope.transaction_name.match?(@assets_regexp)
38
40
  options.merge!(sampled: false)
39
41
  end
40
42
 
41
- transaction = Sentry::Transaction.from_sentry_trace(sentry_trace, **options) if sentry_trace
43
+ transaction = Sentry::Transaction.from_sentry_trace(sentry_trace, baggage: baggage, **options) if sentry_trace
42
44
  Sentry.start_transaction(transaction: transaction, custom_sampling_context: { env: env }, **options)
43
45
  end
44
46
  end
@@ -60,12 +60,29 @@ module Sentry
60
60
 
61
61
  attr_accessor :tracing_subscribers
62
62
 
63
+ # sentry-rails by default skips asset request' transactions by checking if the path matches
64
+ #
65
+ # ```rb
66
+ # %r(\A/{0,2}#{::Rails.application.config.assets.prefix})
67
+ # ```
68
+ #
69
+ # If you want to use a different pattern, you can configure the `assets_regexp` option like:
70
+ #
71
+ # ```rb
72
+ # Sentry.init do |config|
73
+ # config.rails.assets_regexp = /my_regexp/
74
+ # end
75
+ # ```
76
+ attr_accessor :assets_regexp
77
+
63
78
  def initialize
64
79
  @register_error_subscriber = false
65
80
  @report_rescued_exceptions = true
66
81
  @skippable_job_adapters = []
82
+ @assets_regexp = if defined?(::Sprockets::Rails)
83
+ %r(\A/{0,2}#{::Rails.application.config.assets.prefix})
84
+ end
67
85
  @tracing_subscribers = Set.new([
68
- Sentry::Rails::Tracing::ActionControllerSubscriber,
69
86
  Sentry::Rails::Tracing::ActionViewSubscriber,
70
87
  Sentry::Rails::Tracing::ActiveRecordSubscriber,
71
88
  Sentry::Rails::Tracing::ActiveStorageSubscriber
@@ -2,8 +2,34 @@ module Sentry
2
2
  module Rails
3
3
  module ControllerTransaction
4
4
  def self.included(base)
5
- base.prepend_before_action do |controller|
6
- Sentry.get_current_scope.set_transaction_name("#{controller.class}##{controller.action_name}")
5
+ base.prepend_around_action(:sentry_around_action)
6
+ end
7
+
8
+ private
9
+
10
+ def sentry_around_action
11
+ if Sentry.initialized?
12
+ transaction_name = "#{self.class}##{action_name}"
13
+ Sentry.get_current_scope.set_transaction_name(transaction_name, source: :view)
14
+ Sentry.with_child_span(op: "view.process_action.action_controller", description: transaction_name) do |child_span|
15
+ if child_span
16
+ begin
17
+ result = yield
18
+ ensure
19
+ child_span.set_http_status(response.status)
20
+ child_span.set_data(:format, request.format)
21
+ child_span.set_data(:method, request.method)
22
+ child_span.set_data(:path, request.path)
23
+ child_span.set_data(:params, request.params)
24
+ end
25
+
26
+ result
27
+ else
28
+ yield
29
+ end
30
+ end
31
+ else
32
+ yield
7
33
  end
8
34
  end
9
35
  end
@@ -1,10 +1,25 @@
1
1
  module Sentry
2
2
  module Rails
3
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.
4
+ # See https://github.com/rails/rails/blob/main/activesupport/lib/active_support/error_reporter.rb to learn more about reporting APIs.
5
+ # If you want Sentry to subscribe to the error reporter, please set `config.rails.register_error_subscriber` to `true`.
5
6
  class ErrorSubscriber
6
- def report(error, handled:, severity:, context:)
7
- Sentry::Rails.capture_exception(error, level: severity, contexts: { "rails.error" => context }, tags: { handled: handled })
7
+ SKIP_SOURCES = Regexp.union([/.*_cache_store.active_support/])
8
+
9
+ def report(error, handled:, severity:, context:, source: nil)
10
+ tags = { handled: handled }
11
+
12
+ if source
13
+ return if SKIP_SOURCES.match?(source)
14
+ tags[:source] = source
15
+ end
16
+
17
+ if context[:tags].is_a?(Hash)
18
+ context = context.dup
19
+ tags.merge!(context.delete(:tags))
20
+ end
21
+
22
+ Sentry::Rails.capture_exception(error, level: severity, contexts: { "rails.error" => context }, tags: tags)
8
23
  end
9
24
  end
10
25
  end
@@ -53,6 +53,13 @@ module Sentry
53
53
  runner do
54
54
  next unless Sentry.initialized?
55
55
  Sentry.configuration.background_worker_threads = 0
56
+
57
+ at_exit do
58
+ # TODO: Add a condition for Rails 7.1 to avoid confliction with https://github.com/rails/rails/pull/44999
59
+ if $ERROR_INFO && !($ERROR_INFO.is_a?(SystemExit) && $ERROR_INFO.success?)
60
+ Sentry::Rails.capture_exception($ERROR_INFO, tags: { source: "runner" })
61
+ end
62
+ end
56
63
  end
57
64
 
58
65
  def configure_project_root
@@ -110,7 +117,7 @@ module Sentry
110
117
  end
111
118
 
112
119
  def activate_tracing
113
- if Sentry.configuration.tracing_enabled?
120
+ if Sentry.configuration.tracing_enabled? && Sentry.configuration.instrumenter == :sentry
114
121
  subscribers = Sentry.configuration.rails.tracing_subscribers
115
122
  Sentry::Rails::Tracing.register_subscribers(subscribers)
116
123
  Sentry::Rails::Tracing.subscribe_tracing_events
@@ -8,14 +8,20 @@ module Sentry
8
8
  extend InstrumentPayloadCleanupHelper
9
9
 
10
10
  EVENT_NAMES = ["process_action.action_controller"].freeze
11
+ OP_NAME = "view.process_action.action_controller".freeze
11
12
 
12
13
  def self.subscribe!
14
+ Sentry.logger.warn <<~MSG
15
+ DEPRECATION WARNING: sentry-rails has changed its approach on controller span recording and #{self.name} is now depreacted.
16
+ Please stop using or referencing #{self.name} as it will be removed in the next major release.
17
+ MSG
18
+
13
19
  subscribe_to_event(EVENT_NAMES) do |event_name, duration, payload|
14
20
  controller = payload[:controller]
15
21
  action = payload[:action]
16
22
 
17
23
  record_on_current_span(
18
- op: event_name,
24
+ op: OP_NAME,
19
25
  start_timestamp: payload[START_TIMESTAMP_NAME],
20
26
  description: "#{controller}##{action}",
21
27
  duration: duration
@@ -14,6 +14,7 @@ module Sentry
14
14
 
15
15
  record_on_current_span(op: SPAN_PREFIX + event_name, start_timestamp: payload[START_TIMESTAMP_NAME], description: payload[:sql], duration: duration) do |span|
16
16
  span.set_data(:connection_id, payload[:connection_id])
17
+ span.set_tag(:cached, true) if payload.fetch(:cached, false) # cached key is only set for hits in the QueryCache, from Rails 5.1
17
18
  end
18
19
  end
19
20
  end
@@ -21,7 +21,7 @@ module Sentry
21
21
 
22
22
  def self.subscribe!
23
23
  subscribe_to_event(EVENT_NAMES) do |event_name, duration, payload|
24
- record_on_current_span(op: event_name, start_timestamp: payload[START_TIMESTAMP_NAME], description: payload[:service], duration: duration) do |span|
24
+ record_on_current_span(op: "file.#{event_name}".freeze, start_timestamp: payload[START_TIMESTAMP_NAME], description: payload[:service], duration: duration) do |span|
25
25
  payload.each do |key, value|
26
26
  span.set_data(key, value) unless key == START_TIMESTAMP_NAME
27
27
  end
@@ -67,7 +67,7 @@ module Sentry
67
67
  end
68
68
 
69
69
  def self.get_current_transaction
70
- Sentry.get_current_scope.get_transaction
70
+ Sentry.get_current_scope.get_transaction if Sentry.initialized?
71
71
  end
72
72
 
73
73
  # it's just a container for the extended method
@@ -1,5 +1,5 @@
1
1
  module Sentry
2
2
  module Rails
3
- VERSION = "5.3.0"
3
+ VERSION = "5.8.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", "~> 5.3.0"
26
+ spec.add_dependency "sentry-ruby", "~> 5.8.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: 5.3.0
4
+ version: 5.8.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: 2022-04-27 00:00:00.000000000 Z
11
+ date: 2023-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '5.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: sentry-ruby-core
28
+ name: sentry-ruby
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 5.3.0
33
+ version: 5.8.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: 5.3.0
40
+ version: 5.8.0
41
41
  description: A gem that provides Rails integration for the Sentry error logger
42
42
  email: accounts@sentry.io
43
43
  executables: []