sentry-ruby 5.4.2 → 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 +4 -4
- data/.rspec +0 -1
- data/Gemfile +17 -7
- 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 +128 -26
- data/lib/sentry/envelope.rb +1 -4
- data/lib/sentry/event.rb +1 -1
- data/lib/sentry/hub.rb +31 -3
- data/lib/sentry/interfaces/request.rb +6 -16
- data/lib/sentry/interfaces/single_exception.rb +9 -1
- data/lib/sentry/net/http.rb +26 -38
- 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 +36 -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/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 +38 -21
- metadata +6 -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
@@ -3,20 +3,29 @@ 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"
|
23
|
+
|
24
|
+
if RUBY_VERSION.to_f >= 2.6
|
25
|
+
gem "debug", github: "ruby/debug", platform: :ruby
|
26
|
+
gem "irb"
|
27
|
+
end
|
17
28
|
|
18
|
-
gem "object_tracer"
|
19
|
-
gem "debug", github: "ruby/debug", platform: :ruby if RUBY_VERSION.to_f >= 2.6
|
20
29
|
gem "pry"
|
21
30
|
|
22
31
|
gem "benchmark-ips"
|
@@ -24,4 +33,5 @@ gem "benchmark_driver"
|
|
24
33
|
gem "benchmark-ipsa"
|
25
34
|
gem "benchmark-memory"
|
26
35
|
|
27
|
-
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
|
| [](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
@@ -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/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,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,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
|
|