sentry-ruby 5.5.0 → 5.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ad98e145a972608f9b15a669f771074f1fac592b8819fe1e1e2ac70c6b919a0
4
- data.tar.gz: 5058a18d24be77f5879c4455ab0a437010ad526cb5fa0ec869161c7fa5174d4f
3
+ metadata.gz: 2373a9b8990fd62763c4d1b26001f953f95efdd8b51f803e5d59bdb1ba984e3e
4
+ data.tar.gz: d09371eb4bf3aaff6e7735f74cd5887b2e99f636a60f1dca3cf653bbb8ba9bb4
5
5
  SHA512:
6
- metadata.gz: 69c776cddf21fb89754a1750632f2dc3a28d3dc4cd5e20a0c2a175985533b2f1d6774b4196c3437186776b2e60683356b141675606762338bfbb4e4d2fc9f764
7
- data.tar.gz: 3684c877d6370e5f72fb09151e5f01803661e177dfdce326b789e26ed59c06671bde2db641957f6bdc423f576cfe9e97657d5ac7e8fb81a61e8760ac31039ab8
6
+ metadata.gz: 4799b727ddaab0622be00e73b58a2e3f723779e1b46c7d5007d5711a8897022190ff9f87cc90df7411f32fd6b59d4f4637bcf26cc7eba8484cb04429871e9242
7
+ data.tar.gz: d97d9272ee815447ebdcbb72adb4e2255584475547e7878ed6c7af4f312d170bd37f3029acaaa6866eb04f2d89c1581c4854b849c2d57a1a51eb4b67e4ebeb0e
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
1
  --format documentation
2
2
  --color
3
- --require spec_helper
data/Gemfile CHANGED
@@ -7,17 +7,25 @@ rack_version = ENV["RACK_VERSION"]
7
7
  rack_version = "3.0.0" if rack_version.nil?
8
8
  gem "rack", "~> #{Gem::Version.new(rack_version)}" unless rack_version == "0"
9
9
 
10
+ redis_rb_version = ENV.fetch("REDIS_RB_VERSION", "5.0")
11
+ gem "redis", "~> #{redis_rb_version}"
12
+
13
+ gem "puma"
14
+
10
15
  gem "rake", "~> 12.0"
11
16
  gem "rspec", "~> 3.0"
12
17
  gem "rspec-retry"
13
- gem "fakeredis"
14
18
  gem "timecop"
15
- gem 'simplecov'
19
+ gem "simplecov"
16
20
  gem "simplecov-cobertura", "~> 1.4"
17
21
  gem "rexml"
22
+ gem "stackprof" unless RUBY_PLATFORM == "java"
23
+
24
+ if RUBY_VERSION.to_f >= 2.6
25
+ gem "debug", github: "ruby/debug", platform: :ruby
26
+ gem "irb"
27
+ end
18
28
 
19
- gem "object_tracer"
20
- gem "debug", github: "ruby/debug", platform: :ruby if RUBY_VERSION.to_f >= 2.6
21
29
  gem "pry"
22
30
 
23
31
  gem "benchmark-ips"
@@ -25,4 +33,5 @@ gem "benchmark_driver"
25
33
  gem "benchmark-ipsa"
26
34
  gem "benchmark-memory"
27
35
 
28
- gem "yard", "~> 0.9.27"
36
+ gem "yard", github: "lsegal/yard"
37
+ gem "webrick"
data/README.md CHANGED
@@ -20,6 +20,7 @@ Sentry SDK for Ruby
20
20
  | [![Gem Version](https://img.shields.io/gem/v/sentry-sidekiq?label=sentry-sidekiq)](https://rubygems.org/gems/sentry-sidekiq) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-sidekiq%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq/) |
21
21
  | [![Gem Version](https://img.shields.io/gem/v/sentry-delayed_job?label=sentry-delayed_job)](https://rubygems.org/gems/sentry-delayed_job) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-delayed_job%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-delayed_job.svg)](https://rubygems.org/gems/sentry-delayed_job/) |
22
22
  | [![Gem Version](https://img.shields.io/gem/v/sentry-resque?label=sentry-resque)](https://rubygems.org/gems/sentry-resque) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-resque%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-resque.svg)](https://rubygems.org/gems/sentry-resque/) |
23
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-opentelemetry?label=sentry-opentelemetry)](https://rubygems.org/gems/sentry-opentelemetry) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-opentelemetry%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_opentelemetry_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-opentelemetry.svg)](https://rubygems.org/gems/sentry-opentelemetry/) |
23
24
 
24
25
 
25
26
 
@@ -51,6 +52,7 @@ gem "sentry-rails"
51
52
  gem "sentry-sidekiq"
52
53
  gem "sentry-delayed_job"
53
54
  gem "sentry-resque"
55
+ gem "sentry-opentelemetry"
54
56
  ```
55
57
 
56
58
  ### Configuration
@@ -88,6 +90,7 @@ To learn more about sampling transactions, please visit the [official documentat
88
90
  - [Sidekiq](https://docs.sentry.io/platforms/ruby/guides/sidekiq/)
89
91
  - [DelayedJob](https://docs.sentry.io/platforms/ruby/guides/delayed_job/)
90
92
  - [Resque](https://docs.sentry.io/platforms/ruby/guides/resque/)
93
+ - [OpenTemeletry](https://docs.sentry.io/platforms/ruby/performance/instrumentation/opentelemetry/)
91
94
 
92
95
  ### Enriching Events
93
96
 
data/Rakefile CHANGED
@@ -8,6 +8,13 @@ require "rspec/core/rake_task"
8
8
 
9
9
  RSpec::Core::RakeTask.new(:spec).tap do |task|
10
10
  task.rspec_opts = "--order rand"
11
+ task.exclude_pattern = "spec/isolated/**/*_spec.rb"
11
12
  end
12
13
 
13
- task :default => :spec
14
+ task :isolated_specs do
15
+ Dir["spec/isolated/*"].each do |file|
16
+ sh "bundle exec rspec #{file}"
17
+ end
18
+ end
19
+
20
+ task :default => [:spec, :isolated_specs]
@@ -76,7 +76,7 @@ module Sentry
76
76
  end
77
77
  end
78
78
 
79
- APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test)/.freeze
79
+ APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/.freeze
80
80
 
81
81
  # holder for an Array of Backtrace::Line instances
82
82
  attr_reader :lines
@@ -8,17 +8,6 @@ module Sentry
8
8
  SENTRY_PREFIX = 'sentry-'
9
9
  SENTRY_PREFIX_REGEX = /^sentry-/.freeze
10
10
 
11
- DSC_KEYS = %w(
12
- trace_id
13
- public_key
14
- sample_rate
15
- release
16
- environment
17
- transaction
18
- user_id
19
- user_segment
20
- ).freeze
21
-
22
11
  # @return [Hash]
23
12
  attr_reader :items
24
13
 
@@ -68,7 +57,7 @@ module Sentry
68
57
  # hash to be used in the trace envelope header.
69
58
  # @return [Hash]
70
59
  def dynamic_sampling_context
71
- @items.select { |k, _v| DSC_KEYS.include?(k) }
60
+ @items
72
61
  end
73
62
 
74
63
  # Serialize the Baggage object back to a string.
data/lib/sentry/client.rb CHANGED
@@ -76,7 +76,10 @@ module Sentry
76
76
  # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
77
77
  # @return [Event, nil]
78
78
  def event_from_exception(exception, hint = {})
79
- return unless @configuration.sending_allowed? && @configuration.exception_class_allowed?(exception)
79
+ return unless @configuration.sending_allowed?
80
+
81
+ ignore_exclusions = hint.delete(:ignore_exclusions) { false }
82
+ return if !ignore_exclusions && !@configuration.exception_class_allowed?(exception)
80
83
 
81
84
  integration_meta = Sentry.integrations[hint[:integration]]
82
85
 
@@ -122,6 +125,16 @@ module Sentry
122
125
  end
123
126
  end
124
127
 
128
+ if event_type == TransactionEvent::TYPE && configuration.before_send_transaction
129
+ event = configuration.before_send_transaction.call(event, hint)
130
+
131
+ if event.nil?
132
+ log_info("Discarded event because before_send_transaction returned nil")
133
+ transport.record_lost_event(:before_send, 'transaction')
134
+ return
135
+ end
136
+ end
137
+
125
138
  transport.send_event(event)
126
139
 
127
140
  event
@@ -14,6 +14,8 @@ module Sentry
14
14
  class Configuration
15
15
  include CustomInspection
16
16
  include LoggingHelper
17
+ include ArgumentCheckingHelper
18
+
17
19
  # Directories to be recognized as part of your app. e.g. if you
18
20
  # have an `engines` dir at the root of your project, you may want
19
21
  # to set this to something like /(app|config|engines|lib)/
@@ -72,6 +74,19 @@ module Sentry
72
74
  # @return [Proc]
73
75
  attr_reader :before_send
74
76
 
77
+ # Optional Proc, called before sending an event to the server
78
+ # @example
79
+ # config.before_send_transaction = lambda do |event, hint|
80
+ # # skip unimportant transactions or strip sensitive data
81
+ # if event.transaction == "/healthcheck/route"
82
+ # nil
83
+ # else
84
+ # event
85
+ # end
86
+ # end
87
+ # @return [Proc]
88
+ attr_reader :before_send_transaction
89
+
75
90
  # An array of breadcrumbs loggers to be used. Available options are:
76
91
  # - :sentry_logger
77
92
  # - :http_logger
@@ -84,10 +99,6 @@ module Sentry
84
99
  # @return [Array<Symbol>]
85
100
  attr_reader :breadcrumbs_logger
86
101
 
87
- # Whether to capture local variables from the raised exception's frame. Default is false.
88
- # @return [Boolean]
89
- attr_accessor :capture_exception_frame_locals
90
-
91
102
  # Max number of breadcrumbs a breadcrumb buffer can hold
92
103
  # @return [Integer]
93
104
  attr_accessor :max_breadcrumbs
@@ -127,6 +138,22 @@ module Sentry
127
138
  attr_accessor :inspect_exception_causes_for_exclusion
128
139
  alias inspect_exception_causes_for_exclusion? inspect_exception_causes_for_exclusion
129
140
 
141
+ # Whether to capture local variables from the raised exception's frame. Default is false.
142
+ # @return [Boolean]
143
+ attr_accessor :include_local_variables
144
+
145
+ # @deprecated Use {#include_local_variables} instead.
146
+ alias_method :capture_exception_frame_locals, :include_local_variables
147
+
148
+ # @deprecated Use {#include_local_variables=} instead.
149
+ def capture_exception_frame_locals=(value)
150
+ log_warn <<~MSG
151
+ `capture_exception_frame_locals` is now deprecated in favor of `include_local_variables`.
152
+ MSG
153
+
154
+ self.include_local_variables = value
155
+ end
156
+
130
157
  # You may provide your own LineCache for matching paths with source files.
131
158
  # This may be useful if you need to get source code from places other than the disk.
132
159
  # @see LineCache
@@ -154,7 +181,7 @@ module Sentry
154
181
  # Release tag to be passed with every event sent to Sentry.
155
182
  # We automatically try to set this to a git SHA or Capistrano release.
156
183
  # @return [String]
157
- attr_accessor :release
184
+ attr_reader :release
158
185
 
159
186
  # The sampling factor to apply to events. A value of 0.0 will not send
160
187
  # any events, and a value of 1.0 will send 100% of events.
@@ -189,8 +216,8 @@ module Sentry
189
216
  attr_reader :transport
190
217
 
191
218
  # Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
192
- # @return [Float]
193
- attr_accessor :traces_sample_rate
219
+ # @return [Float, nil]
220
+ attr_reader :traces_sample_rate
194
221
 
195
222
  # Take a Proc that controls the sample rate for every tracing event, e.g.
196
223
  # @example
@@ -202,6 +229,11 @@ module Sentry
202
229
  # @return [Proc]
203
230
  attr_accessor :traces_sampler
204
231
 
232
+ # Easier way to use performance tracing
233
+ # If set to true, will set traces_sample_rate to 1.0
234
+ # @return [Boolean, nil]
235
+ attr_reader :enable_tracing
236
+
205
237
  # Send diagnostic client reports about dropped events, true by default
206
238
  # tries to attach to an existing envelope max once every 30s
207
239
  # @return [Boolean]
@@ -211,10 +243,29 @@ module Sentry
211
243
  # @return [Boolean]
212
244
  attr_accessor :auto_session_tracking
213
245
 
246
+ # The instrumenter to use, :sentry or :otel
247
+ # @return [Symbol]
248
+ attr_reader :instrumenter
249
+
250
+ # Take a float between 0.0 and 1.0 as the sample rate for capturing profiles.
251
+ # Note that this rate is relative to traces_sample_rate / traces_sampler,
252
+ # i.e. the profile is sampled by this rate after the transaction is sampled.
253
+ # @return [Float, nil]
254
+ attr_reader :profiles_sample_rate
255
+
214
256
  # these are not config options
215
257
  # @!visibility private
216
258
  attr_reader :errors, :gem_specs
217
259
 
260
+ # These exceptions could enter Puma's `lowlevel_error_handler` callback and the SDK's Puma integration
261
+ # But they are mostly considered as noise and should be ignored by default
262
+ # Please see https://github.com/getsentry/sentry-ruby/pull/2026 for more information
263
+ PUMA_IGNORE_DEFAULT = [
264
+ 'Puma::MiniSSL::SSLError',
265
+ 'Puma::HttpParserError',
266
+ 'Puma::HttpParserError501'
267
+ ].freeze
268
+
218
269
  # Most of these errors generate 4XX responses. In general, Sentry clients
219
270
  # only automatically report 5xx responses.
220
271
  IGNORE_DEFAULT = [
@@ -237,9 +288,20 @@ module Sentry
237
288
  MODULE_SEPARATOR = "::".freeze
238
289
  SKIP_INSPECTION_ATTRIBUTES = [:@linecache, :@stacktrace_builder]
239
290
 
240
- # Post initialization callbacks are called at the end of initialization process
241
- # allowing extending the configuration of sentry-ruby by multiple extensions
242
- @@post_initialization_callbacks = []
291
+ INSTRUMENTERS = [:sentry, :otel]
292
+
293
+ class << self
294
+ # Post initialization callbacks are called at the end of initialization process
295
+ # allowing extending the configuration of sentry-ruby by multiple extensions
296
+ def post_initialization_callbacks
297
+ @post_initialization_callbacks ||= []
298
+ end
299
+
300
+ # allow extensions to add their hooks to the Configuration class
301
+ def add_post_initialization_callback(&block)
302
+ post_initialization_callbacks << block
303
+ end
304
+ end
243
305
 
244
306
  def initialize
245
307
  self.app_dirs_pattern = nil
@@ -249,11 +311,11 @@ module Sentry
249
311
  self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
250
312
  self.breadcrumbs_logger = []
251
313
  self.context_lines = 3
252
- self.capture_exception_frame_locals = false
314
+ self.include_local_variables = false
253
315
  self.environment = environment_from_env
254
316
  self.enabled_environments = []
255
317
  self.exclude_loggers = []
256
- self.excluded_exceptions = IGNORE_DEFAULT.dup
318
+ self.excluded_exceptions = IGNORE_DEFAULT + PUMA_IGNORE_DEFAULT
257
319
  self.inspect_exception_causes_for_exclusion = true
258
320
  self.linecache = ::Sentry::LineCache.new
259
321
  self.logger = ::Sentry::Logger.new(STDOUT)
@@ -269,11 +331,13 @@ module Sentry
269
331
  self.trusted_proxies = []
270
332
  self.dsn = ENV['SENTRY_DSN']
271
333
  self.server_name = server_name_from_env
334
+ self.instrumenter = :sentry
272
335
 
273
336
  self.before_send = nil
337
+ self.before_send_transaction = nil
274
338
  self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
275
- self.traces_sample_rate = nil
276
339
  self.traces_sampler = nil
340
+ self.enable_tracing = nil
277
341
 
278
342
  @transport = Transport::Configuration.new
279
343
  @gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
@@ -287,6 +351,12 @@ module Sentry
287
351
 
288
352
  alias server= dsn=
289
353
 
354
+ def release=(value)
355
+ check_argument_type!(value, String, NilClass)
356
+
357
+ @release = value
358
+ end
359
+
290
360
  def async=(value)
291
361
  check_callable!("async", value)
292
362
 
@@ -322,6 +392,12 @@ module Sentry
322
392
  @before_send = value
323
393
  end
324
394
 
395
+ def before_send_transaction=(value)
396
+ check_callable!("before_send_transaction", value)
397
+
398
+ @before_send_transaction = value
399
+ end
400
+
325
401
  def before_breadcrumb=(value)
326
402
  check_callable!("before_breadcrumb", value)
327
403
 
@@ -332,6 +408,30 @@ module Sentry
332
408
  @environment = environment.to_s
333
409
  end
334
410
 
411
+ def instrumenter=(instrumenter)
412
+ @instrumenter = INSTRUMENTERS.include?(instrumenter) ? instrumenter : :sentry
413
+ end
414
+
415
+ def enable_tracing=(enable_tracing)
416
+ @enable_tracing = enable_tracing
417
+ @traces_sample_rate ||= 1.0 if enable_tracing
418
+ end
419
+
420
+ def is_numeric_or_nil?(value)
421
+ value.is_a?(Numeric) || value.nil?
422
+ end
423
+
424
+ def traces_sample_rate=(traces_sample_rate)
425
+ raise ArgumentError, "traces_sample_rate must be a Numeric or nil" unless is_numeric_or_nil?(traces_sample_rate)
426
+ @traces_sample_rate = traces_sample_rate
427
+ end
428
+
429
+ def profiles_sample_rate=(profiles_sample_rate)
430
+ raise ArgumentError, "profiles_sample_rate must be a Numeric or nil" unless is_numeric_or_nil?(profiles_sample_rate)
431
+ log_info("Please make sure to include the 'stackprof' gem in your Gemfile to use Profiling with Sentry.") unless defined?(StackProf)
432
+ @profiles_sample_rate = profiles_sample_rate
433
+ end
434
+
335
435
  def sending_allowed?
336
436
  @errors = []
337
437
 
@@ -361,8 +461,21 @@ module Sentry
361
461
  enabled_environments.empty? || enabled_environments.include?(environment)
362
462
  end
363
463
 
464
+ def valid_sample_rate?(sample_rate)
465
+ return false unless sample_rate.is_a?(Numeric)
466
+ sample_rate >= 0.0 && sample_rate <= 1.0
467
+ end
468
+
364
469
  def tracing_enabled?
365
- !!((@traces_sample_rate && @traces_sample_rate >= 0.0 && @traces_sample_rate <= 1.0) || @traces_sampler) && sending_allowed?
470
+ valid_sampler = !!((valid_sample_rate?(@traces_sample_rate)) || @traces_sampler)
471
+
472
+ (@enable_tracing != false) && valid_sampler && sending_allowed?
473
+ end
474
+
475
+ def profiling_enabled?
476
+ valid_sampler = !!(valid_sample_rate?(@profiles_sample_rate))
477
+
478
+ tracing_enabled? && valid_sampler && sending_allowed?
366
479
  end
367
480
 
368
481
  # @return [String, nil]
@@ -390,7 +503,7 @@ module Sentry
390
503
  def detect_release
391
504
  return unless sending_allowed?
392
505
 
393
- self.release ||= ReleaseDetector.detect_release(project_root: project_root, running_on_heroku: running_on_heroku?)
506
+ @release ||= ReleaseDetector.detect_release(project_root: project_root, running_on_heroku: running_on_heroku?)
394
507
 
395
508
  if running_on_heroku? && release.nil?
396
509
  log_warn(HEROKU_DYNO_METADATA_MESSAGE)
@@ -487,16 +600,5 @@ module Sentry
487
600
  instance_eval(&hook)
488
601
  end
489
602
  end
490
-
491
- # allow extensions to add their hooks to the Configuration class
492
- def self.add_post_initialization_callback(&block)
493
- self.post_initialization_callbacks << block
494
- end
495
-
496
- protected
497
-
498
- def self.post_initialization_callbacks
499
- @@post_initialization_callbacks
500
- end
501
603
  end
502
604
  end
@@ -19,10 +19,7 @@ module Sentry
19
19
  end
20
20
 
21
21
  def to_s
22
- <<~ITEM
23
- #{JSON.generate(@headers)}
24
- #{JSON.generate(@payload)}
25
- ITEM
22
+ [JSON.generate(@headers), JSON.generate(@payload)].join("\n")
26
23
  end
27
24
 
28
25
  def serialize
data/lib/sentry/hub.rb CHANGED
@@ -76,8 +76,9 @@ module Sentry
76
76
  @stack.pop
77
77
  end
78
78
 
79
- def start_transaction(transaction: nil, custom_sampling_context: {}, **options)
79
+ def start_transaction(transaction: nil, custom_sampling_context: {}, instrumenter: :sentry, **options)
80
80
  return unless configuration.tracing_enabled?
81
+ return unless instrumenter == configuration.instrumenter
81
82
 
82
83
  transaction ||= Transaction.new(**options.merge(hub: self))
83
84
 
@@ -87,13 +88,39 @@ module Sentry
87
88
  }
88
89
 
89
90
  sampling_context.merge!(custom_sampling_context)
90
-
91
91
  transaction.set_initial_sample_decision(sampling_context: sampling_context)
92
+
93
+ transaction.start_profiler!
94
+
92
95
  transaction
93
96
  end
94
97
 
98
+ def with_child_span(instrumenter: :sentry, **attributes, &block)
99
+ return yield(nil) unless instrumenter == configuration.instrumenter
100
+
101
+ current_span = current_scope.get_span
102
+ return yield(nil) unless current_span
103
+
104
+ result = nil
105
+
106
+ begin
107
+ current_span.with_child_span(**attributes) do |child_span|
108
+ current_scope.set_span(child_span)
109
+ result = yield(child_span)
110
+ end
111
+ ensure
112
+ current_scope.set_span(current_span)
113
+ end
114
+
115
+ result
116
+ end
117
+
95
118
  def capture_exception(exception, **options, &block)
96
- check_argument_type!(exception, ::Exception)
119
+ if RUBY_PLATFORM == "java"
120
+ check_argument_type!(exception, ::Exception, ::Java::JavaLang::Throwable)
121
+ else
122
+ check_argument_type!(exception, ::Exception)
123
+ end
97
124
 
98
125
  return if Sentry.exception_captured?(exception)
99
126
 
@@ -101,6 +128,7 @@ module Sentry
101
128
 
102
129
  options[:hint] ||= {}
103
130
  options[:hint][:exception] = exception
131
+
104
132
  event = current_client.event_from_exception(exception, options[:hint])
105
133
 
106
134
  return unless event
@@ -73,7 +73,7 @@ module Sentry
73
73
  request.POST
74
74
  elsif request.body # JSON requests, etc
75
75
  data = request.body.read(MAX_BODY_LIMIT)
76
- data = encode_to_utf_8(data.to_s)
76
+ data = Utils::EncodingHelper.encode_to_utf_8(data.to_s)
77
77
  request.body.rewind
78
78
  data
79
79
  end
@@ -94,7 +94,7 @@ module Sentry
94
94
  key = key.sub(/^HTTP_/, "")
95
95
  key = key.split('_').map(&:capitalize).join('-')
96
96
 
97
- memo[key] = encode_to_utf_8(value.to_s)
97
+ memo[key] = Utils::EncodingHelper.encode_to_utf_8(value.to_s)
98
98
  rescue StandardError => e
99
99
  # Rails adds objects to the Rack env that can sometimes raise exceptions
100
100
  # when `to_s` is called.
@@ -105,18 +105,6 @@ module Sentry
105
105
  end
106
106
  end
107
107
 
108
- def encode_to_utf_8(value)
109
- if value.encoding != Encoding::UTF_8 && value.respond_to?(:force_encoding)
110
- value = value.dup.force_encoding(Encoding::UTF_8)
111
- end
112
-
113
- if !value.valid_encoding?
114
- value = value.scrub
115
- end
116
-
117
- value
118
- end
119
-
120
108
  def is_skippable_header?(key)
121
109
  key.upcase != key || # lower-case envs aren't real http headers
122
110
  key == "HTTP_COOKIE" || # Cookies don't go here, they go somewhere else
@@ -15,7 +15,15 @@ module Sentry
15
15
 
16
16
  def initialize(exception:, stacktrace: nil)
17
17
  @type = exception.class.to_s
18
- @value = (exception.message || "").byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES)
18
+ exception_message =
19
+ if exception.respond_to?(:detailed_message)
20
+ exception.detailed_message(highlight: false)
21
+ else
22
+ exception.message || ""
23
+ end
24
+
25
+ @value = exception_message.byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES)
26
+
19
27
  @module = exception.class.to_s.split('::')[0...-1].join('::')
20
28
  @thread_id = Thread.current.object_id
21
29
  @stacktrace = stacktrace
@@ -26,14 +26,24 @@ module Sentry
26
26
  #
27
27
  # So we're only instrumenting request when `Net::HTTP` is already started
28
28
  def request(req, body = nil, &block)
29
- return super unless started?
30
-
31
- sentry_span = start_sentry_span
32
- set_sentry_trace_header(req, sentry_span)
33
-
34
- super.tap do |res|
35
- record_sentry_breadcrumb(req, res)
36
- record_sentry_span(req, res, sentry_span)
29
+ return super unless started? && Sentry.initialized?
30
+ return super if from_sentry_sdk?
31
+
32
+ Sentry.with_child_span(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f) do |sentry_span|
33
+ set_sentry_trace_header(req, sentry_span)
34
+
35
+ super.tap do |res|
36
+ record_sentry_breadcrumb(req, res)
37
+
38
+ if sentry_span
39
+ request_info = extract_request_info(req)
40
+ sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
41
+ sentry_span.set_data('url', request_info[:url])
42
+ sentry_span.set_data('http.method', request_info[:method])
43
+ sentry_span.set_data('http.query', request_info[:query]) if request_info[:query]
44
+ sentry_span.set_data('status', res.code.to_i)
45
+ end
46
+ end
37
47
  end
38
48
  end
39
49
 
@@ -53,7 +63,6 @@ module Sentry
53
63
 
54
64
  def record_sentry_breadcrumb(req, res)
55
65
  return unless Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
56
- return if from_sentry_sdk?
57
66
 
58
67
  request_info = extract_request_info(req)
59
68
 
@@ -69,29 +78,6 @@ module Sentry
69
78
  Sentry.add_breadcrumb(crumb)
70
79
  end
71
80
 
72
- def record_sentry_span(req, res, sentry_span)
73
- return unless Sentry.initialized? && sentry_span
74
-
75
- request_info = extract_request_info(req)
76
- sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
77
- sentry_span.set_data(:status, res.code.to_i)
78
- finish_sentry_span(sentry_span)
79
- end
80
-
81
- def start_sentry_span
82
- return unless Sentry.initialized? && span = Sentry.get_current_scope.get_span
83
- return if from_sentry_sdk?
84
- return if span.sampled == false
85
-
86
- span.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
87
- end
88
-
89
- def finish_sentry_span(sentry_span)
90
- return unless Sentry.initialized? && sentry_span
91
-
92
- sentry_span.set_timestamp(Sentry.utc_now.to_f)
93
- end
94
-
95
81
  def from_sentry_sdk?
96
82
  dsn = Sentry.configuration.dsn
97
83
  dsn && dsn.host == self.address
@@ -104,7 +90,7 @@ module Sentry
104
90
  result = { method: req.method, url: url }
105
91
 
106
92
  if Sentry.configuration.send_default_pii
107
- result[:url] = result[:url] + "?#{uri.query}"
93
+ result[:query] = uri.query
108
94
  result[:body] = req.body
109
95
  end
110
96
 
@@ -114,7 +100,4 @@ module Sentry
114
100
  end
115
101
  end
116
102
 
117
- Sentry.register_patch do
118
- patch = Sentry::Net::HTTP
119
- Net::HTTP.send(:prepend, patch) unless Net::HTTP.ancestors.include?(patch)
120
- end
103
+ Sentry.register_patch(Sentry::Net::HTTP, Net::HTTP)