sentry-ruby 5.4.2 → 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 +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
|
| [![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
@@ -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
|
|