sentry-ruby 5.4.2 → 5.9.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/.rspec +0 -1
- data/Gemfile +12 -5
- data/README.md +3 -0
- data/Rakefile +8 -1
- data/lib/sentry/backtrace.rb +1 -1
- data/lib/sentry/baggage.rb +70 -0
- data/lib/sentry/client.rb +31 -11
- data/lib/sentry/configuration.rb +96 -20
- data/lib/sentry/envelope.rb +1 -4
- data/lib/sentry/event.rb +1 -1
- data/lib/sentry/hub.rb +26 -2
- data/lib/sentry/interfaces/request.rb +6 -16
- data/lib/sentry/interfaces/single_exception.rb +9 -1
- data/lib/sentry/net/http.rb +20 -35
- data/lib/sentry/profiler.rb +222 -0
- data/lib/sentry/puma.rb +25 -0
- data/lib/sentry/rack/capture_exceptions.rb +6 -4
- data/lib/sentry/rake.rb +1 -1
- data/lib/sentry/redis.rb +35 -23
- data/lib/sentry/scope.rb +55 -6
- data/lib/sentry/session.rb +5 -7
- data/lib/sentry/span.rb +19 -9
- data/lib/sentry/test_helper.rb +3 -1
- data/lib/sentry/transaction.rb +173 -19
- data/lib/sentry/transaction_event.rb +54 -0
- data/lib/sentry/transport.rb +19 -8
- data/lib/sentry/utils/encoding_helper.rb +22 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +38 -21
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a114a391fe058601b40369376152bee8ba9b1b96ab94710344283cfe1a4490b
|
4
|
+
data.tar.gz: 7a17648c7a5d06f22d2d643f6ff1cb25d3fed2348609e372fc5762043ebd538a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dab19469a8e68201380e2be405332bb7c8caef7bf46fd4dae70f4dc3beaac2902ce51b2b2c902b39ca048e1bc5ff47f85b1e7d3a824b5f20ff002dcbdca2c354
|
7
|
+
data.tar.gz: 6bf0cba7b42dd9bfd5078e4353ad7f92d932b959a87c748cb30e505ffd8d205899c819ea4f72e5f3099f0b861139864062b870219678abdeda0a0629604963d3
|
data/.rspec
CHANGED
data/Gemfile
CHANGED
@@ -3,17 +3,23 @@ git_source(:github) { |name| "https://github.com/#{name}.git" }
|
|
3
3
|
|
4
4
|
gem "sentry-ruby", path: "./"
|
5
5
|
|
6
|
-
|
6
|
+
rack_version = ENV["RACK_VERSION"]
|
7
|
+
rack_version = "3.0.0" if rack_version.nil?
|
8
|
+
gem "rack", "~> #{Gem::Version.new(rack_version)}" unless rack_version == "0"
|
9
|
+
|
10
|
+
redis_rb_version = ENV.fetch("REDIS_RB_VERSION", "5.0")
|
11
|
+
gem "redis", "~> #{redis_rb_version}"
|
12
|
+
|
13
|
+
gem "puma"
|
7
14
|
|
8
15
|
gem "rake", "~> 12.0"
|
9
16
|
gem "rspec", "~> 3.0"
|
10
17
|
gem "rspec-retry"
|
11
|
-
gem "webmock"
|
12
|
-
gem "fakeredis"
|
13
18
|
gem "timecop"
|
14
|
-
gem
|
19
|
+
gem "simplecov"
|
15
20
|
gem "simplecov-cobertura", "~> 1.4"
|
16
21
|
gem "rexml"
|
22
|
+
gem "stackprof" unless RUBY_PLATFORM == "java"
|
17
23
|
|
18
24
|
gem "object_tracer"
|
19
25
|
gem "debug", github: "ruby/debug", platform: :ruby if RUBY_VERSION.to_f >= 2.6
|
@@ -24,4 +30,5 @@ gem "benchmark_driver"
|
|
24
30
|
gem "benchmark-ipsa"
|
25
31
|
gem "benchmark-memory"
|
26
32
|
|
27
|
-
gem "yard",
|
33
|
+
gem "yard", github: "lsegal/yard"
|
34
|
+
gem "webrick"
|
data/README.md
CHANGED
@@ -20,6 +20,7 @@ Sentry SDK for Ruby
|
|
20
20
|
| [](https://rubygems.org/gems/sentry-sidekiq) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-sidekiq/) |
|
21
21
|
| [](https://rubygems.org/gems/sentry-delayed_job) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-delayed_job/) |
|
22
22
|
| [](https://rubygems.org/gems/sentry-resque) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-resque/) |
|
23
|
+
| [](https://rubygems.org/gems/sentry-opentelemetry) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_opentelemetry_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](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
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module Sentry
|
6
|
+
# A {https://www.w3.org/TR/baggage W3C Baggage Header} implementation.
|
7
|
+
class Baggage
|
8
|
+
SENTRY_PREFIX = 'sentry-'
|
9
|
+
SENTRY_PREFIX_REGEX = /^sentry-/.freeze
|
10
|
+
|
11
|
+
# @return [Hash]
|
12
|
+
attr_reader :items
|
13
|
+
|
14
|
+
# @return [Boolean]
|
15
|
+
attr_reader :mutable
|
16
|
+
|
17
|
+
def initialize(items, mutable: true)
|
18
|
+
@items = items
|
19
|
+
@mutable = mutable
|
20
|
+
end
|
21
|
+
|
22
|
+
# Creates a Baggage object from an incoming W3C Baggage header string.
|
23
|
+
#
|
24
|
+
# Sentry items are identified with the 'sentry-' prefix and stored in a hash.
|
25
|
+
# The presence of a Sentry item makes the baggage object immutable.
|
26
|
+
#
|
27
|
+
# @param header [String] The incoming Baggage header string.
|
28
|
+
# @return [Baggage, nil]
|
29
|
+
def self.from_incoming_header(header)
|
30
|
+
items = {}
|
31
|
+
mutable = true
|
32
|
+
|
33
|
+
header.split(',').each do |item|
|
34
|
+
item = item.strip
|
35
|
+
key, val = item.split('=')
|
36
|
+
|
37
|
+
next unless key && val
|
38
|
+
next unless key =~ SENTRY_PREFIX_REGEX
|
39
|
+
|
40
|
+
baggage_key = key.split('-')[1]
|
41
|
+
next unless baggage_key
|
42
|
+
|
43
|
+
items[CGI.unescape(baggage_key)] = CGI.unescape(val)
|
44
|
+
mutable = false
|
45
|
+
end
|
46
|
+
|
47
|
+
new(items, mutable: mutable)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Make the Baggage immutable.
|
51
|
+
# @return [void]
|
52
|
+
def freeze!
|
53
|
+
@mutable = false
|
54
|
+
end
|
55
|
+
|
56
|
+
# A {https://develop.sentry.dev/sdk/performance/dynamic-sampling-context/#envelope-header Dynamic Sampling Context}
|
57
|
+
# hash to be used in the trace envelope header.
|
58
|
+
# @return [Hash]
|
59
|
+
def dynamic_sampling_context
|
60
|
+
@items
|
61
|
+
end
|
62
|
+
|
63
|
+
# Serialize the Baggage object back to a string.
|
64
|
+
# @return [String]
|
65
|
+
def serialize
|
66
|
+
items = @items.map { |k, v| "#{SENTRY_PREFIX}#{CGI.escape(k)}=#{CGI.escape(v)}" }
|
67
|
+
items.join(',')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
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
|
|
@@ -105,16 +108,7 @@ module Sentry
|
|
105
108
|
# @param transaction [Transaction] the transaction to be recorded.
|
106
109
|
# @return [TransactionEvent]
|
107
110
|
def event_from_transaction(transaction)
|
108
|
-
TransactionEvent.new(configuration: configuration
|
109
|
-
event.transaction = transaction.name
|
110
|
-
event.contexts.merge!(trace: transaction.get_trace_context)
|
111
|
-
event.timestamp = transaction.timestamp
|
112
|
-
event.start_timestamp = transaction.start_timestamp
|
113
|
-
event.tags = transaction.tags
|
114
|
-
|
115
|
-
finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
|
116
|
-
event.spans = finished_spans.map(&:to_hash)
|
117
|
-
end
|
111
|
+
TransactionEvent.new(configuration: configuration, transaction: transaction)
|
118
112
|
end
|
119
113
|
|
120
114
|
# @!macro send_event
|
@@ -131,6 +125,16 @@ module Sentry
|
|
131
125
|
end
|
132
126
|
end
|
133
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
|
+
|
134
138
|
transport.send_event(event)
|
135
139
|
|
136
140
|
event
|
@@ -156,6 +160,22 @@ module Sentry
|
|
156
160
|
trace
|
157
161
|
end
|
158
162
|
|
163
|
+
# Generates a W3C Baggage header for distribted tracing from the given Span.
|
164
|
+
# Returns `nil` if `config.propagate_traces` is `false`.
|
165
|
+
# @param span [Span] the span to generate trace from.
|
166
|
+
# @return [String, nil]
|
167
|
+
def generate_baggage(span)
|
168
|
+
return unless configuration.propagate_traces
|
169
|
+
|
170
|
+
baggage = span.to_baggage
|
171
|
+
|
172
|
+
if baggage && !baggage.empty?
|
173
|
+
log_debug("[Tracing] Adding #{BAGGAGE_HEADER_NAME} header to outgoing request: #{baggage}")
|
174
|
+
end
|
175
|
+
|
176
|
+
baggage
|
177
|
+
end
|
178
|
+
|
159
179
|
private
|
160
180
|
|
161
181
|
def dispatch_background_event(event, hint)
|
data/lib/sentry/configuration.rb
CHANGED
@@ -72,6 +72,19 @@ module Sentry
|
|
72
72
|
# @return [Proc]
|
73
73
|
attr_reader :before_send
|
74
74
|
|
75
|
+
# Optional Proc, called before sending an event to the server
|
76
|
+
# @example
|
77
|
+
# config.before_send_transaction = lambda do |event, hint|
|
78
|
+
# # skip unimportant transactions or strip sensitive data
|
79
|
+
# if event.transaction == "/healthcheck/route"
|
80
|
+
# nil
|
81
|
+
# else
|
82
|
+
# event
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
# @return [Proc]
|
86
|
+
attr_reader :before_send_transaction
|
87
|
+
|
75
88
|
# An array of breadcrumbs loggers to be used. Available options are:
|
76
89
|
# - :sentry_logger
|
77
90
|
# - :http_logger
|
@@ -84,10 +97,6 @@ module Sentry
|
|
84
97
|
# @return [Array<Symbol>]
|
85
98
|
attr_reader :breadcrumbs_logger
|
86
99
|
|
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
100
|
# Max number of breadcrumbs a breadcrumb buffer can hold
|
92
101
|
# @return [Integer]
|
93
102
|
attr_accessor :max_breadcrumbs
|
@@ -127,6 +136,22 @@ module Sentry
|
|
127
136
|
attr_accessor :inspect_exception_causes_for_exclusion
|
128
137
|
alias inspect_exception_causes_for_exclusion? inspect_exception_causes_for_exclusion
|
129
138
|
|
139
|
+
# Whether to capture local variables from the raised exception's frame. Default is false.
|
140
|
+
# @return [Boolean]
|
141
|
+
attr_accessor :include_local_variables
|
142
|
+
|
143
|
+
# @deprecated Use {#include_local_variables} instead.
|
144
|
+
alias_method :capture_exception_frame_locals, :include_local_variables
|
145
|
+
|
146
|
+
# @deprecated Use {#include_local_variables=} instead.
|
147
|
+
def capture_exception_frame_locals=(value)
|
148
|
+
log_warn <<~MSG
|
149
|
+
`capture_exception_frame_locals` is now deprecated in favor of `include_local_variables`.
|
150
|
+
MSG
|
151
|
+
|
152
|
+
self.include_local_variables = value
|
153
|
+
end
|
154
|
+
|
130
155
|
# You may provide your own LineCache for matching paths with source files.
|
131
156
|
# This may be useful if you need to get source code from places other than the disk.
|
132
157
|
# @see LineCache
|
@@ -202,6 +227,11 @@ module Sentry
|
|
202
227
|
# @return [Proc]
|
203
228
|
attr_accessor :traces_sampler
|
204
229
|
|
230
|
+
# Easier way to use performance tracing
|
231
|
+
# If set to true, will set traces_sample_rate to 1.0
|
232
|
+
# @return [Boolean, nil]
|
233
|
+
attr_reader :enable_tracing
|
234
|
+
|
205
235
|
# Send diagnostic client reports about dropped events, true by default
|
206
236
|
# tries to attach to an existing envelope max once every 30s
|
207
237
|
# @return [Boolean]
|
@@ -211,6 +241,16 @@ module Sentry
|
|
211
241
|
# @return [Boolean]
|
212
242
|
attr_accessor :auto_session_tracking
|
213
243
|
|
244
|
+
# The instrumenter to use, :sentry or :otel
|
245
|
+
# @return [Symbol]
|
246
|
+
attr_reader :instrumenter
|
247
|
+
|
248
|
+
# Take a float between 0.0 and 1.0 as the sample rate for capturing profiles.
|
249
|
+
# Note that this rate is relative to traces_sample_rate / traces_sampler,
|
250
|
+
# i.e. the profile is sampled by this rate after the transaction is sampled.
|
251
|
+
# @return [Float, nil]
|
252
|
+
attr_reader :profiles_sample_rate
|
253
|
+
|
214
254
|
# these are not config options
|
215
255
|
# @!visibility private
|
216
256
|
attr_reader :errors, :gem_specs
|
@@ -237,9 +277,20 @@ module Sentry
|
|
237
277
|
MODULE_SEPARATOR = "::".freeze
|
238
278
|
SKIP_INSPECTION_ATTRIBUTES = [:@linecache, :@stacktrace_builder]
|
239
279
|
|
240
|
-
|
241
|
-
|
242
|
-
|
280
|
+
INSTRUMENTERS = [:sentry, :otel]
|
281
|
+
|
282
|
+
class << self
|
283
|
+
# Post initialization callbacks are called at the end of initialization process
|
284
|
+
# allowing extending the configuration of sentry-ruby by multiple extensions
|
285
|
+
def post_initialization_callbacks
|
286
|
+
@post_initialization_callbacks ||= []
|
287
|
+
end
|
288
|
+
|
289
|
+
# allow extensions to add their hooks to the Configuration class
|
290
|
+
def add_post_initialization_callback(&block)
|
291
|
+
post_initialization_callbacks << block
|
292
|
+
end
|
293
|
+
end
|
243
294
|
|
244
295
|
def initialize
|
245
296
|
self.app_dirs_pattern = nil
|
@@ -249,7 +300,7 @@ module Sentry
|
|
249
300
|
self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
|
250
301
|
self.breadcrumbs_logger = []
|
251
302
|
self.context_lines = 3
|
252
|
-
self.
|
303
|
+
self.include_local_variables = false
|
253
304
|
self.environment = environment_from_env
|
254
305
|
self.enabled_environments = []
|
255
306
|
self.exclude_loggers = []
|
@@ -269,11 +320,14 @@ module Sentry
|
|
269
320
|
self.trusted_proxies = []
|
270
321
|
self.dsn = ENV['SENTRY_DSN']
|
271
322
|
self.server_name = server_name_from_env
|
323
|
+
self.instrumenter = :sentry
|
272
324
|
|
273
325
|
self.before_send = nil
|
326
|
+
self.before_send_transaction = nil
|
274
327
|
self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
|
275
328
|
self.traces_sample_rate = nil
|
276
329
|
self.traces_sampler = nil
|
330
|
+
self.enable_tracing = nil
|
277
331
|
|
278
332
|
@transport = Transport::Configuration.new
|
279
333
|
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
@@ -322,6 +376,12 @@ module Sentry
|
|
322
376
|
@before_send = value
|
323
377
|
end
|
324
378
|
|
379
|
+
def before_send_transaction=(value)
|
380
|
+
check_callable!("before_send_transaction", value)
|
381
|
+
|
382
|
+
@before_send_transaction = value
|
383
|
+
end
|
384
|
+
|
325
385
|
def before_breadcrumb=(value)
|
326
386
|
check_callable!("before_breadcrumb", value)
|
327
387
|
|
@@ -332,6 +392,20 @@ module Sentry
|
|
332
392
|
@environment = environment.to_s
|
333
393
|
end
|
334
394
|
|
395
|
+
def instrumenter=(instrumenter)
|
396
|
+
@instrumenter = INSTRUMENTERS.include?(instrumenter) ? instrumenter : :sentry
|
397
|
+
end
|
398
|
+
|
399
|
+
def enable_tracing=(enable_tracing)
|
400
|
+
@enable_tracing = enable_tracing
|
401
|
+
@traces_sample_rate ||= 1.0 if enable_tracing
|
402
|
+
end
|
403
|
+
|
404
|
+
def profiles_sample_rate=(profiles_sample_rate)
|
405
|
+
log_info("Please make sure to include the 'stackprof' gem in your Gemfile to use Profiling with Sentry.") unless defined?(StackProf)
|
406
|
+
@profiles_sample_rate = profiles_sample_rate
|
407
|
+
end
|
408
|
+
|
335
409
|
def sending_allowed?
|
336
410
|
@errors = []
|
337
411
|
|
@@ -362,7 +436,20 @@ module Sentry
|
|
362
436
|
end
|
363
437
|
|
364
438
|
def tracing_enabled?
|
365
|
-
!!((@traces_sample_rate &&
|
439
|
+
valid_sampler = !!((@traces_sample_rate &&
|
440
|
+
@traces_sample_rate >= 0.0 &&
|
441
|
+
@traces_sample_rate <= 1.0) ||
|
442
|
+
@traces_sampler)
|
443
|
+
|
444
|
+
(@enable_tracing != false) && valid_sampler && sending_allowed?
|
445
|
+
end
|
446
|
+
|
447
|
+
def profiling_enabled?
|
448
|
+
valid_sampler = !!(@profiles_sample_rate &&
|
449
|
+
@profiles_sample_rate >= 0.0 &&
|
450
|
+
@profiles_sample_rate <= 1.0)
|
451
|
+
|
452
|
+
tracing_enabled? && valid_sampler && sending_allowed?
|
366
453
|
end
|
367
454
|
|
368
455
|
# @return [String, nil]
|
@@ -487,16 +574,5 @@ module Sentry
|
|
487
574
|
instance_eval(&hook)
|
488
575
|
end
|
489
576
|
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
577
|
end
|
502
578
|
end
|
data/lib/sentry/envelope.rb
CHANGED
data/lib/sentry/event.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,11 +88,33 @@ 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
|
check_argument_type!(exception, ::Exception)
|
97
120
|
|
@@ -101,6 +124,7 @@ module Sentry
|
|
101
124
|
|
102
125
|
options[:hint] ||= {}
|
103
126
|
options[:hint][:exception] = exception
|
127
|
+
|
104
128
|
event = current_client.event_from_exception(exception, options[:hint])
|
105
129
|
|
106
130
|
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,31 +105,21 @@ 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
|
123
111
|
!(key.start_with?('HTTP_') || CONTENT_HEADERS.include?(key))
|
124
112
|
end
|
125
113
|
|
126
|
-
# Rack adds in an incorrect HTTP_VERSION key, which causes downstream
|
114
|
+
# In versions < 3, Rack adds in an incorrect HTTP_VERSION key, which causes downstream
|
127
115
|
# to think this is a Version header. Instead, this is mapped to
|
128
116
|
# env['SERVER_PROTOCOL']. But we don't want to ignore a valid header
|
129
117
|
# if the request has legitimately sent a Version header themselves.
|
130
118
|
# See: https://github.com/rack/rack/blob/028438f/lib/rack/handler/cgi.rb#L29
|
131
|
-
# NOTE: This will be removed in version 3.0+
|
132
119
|
def is_server_protocol?(key, value, protocol_version)
|
120
|
+
rack_version = Gem::Version.new(::Rack.release)
|
121
|
+
return false if rack_version >= Gem::Version.new("3.0")
|
122
|
+
|
133
123
|
key == 'HTTP_VERSION' && value == protocol_version
|
134
124
|
end
|
135
125
|
|
@@ -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,21 @@ 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?
|
29
|
+
return super unless started? && Sentry.initialized?
|
30
|
+
return super if from_sentry_sdk?
|
30
31
|
|
31
|
-
|
32
|
-
|
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)
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
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(:status, res.code.to_i)
|
42
|
+
end
|
43
|
+
end
|
37
44
|
end
|
38
45
|
end
|
39
46
|
|
@@ -42,13 +49,17 @@ module Sentry
|
|
42
49
|
def set_sentry_trace_header(req, sentry_span)
|
43
50
|
return unless sentry_span
|
44
51
|
|
45
|
-
|
52
|
+
client = Sentry.get_current_client
|
53
|
+
|
54
|
+
trace = client.generate_sentry_trace(sentry_span)
|
46
55
|
req[SENTRY_TRACE_HEADER_NAME] = trace if trace
|
56
|
+
|
57
|
+
baggage = client.generate_baggage(sentry_span)
|
58
|
+
req[BAGGAGE_HEADER_NAME] = baggage if baggage && !baggage.empty?
|
47
59
|
end
|
48
60
|
|
49
61
|
def record_sentry_breadcrumb(req, res)
|
50
62
|
return unless Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
|
51
|
-
return if from_sentry_sdk?
|
52
63
|
|
53
64
|
request_info = extract_request_info(req)
|
54
65
|
|
@@ -64,29 +75,6 @@ module Sentry
|
|
64
75
|
Sentry.add_breadcrumb(crumb)
|
65
76
|
end
|
66
77
|
|
67
|
-
def record_sentry_span(req, res, sentry_span)
|
68
|
-
return unless Sentry.initialized? && sentry_span
|
69
|
-
|
70
|
-
request_info = extract_request_info(req)
|
71
|
-
sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
|
72
|
-
sentry_span.set_data(:status, res.code.to_i)
|
73
|
-
finish_sentry_span(sentry_span)
|
74
|
-
end
|
75
|
-
|
76
|
-
def start_sentry_span
|
77
|
-
return unless Sentry.initialized? && span = Sentry.get_current_scope.get_span
|
78
|
-
return if from_sentry_sdk?
|
79
|
-
return if span.sampled == false
|
80
|
-
|
81
|
-
span.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
|
82
|
-
end
|
83
|
-
|
84
|
-
def finish_sentry_span(sentry_span)
|
85
|
-
return unless Sentry.initialized? && sentry_span
|
86
|
-
|
87
|
-
sentry_span.set_timestamp(Sentry.utc_now.to_f)
|
88
|
-
end
|
89
|
-
|
90
78
|
def from_sentry_sdk?
|
91
79
|
dsn = Sentry.configuration.dsn
|
92
80
|
dsn && dsn.host == self.address
|
@@ -109,7 +97,4 @@ module Sentry
|
|
109
97
|
end
|
110
98
|
end
|
111
99
|
|
112
|
-
Sentry.register_patch
|
113
|
-
patch = Sentry::Net::HTTP
|
114
|
-
Net::HTTP.send(:prepend, patch) unless Net::HTTP.ancestors.include?(patch)
|
115
|
-
end
|
100
|
+
Sentry.register_patch(Sentry::Net::HTTP, Net::HTTP)
|