sentry-ruby 5.5.0 → 5.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/Gemfile +14 -5
- data/README.md +3 -0
- data/Rakefile +8 -1
- data/lib/sentry/backtrace.rb +1 -1
- data/lib/sentry/baggage.rb +1 -12
- data/lib/sentry/client.rb +14 -1
- data/lib/sentry/configuration.rb +128 -26
- data/lib/sentry/envelope.rb +1 -4
- data/lib/sentry/hub.rb +31 -3
- data/lib/sentry/interfaces/request.rb +2 -14
- data/lib/sentry/interfaces/single_exception.rb +9 -1
- data/lib/sentry/net/http.rb +20 -37
- data/lib/sentry/profiler.rb +222 -0
- data/lib/sentry/puma.rb +25 -0
- data/lib/sentry/rack/capture_exceptions.rb +1 -1
- data/lib/sentry/redis.rb +36 -23
- data/lib/sentry/scope.rb +26 -3
- data/lib/sentry/span.rb +14 -11
- data/lib/sentry/test_helper.rb +1 -1
- data/lib/sentry/transaction.rb +73 -15
- data/lib/sentry/transaction_event.rb +36 -0
- data/lib/sentry/transport.rb +7 -0
- data/lib/sentry/utils/argument_checking_helper.rb +3 -3
- data/lib/sentry/utils/encoding_helper.rb +22 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +35 -20
- metadata +5 -3
- 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: 2373a9b8990fd62763c4d1b26001f953f95efdd8b51f803e5d59bdb1ba984e3e
|
4
|
+
data.tar.gz: d09371eb4bf3aaff6e7735f74cd5887b2e99f636a60f1dca3cf653bbb8ba9bb4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4799b727ddaab0622be00e73b58a2e3f723779e1b46c7d5007d5711a8897022190ff9f87cc90df7411f32fd6b59d4f4637bcf26cc7eba8484cb04429871e9242
|
7
|
+
data.tar.gz: d97d9272ee815447ebdcbb72adb4e2255584475547e7878ed6c7af4f312d170bd37f3029acaaa6866eb04f2d89c1581c4854b849c2d57a1a51eb4b67e4ebeb0e
|
data/.rspec
CHANGED
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
|
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",
|
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 :
|
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]
|
data/lib/sentry/backtrace.rb
CHANGED
data/lib/sentry/baggage.rb
CHANGED
@@ -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
|
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?
|
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
|
data/lib/sentry/configuration.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
241
|
-
|
242
|
-
|
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.
|
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
|
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
|
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
|
-
|
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
|
data/lib/sentry/envelope.rb
CHANGED
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
|
-
|
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
|
-
|
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
|
data/lib/sentry/net/http.rb
CHANGED
@@ -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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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[:
|
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
|
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)
|