sentry-ruby 5.16.1 → 5.18.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/Gemfile +2 -0
- data/README.md +10 -10
- data/Rakefile +1 -1
- data/bin/console +1 -0
- data/lib/sentry/background_worker.rb +1 -1
- data/lib/sentry/backpressure_monitor.rb +2 -32
- data/lib/sentry/backtrace.rb +7 -3
- data/lib/sentry/check_in_event.rb +1 -1
- data/lib/sentry/client.rb +42 -9
- data/lib/sentry/configuration.rb +20 -12
- data/lib/sentry/cron/monitor_schedule.rb +1 -1
- data/lib/sentry/dsn.rb +1 -1
- data/lib/sentry/envelope.rb +18 -1
- data/lib/sentry/error_event.rb +2 -2
- data/lib/sentry/event.rb +8 -8
- data/lib/sentry/graphql.rb +9 -0
- data/lib/sentry/hub.rb +13 -2
- data/lib/sentry/integrable.rb +4 -0
- data/lib/sentry/interface.rb +1 -0
- data/lib/sentry/interfaces/exception.rb +5 -3
- data/lib/sentry/interfaces/mechanism.rb +20 -0
- data/lib/sentry/interfaces/request.rb +2 -2
- data/lib/sentry/interfaces/single_exception.rb +6 -4
- data/lib/sentry/interfaces/stacktrace_builder.rb +8 -0
- data/lib/sentry/metrics/aggregator.rb +248 -0
- data/lib/sentry/metrics/configuration.rb +47 -0
- data/lib/sentry/metrics/counter_metric.rb +25 -0
- data/lib/sentry/metrics/distribution_metric.rb +25 -0
- data/lib/sentry/metrics/gauge_metric.rb +35 -0
- data/lib/sentry/metrics/local_aggregator.rb +53 -0
- data/lib/sentry/metrics/metric.rb +19 -0
- data/lib/sentry/metrics/set_metric.rb +28 -0
- data/lib/sentry/metrics/timing.rb +43 -0
- data/lib/sentry/metrics.rb +56 -0
- data/lib/sentry/net/http.rb +2 -1
- data/lib/sentry/propagation_context.rb +9 -8
- data/lib/sentry/puma.rb +1 -1
- data/lib/sentry/rack/capture_exceptions.rb +14 -2
- data/lib/sentry/rake.rb +3 -1
- data/lib/sentry/redis.rb +2 -1
- data/lib/sentry/scope.rb +21 -26
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +6 -38
- data/lib/sentry/span.rb +39 -5
- data/lib/sentry/test_helper.rb +1 -1
- data/lib/sentry/threaded_periodic_worker.rb +39 -0
- data/lib/sentry/transaction.rb +15 -14
- data/lib/sentry/transaction_event.rb +5 -0
- data/lib/sentry/transport/configuration.rb +0 -1
- data/lib/sentry/transport.rb +8 -22
- data/lib/sentry/utils/argument_checking_helper.rb +6 -0
- data/lib/sentry/utils/logging_helper.rb +0 -4
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +26 -3
- data/sentry-ruby.gemspec +1 -0
- metadata +29 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60b2f077a84b2ebd81dd8db1113b550256994ab7561ea96e94dd9799d3f61b9f
|
4
|
+
data.tar.gz: 4739ab8bca432f215b10747c4bc4caa031daa8f0751c90729b1a946554ea1875
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 289e1be06a0d13f066881d3f1b2d0b674c3a61d576f4901b252872831263decb1af3ee7ff8201027ed1003231442680547e01a9f3e1130b773289770552ac10f
|
7
|
+
data.tar.gz: f0e5d48799611bd5db4b0b759b18e2b7eea13052bf24a21b9641c4fd755647ee3b4f007ac778f694b63a2ee03d94f7bab6a57ae5c83a7ace58dab7714382aa5c
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -13,14 +13,14 @@ _Bad software is everywhere, and we're tired of it. Sentry is on a mission to he
|
|
13
13
|
Sentry SDK for Ruby
|
14
14
|
===========
|
15
15
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
| [](https://rubygems.org/gems/sentry-ruby) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-rails) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](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-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-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-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-ruby) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://www.rubydoc.info/gems/sentry-ruby) |
|
19
|
+
| [](https://rubygems.org/gems/sentry-rails) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://www.rubydoc.info/gems/sentry-rails) |
|
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://www.rubydoc.info/gems/sentry-sidekiq) |
|
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://www.rubydoc.info/gems/sentry-delayed_job) |
|
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://www.rubydoc.info/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://www.rubydoc.info/gems/sentry-opentelemetry) |
|
24
24
|
|
25
25
|
|
26
26
|
|
@@ -90,7 +90,7 @@ To learn more about sampling transactions, please visit the [official documentat
|
|
90
90
|
- [Sidekiq](https://docs.sentry.io/platforms/ruby/guides/sidekiq/)
|
91
91
|
- [DelayedJob](https://docs.sentry.io/platforms/ruby/guides/delayed_job/)
|
92
92
|
- [Resque](https://docs.sentry.io/platforms/ruby/guides/resque/)
|
93
|
-
- [
|
93
|
+
- [OpenTelemetry](https://docs.sentry.io/platforms/ruby/performance/instrumentation/opentelemetry/)
|
94
94
|
|
95
95
|
### Enriching Events
|
96
96
|
|
@@ -103,6 +103,6 @@ To learn more about sampling transactions, please visit the [official documentat
|
|
103
103
|
|
104
104
|
* [](https://docs.sentry.io/platforms/ruby/)
|
105
105
|
* [](https://forum.sentry.io/c/sdks)
|
106
|
-
* [](https://discord.gg/PXa5Apfe7K)
|
106
|
+
* [](https://discord.gg/PXa5Apfe7K)
|
107
107
|
* [](https://stackoverflow.com/questions/tagged/sentry)
|
108
108
|
* [](https://twitter.com/intent/follow?screen_name=getsentry)
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
@@ -31,7 +31,7 @@ module Sentry
|
|
31
31
|
log_debug("config.background_worker_threads is set to 0, all events will be sent synchronously")
|
32
32
|
Concurrent::ImmediateExecutor.new
|
33
33
|
else
|
34
|
-
log_debug("Initializing the background worker with #{@number_of_threads} threads")
|
34
|
+
log_debug("Initializing the Sentry background worker with #{@number_of_threads} threads")
|
35
35
|
|
36
36
|
executor = Concurrent::ThreadPoolExecutor.new(
|
37
37
|
min_threads: 0,
|
@@ -1,19 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Sentry
|
4
|
-
class BackpressureMonitor
|
5
|
-
include LoggingHelper
|
6
|
-
|
4
|
+
class BackpressureMonitor < ThreadedPeriodicWorker
|
7
5
|
DEFAULT_INTERVAL = 10
|
8
6
|
MAX_DOWNSAMPLE_FACTOR = 10
|
9
7
|
|
10
8
|
def initialize(configuration, client, interval: DEFAULT_INTERVAL)
|
11
|
-
|
9
|
+
super(configuration.logger, interval)
|
12
10
|
@client = client
|
13
|
-
@logger = configuration.logger
|
14
|
-
|
15
|
-
@thread = nil
|
16
|
-
@exited = false
|
17
11
|
|
18
12
|
@healthy = true
|
19
13
|
@downsample_factor = 0
|
@@ -47,29 +41,5 @@ module Sentry
|
|
47
41
|
log_debug("[BackpressureMonitor] health check negative, downsampling with a factor of #{@downsample_factor}")
|
48
42
|
end
|
49
43
|
end
|
50
|
-
|
51
|
-
def kill
|
52
|
-
log_debug("[BackpressureMonitor] killing monitor")
|
53
|
-
|
54
|
-
@exited = true
|
55
|
-
@thread&.kill
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def ensure_thread
|
61
|
-
return if @exited
|
62
|
-
return if @thread&.alive?
|
63
|
-
|
64
|
-
@thread = Thread.new do
|
65
|
-
loop do
|
66
|
-
sleep(@interval)
|
67
|
-
run
|
68
|
-
end
|
69
|
-
end
|
70
|
-
rescue ThreadError
|
71
|
-
log_debug("[BackpressureMonitor] Thread creation failed")
|
72
|
-
@exited = true
|
73
|
-
end
|
74
44
|
end
|
75
45
|
end
|
data/lib/sentry/backtrace.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rubygems"
|
4
|
+
|
3
5
|
module Sentry
|
4
6
|
# @api private
|
5
7
|
class Backtrace
|
@@ -10,7 +12,7 @@ module Sentry
|
|
10
12
|
RUBY_INPUT_FORMAT = /
|
11
13
|
^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
|
12
14
|
(\d+)
|
13
|
-
(?: :in
|
15
|
+
(?: :in\s('|`)([^']+)')?$
|
14
16
|
/x.freeze
|
15
17
|
|
16
18
|
# org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
|
@@ -33,10 +35,10 @@ module Sentry
|
|
33
35
|
# Parses a single line of a given backtrace
|
34
36
|
# @param [String] unparsed_line The raw line from +caller+ or some backtrace
|
35
37
|
# @return [Line] The parsed backtrace line
|
36
|
-
def self.parse(unparsed_line, in_app_pattern)
|
38
|
+
def self.parse(unparsed_line, in_app_pattern = nil)
|
37
39
|
ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
|
38
40
|
if ruby_match
|
39
|
-
_, file, number, method = ruby_match.to_a
|
41
|
+
_, file, number, _, method = ruby_match.to_a
|
40
42
|
file.sub!(/\.class$/, RB_EXTENSION)
|
41
43
|
module_name = nil
|
42
44
|
else
|
@@ -55,6 +57,8 @@ module Sentry
|
|
55
57
|
end
|
56
58
|
|
57
59
|
def in_app
|
60
|
+
return false unless in_app_pattern
|
61
|
+
|
58
62
|
if file =~ in_app_pattern
|
59
63
|
true
|
60
64
|
else
|
data/lib/sentry/client.rb
CHANGED
@@ -49,16 +49,17 @@ module Sentry
|
|
49
49
|
return unless configuration.sending_allowed?
|
50
50
|
|
51
51
|
if event.is_a?(ErrorEvent) && !configuration.sample_allowed?
|
52
|
-
transport.record_lost_event(:sample_rate, '
|
52
|
+
transport.record_lost_event(:sample_rate, 'error')
|
53
53
|
return
|
54
54
|
end
|
55
55
|
|
56
56
|
event_type = event.is_a?(Event) ? event.type : event["type"]
|
57
|
+
data_category = Envelope::Item.data_category(event_type)
|
57
58
|
event = scope.apply_to_event(event, hint)
|
58
59
|
|
59
60
|
if event.nil?
|
60
61
|
log_debug("Discarded event because one of the event processors returned nil")
|
61
|
-
transport.record_lost_event(:event_processor,
|
62
|
+
transport.record_lost_event(:event_processor, data_category)
|
62
63
|
return
|
63
64
|
end
|
64
65
|
|
@@ -66,7 +67,7 @@ module Sentry
|
|
66
67
|
dispatch_async_event(async_block, event, hint)
|
67
68
|
elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
|
68
69
|
queued = dispatch_background_event(event, hint)
|
69
|
-
transport.record_lost_event(:queue_overflow,
|
70
|
+
transport.record_lost_event(:queue_overflow, data_category) unless queued
|
70
71
|
else
|
71
72
|
send_event(event, hint)
|
72
73
|
end
|
@@ -77,6 +78,20 @@ module Sentry
|
|
77
78
|
nil
|
78
79
|
end
|
79
80
|
|
81
|
+
# Capture an envelope directly.
|
82
|
+
# @param envelope [Envelope] the envelope to be captured.
|
83
|
+
# @return [void]
|
84
|
+
def capture_envelope(envelope)
|
85
|
+
Sentry.background_worker.perform { send_envelope(envelope) }
|
86
|
+
end
|
87
|
+
|
88
|
+
# Flush pending events to Sentry.
|
89
|
+
# @return [void]
|
90
|
+
def flush
|
91
|
+
transport.flush if configuration.sending_to_dsn_allowed?
|
92
|
+
spotlight_transport.flush if spotlight_transport
|
93
|
+
end
|
94
|
+
|
80
95
|
# Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
|
81
96
|
# @param exception [Exception] the exception to be reported.
|
82
97
|
# @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
|
@@ -88,9 +103,10 @@ module Sentry
|
|
88
103
|
return if !ignore_exclusions && !@configuration.exception_class_allowed?(exception)
|
89
104
|
|
90
105
|
integration_meta = Sentry.integrations[hint[:integration]]
|
106
|
+
mechanism = hint.delete(:mechanism) { Mechanism.new }
|
91
107
|
|
92
108
|
ErrorEvent.new(configuration: configuration, integration_meta: integration_meta).tap do |event|
|
93
|
-
event.add_exception_interface(exception)
|
109
|
+
event.add_exception_interface(exception, mechanism: mechanism)
|
94
110
|
event.add_threads_interface(crashed: true)
|
95
111
|
event.level = :error
|
96
112
|
end
|
@@ -151,13 +167,14 @@ module Sentry
|
|
151
167
|
# @!macro send_event
|
152
168
|
def send_event(event, hint = nil)
|
153
169
|
event_type = event.is_a?(Event) ? event.type : event["type"]
|
170
|
+
data_category = Envelope::Item.data_category(event_type)
|
154
171
|
|
155
172
|
if event_type != TransactionEvent::TYPE && configuration.before_send
|
156
173
|
event = configuration.before_send.call(event, hint)
|
157
174
|
|
158
175
|
if event.nil?
|
159
176
|
log_debug("Discarded event because before_send returned nil")
|
160
|
-
transport.record_lost_event(:before_send,
|
177
|
+
transport.record_lost_event(:before_send, data_category)
|
161
178
|
return
|
162
179
|
end
|
163
180
|
end
|
@@ -167,18 +184,34 @@ module Sentry
|
|
167
184
|
|
168
185
|
if event.nil?
|
169
186
|
log_debug("Discarded event because before_send_transaction returned nil")
|
170
|
-
transport.record_lost_event(:before_send,
|
187
|
+
transport.record_lost_event(:before_send, data_category)
|
171
188
|
return
|
172
189
|
end
|
173
190
|
end
|
174
191
|
|
175
|
-
transport.send_event(event)
|
176
|
-
spotlight_transport
|
192
|
+
transport.send_event(event) if configuration.sending_to_dsn_allowed?
|
193
|
+
spotlight_transport.send_event(event) if spotlight_transport
|
177
194
|
|
178
195
|
event
|
179
196
|
rescue => e
|
180
197
|
log_error("Event sending failed", e, debug: configuration.debug)
|
181
|
-
transport.record_lost_event(:network_error,
|
198
|
+
transport.record_lost_event(:network_error, data_category)
|
199
|
+
raise
|
200
|
+
end
|
201
|
+
|
202
|
+
# Send an envelope directly to Sentry.
|
203
|
+
# @param envelope [Envelope] the envelope to be sent.
|
204
|
+
# @return [void]
|
205
|
+
def send_envelope(envelope)
|
206
|
+
transport.send_envelope(envelope) if configuration.sending_to_dsn_allowed?
|
207
|
+
spotlight_transport.send_envelope(envelope) if spotlight_transport
|
208
|
+
rescue => e
|
209
|
+
log_error("Envelope sending failed", e, debug: configuration.debug)
|
210
|
+
|
211
|
+
envelope.items.map(&:data_category).each do |data_category|
|
212
|
+
transport.record_lost_event(:network_error, data_category)
|
213
|
+
end
|
214
|
+
|
182
215
|
raise
|
183
216
|
end
|
184
217
|
|
data/lib/sentry/configuration.rb
CHANGED
@@ -8,6 +8,7 @@ require "sentry/dsn"
|
|
8
8
|
require "sentry/release_detector"
|
9
9
|
require "sentry/transport/configuration"
|
10
10
|
require "sentry/cron/configuration"
|
11
|
+
require "sentry/metrics/configuration"
|
11
12
|
require "sentry/linecache"
|
12
13
|
require "sentry/interfaces/stacktrace_builder"
|
13
14
|
|
@@ -235,6 +236,10 @@ module Sentry
|
|
235
236
|
# @return [Cron::Configuration]
|
236
237
|
attr_reader :cron
|
237
238
|
|
239
|
+
# Metrics related configuration.
|
240
|
+
# @return [Metrics::Configuration]
|
241
|
+
attr_reader :metrics
|
242
|
+
|
238
243
|
# Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
|
239
244
|
# @return [Float, nil]
|
240
245
|
attr_reader :traces_sample_rate
|
@@ -311,11 +316,11 @@ module Sentry
|
|
311
316
|
'Sinatra::NotFound'
|
312
317
|
].freeze
|
313
318
|
|
314
|
-
RACK_ENV_WHITELIST_DEFAULT = %w
|
319
|
+
RACK_ENV_WHITELIST_DEFAULT = %w[
|
315
320
|
REMOTE_ADDR
|
316
321
|
SERVER_NAME
|
317
322
|
SERVER_PORT
|
318
|
-
|
323
|
+
].freeze
|
319
324
|
|
320
325
|
HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
|
321
326
|
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`".freeze
|
@@ -328,7 +333,7 @@ module Sentry
|
|
328
333
|
|
329
334
|
PROPAGATION_TARGETS_MATCH_ALL = /.*/.freeze
|
330
335
|
|
331
|
-
DEFAULT_PATCHES = %i
|
336
|
+
DEFAULT_PATCHES = %i[redis puma http].freeze
|
332
337
|
|
333
338
|
class << self
|
334
339
|
# Post initialization callbacks are called at the end of initialization process
|
@@ -337,7 +342,7 @@ module Sentry
|
|
337
342
|
@post_initialization_callbacks ||= []
|
338
343
|
end
|
339
344
|
|
340
|
-
|
345
|
+
# allow extensions to add their hooks to the Configuration class
|
341
346
|
def add_post_initialization_callback(&block)
|
342
347
|
post_initialization_callbacks << block
|
343
348
|
end
|
@@ -346,7 +351,7 @@ module Sentry
|
|
346
351
|
def initialize
|
347
352
|
self.app_dirs_pattern = nil
|
348
353
|
self.debug = false
|
349
|
-
self.background_worker_threads = Concurrent.processor_count
|
354
|
+
self.background_worker_threads = (Concurrent.processor_count / 2.0).ceil
|
350
355
|
self.background_worker_max_queue = BackgroundWorker::DEFAULT_MAX_QUEUE
|
351
356
|
self.backtrace_cleanup_callback = nil
|
352
357
|
self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
|
@@ -386,6 +391,7 @@ module Sentry
|
|
386
391
|
|
387
392
|
@transport = Transport::Configuration.new
|
388
393
|
@cron = Cron::Configuration.new
|
394
|
+
@metrics = Metrics::Configuration.new
|
389
395
|
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
390
396
|
|
391
397
|
run_post_initialization_callbacks
|
@@ -479,9 +485,13 @@ module Sentry
|
|
479
485
|
end
|
480
486
|
|
481
487
|
def sending_allowed?
|
488
|
+
spotlight || sending_to_dsn_allowed?
|
489
|
+
end
|
490
|
+
|
491
|
+
def sending_to_dsn_allowed?
|
482
492
|
@errors = []
|
483
493
|
|
484
|
-
|
494
|
+
valid? && capture_in_environment?
|
485
495
|
end
|
486
496
|
|
487
497
|
def sample_allowed?
|
@@ -490,6 +500,10 @@ module Sentry
|
|
490
500
|
Random.rand < sample_rate
|
491
501
|
end
|
492
502
|
|
503
|
+
def session_tracking?
|
504
|
+
auto_session_tracking && enabled_in_current_env?
|
505
|
+
end
|
506
|
+
|
493
507
|
def exception_class_allowed?(exc)
|
494
508
|
if exc.is_a?(Sentry::Error)
|
495
509
|
# Try to prevent error reporting loops
|
@@ -566,12 +580,6 @@ module Sentry
|
|
566
580
|
|
567
581
|
private
|
568
582
|
|
569
|
-
def check_callable!(name, value)
|
570
|
-
unless value == nil || value.respond_to?(:call)
|
571
|
-
raise ArgumentError, "#{name} must be callable (or nil to disable)"
|
572
|
-
end
|
573
|
-
end
|
574
|
-
|
575
583
|
def init_dsn(dsn_string)
|
576
584
|
return if dsn_string.nil? || dsn_string.empty?
|
577
585
|
|
data/lib/sentry/dsn.rb
CHANGED
@@ -5,7 +5,7 @@ require "uri"
|
|
5
5
|
module Sentry
|
6
6
|
class DSN
|
7
7
|
PORT_MAP = { 'http' => 80, 'https' => 443 }.freeze
|
8
|
-
REQUIRED_ATTRIBUTES = %w
|
8
|
+
REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
|
9
9
|
|
10
10
|
attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
|
11
11
|
|
data/lib/sentry/envelope.rb
CHANGED
@@ -18,8 +18,25 @@ module Sentry
|
|
18
18
|
@headers[:type] || 'event'
|
19
19
|
end
|
20
20
|
|
21
|
+
# rate limits and client reports use the data_category rather than envelope item type
|
22
|
+
def self.data_category(type)
|
23
|
+
case type
|
24
|
+
when 'session', 'attachment', 'transaction', 'profile' then type
|
25
|
+
when 'sessions' then 'session'
|
26
|
+
when 'check_in' then 'monitor'
|
27
|
+
when 'statsd', 'metric_meta' then 'metric_bucket'
|
28
|
+
when 'event' then 'error'
|
29
|
+
when 'client_report' then 'internal'
|
30
|
+
else 'default'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def data_category
|
35
|
+
self.class.data_category(type)
|
36
|
+
end
|
37
|
+
|
21
38
|
def to_s
|
22
|
-
[JSON.generate(@headers), JSON.generate(@payload)].join("\n")
|
39
|
+
[JSON.generate(@headers), @payload.is_a?(String) ? @payload : JSON.generate(@payload)].join("\n")
|
23
40
|
end
|
24
41
|
|
25
42
|
def serialize
|
data/lib/sentry/error_event.rb
CHANGED
@@ -27,12 +27,12 @@ module Sentry
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# @!visibility private
|
30
|
-
def add_exception_interface(exception)
|
30
|
+
def add_exception_interface(exception, mechanism:)
|
31
31
|
if exception.respond_to?(:sentry_context)
|
32
32
|
@extra.merge!(exception.sentry_context)
|
33
33
|
end
|
34
34
|
|
35
|
-
@exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder)
|
35
|
+
@exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder, mechanism: mechanism)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/lib/sentry/event.rb
CHANGED
@@ -14,16 +14,16 @@ module Sentry
|
|
14
14
|
class Event
|
15
15
|
TYPE = "event"
|
16
16
|
# These are readable attributes.
|
17
|
-
SERIALIZEABLE_ATTRIBUTES = %i
|
17
|
+
SERIALIZEABLE_ATTRIBUTES = %i[
|
18
18
|
event_id level timestamp
|
19
19
|
release environment server_name modules
|
20
20
|
message user tags contexts extra
|
21
21
|
fingerprint breadcrumbs transaction transaction_info
|
22
22
|
platform sdk type
|
23
|
-
|
23
|
+
]
|
24
24
|
|
25
25
|
# These are writable attributes.
|
26
|
-
WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i
|
26
|
+
WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i[type timestamp level]
|
27
27
|
|
28
28
|
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
29
29
|
|
@@ -145,11 +145,11 @@ module Sentry
|
|
145
145
|
# REMOTE_ADDR to determine the Event IP, and must use other headers instead.
|
146
146
|
def calculate_real_ip_from_rack(env)
|
147
147
|
Utils::RealIp.new(
|
148
|
-
:
|
149
|
-
:
|
150
|
-
:
|
151
|
-
:
|
152
|
-
:
|
148
|
+
remote_addr: env["REMOTE_ADDR"],
|
149
|
+
client_ip: env["HTTP_CLIENT_IP"],
|
150
|
+
real_ip: env["HTTP_X_REAL_IP"],
|
151
|
+
forwarded_for: env["HTTP_X_FORWARDED_FOR"],
|
152
|
+
trusted_proxies: @trusted_proxies
|
153
153
|
).calculate_ip
|
154
154
|
end
|
155
155
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Sentry.register_patch(:graphql) do |config|
|
4
|
+
if defined?(::GraphQL::Schema) && defined?(::GraphQL::Tracing::SentryTrace) && ::GraphQL::Schema.respond_to?(:trace_with)
|
5
|
+
::GraphQL::Schema.trace_with(::GraphQL::Tracing::SentryTrace, set_transaction_name: true)
|
6
|
+
else
|
7
|
+
config.logger.warn(Sentry::LOGGER_PROGNAME) { 'You tried to enable the GraphQL integration but no GraphQL gem was detected. Make sure you have the `graphql` gem (>= 2.2.6) in your Gemfile.' }
|
8
|
+
end
|
9
|
+
end
|
data/lib/sentry/hub.rb
CHANGED
@@ -193,7 +193,12 @@ module Sentry
|
|
193
193
|
elsif custom_scope = options[:scope]
|
194
194
|
scope.update_from_scope(custom_scope)
|
195
195
|
elsif !options.empty?
|
196
|
-
scope.update_from_options(**options)
|
196
|
+
unsupported_option_keys = scope.update_from_options(**options)
|
197
|
+
|
198
|
+
configuration.log_debug <<~MSG
|
199
|
+
Options #{unsupported_option_keys} are not supported and will not be applied to the event.
|
200
|
+
You may want to set them under the `extra` option.
|
201
|
+
MSG
|
197
202
|
end
|
198
203
|
|
199
204
|
event = current_client.capture_event(event, scope, hint)
|
@@ -245,7 +250,7 @@ module Sentry
|
|
245
250
|
end
|
246
251
|
|
247
252
|
def with_session_tracking(&block)
|
248
|
-
return yield unless configuration.
|
253
|
+
return yield unless configuration.session_tracking?
|
249
254
|
|
250
255
|
start_session
|
251
256
|
yield
|
@@ -279,6 +284,12 @@ module Sentry
|
|
279
284
|
headers
|
280
285
|
end
|
281
286
|
|
287
|
+
def get_trace_propagation_meta
|
288
|
+
get_trace_propagation_headers.map do |k, v|
|
289
|
+
"<meta name=\"#{k}\" content=\"#{v}\">"
|
290
|
+
end.join("\n")
|
291
|
+
end
|
292
|
+
|
282
293
|
def continue_trace(env, **options)
|
283
294
|
configure_scope { |s| s.generate_propagation_context(env) }
|
284
295
|
|
data/lib/sentry/integrable.rb
CHANGED
@@ -14,6 +14,10 @@ module Sentry
|
|
14
14
|
def capture_exception(exception, **options, &block)
|
15
15
|
options[:hint] ||= {}
|
16
16
|
options[:hint][:integration] = integration_name
|
17
|
+
|
18
|
+
# within an integration, we usually intercept uncaught exceptions so we set handled to false.
|
19
|
+
options[:hint][:mechanism] ||= Sentry::Mechanism.new(type: integration_name, handled: false)
|
20
|
+
|
17
21
|
Sentry.capture_exception(exception, **options, &block)
|
18
22
|
end
|
19
23
|
|
data/lib/sentry/interface.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require "set"
|
3
4
|
|
4
5
|
module Sentry
|
@@ -23,17 +24,18 @@ module Sentry
|
|
23
24
|
# @param stacktrace_builder [StacktraceBuilder]
|
24
25
|
# @see SingleExceptionInterface#build_with_stacktrace
|
25
26
|
# @see SingleExceptionInterface#initialize
|
27
|
+
# @param mechanism [Mechanism]
|
26
28
|
# @return [ExceptionInterface]
|
27
|
-
def self.build(exception:, stacktrace_builder:)
|
29
|
+
def self.build(exception:, stacktrace_builder:, mechanism:)
|
28
30
|
exceptions = Sentry::Utils::ExceptionCauseChain.exception_to_array(exception).reverse
|
29
31
|
processed_backtrace_ids = Set.new
|
30
32
|
|
31
33
|
exceptions = exceptions.map do |e|
|
32
34
|
if e.backtrace && !processed_backtrace_ids.include?(e.backtrace.object_id)
|
33
35
|
processed_backtrace_ids << e.backtrace.object_id
|
34
|
-
SingleExceptionInterface.build_with_stacktrace(exception: e, stacktrace_builder: stacktrace_builder)
|
36
|
+
SingleExceptionInterface.build_with_stacktrace(exception: e, stacktrace_builder: stacktrace_builder, mechanism: mechanism)
|
35
37
|
else
|
36
|
-
SingleExceptionInterface.new(exception: exception)
|
38
|
+
SingleExceptionInterface.new(exception: exception, mechanism: mechanism)
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
class Mechanism < Interface
|
5
|
+
# Generic identifier, mostly the source integration for this exception.
|
6
|
+
# @return [String]
|
7
|
+
attr_accessor :type
|
8
|
+
|
9
|
+
# A manually captured exception has handled set to true,
|
10
|
+
# false if coming from an integration where we intercept an uncaught exception.
|
11
|
+
# Defaults to true here and will be set to false explicitly in integrations.
|
12
|
+
# @return [Boolean]
|
13
|
+
attr_accessor :handled
|
14
|
+
|
15
|
+
def initialize(type: 'generic', handled: true)
|
16
|
+
@type = type
|
17
|
+
@handled = handled
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|