sentry-ruby 5.13.0 → 5.21.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 +7 -18
- data/README.md +20 -10
- data/Rakefile +3 -1
- data/bin/console +2 -0
- data/lib/sentry/attachment.rb +40 -0
- data/lib/sentry/background_worker.rb +9 -2
- data/lib/sentry/backpressure_monitor.rb +45 -0
- data/lib/sentry/backtrace.rb +10 -8
- data/lib/sentry/baggage.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
- data/lib/sentry/check_in_event.rb +5 -5
- data/lib/sentry/client.rb +71 -18
- data/lib/sentry/configuration.rb +108 -32
- data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
- data/lib/sentry/cron/configuration.rb +23 -0
- data/lib/sentry/cron/monitor_check_ins.rb +42 -26
- data/lib/sentry/cron/monitor_config.rb +1 -1
- data/lib/sentry/cron/monitor_schedule.rb +1 -1
- data/lib/sentry/dsn.rb +4 -4
- data/lib/sentry/envelope/item.rb +88 -0
- data/lib/sentry/envelope.rb +2 -68
- data/lib/sentry/error_event.rb +2 -2
- data/lib/sentry/event.rb +20 -46
- data/lib/sentry/faraday.rb +77 -0
- data/lib/sentry/graphql.rb +9 -0
- data/lib/sentry/hub.rb +25 -5
- 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 +7 -7
- data/lib/sentry/interfaces/single_exception.rb +10 -7
- data/lib/sentry/interfaces/stacktrace.rb +3 -1
- data/lib/sentry/interfaces/stacktrace_builder.rb +23 -2
- data/lib/sentry/logger.rb +1 -1
- 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 +22 -39
- data/lib/sentry/profiler/helpers.rb +46 -0
- data/lib/sentry/profiler.rb +25 -56
- data/lib/sentry/propagation_context.rb +10 -9
- data/lib/sentry/puma.rb +1 -1
- data/lib/sentry/rack/capture_exceptions.rb +16 -4
- data/lib/sentry/rack.rb +2 -2
- data/lib/sentry/rake.rb +4 -15
- data/lib/sentry/redis.rb +2 -1
- data/lib/sentry/release_detector.rb +5 -5
- data/lib/sentry/scope.rb +48 -37
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +7 -39
- data/lib/sentry/span.rb +46 -5
- data/lib/sentry/test_helper.rb +5 -2
- data/lib/sentry/threaded_periodic_worker.rb +39 -0
- data/lib/sentry/transaction.rb +27 -18
- data/lib/sentry/transaction_event.rb +6 -2
- data/lib/sentry/transport/configuration.rb +73 -1
- data/lib/sentry/transport/http_transport.rb +72 -41
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +36 -41
- data/lib/sentry/utils/argument_checking_helper.rb +6 -0
- data/lib/sentry/utils/env_helper.rb +21 -0
- data/lib/sentry/utils/http_tracing.rb +41 -0
- data/lib/sentry/utils/logging_helper.rb +0 -4
- data/lib/sentry/utils/real_ip.rb +2 -2
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/vernier/output.rb +89 -0
- data/lib/sentry/vernier/profiler.rb +125 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +61 -27
- data/sentry-ruby-core.gemspec +3 -1
- data/sentry-ruby.gemspec +15 -6
- metadata +47 -7
data/lib/sentry/configuration.rb
CHANGED
@@ -3,10 +3,13 @@
|
|
3
3
|
require "concurrent/utility/processor_counter"
|
4
4
|
|
5
5
|
require "sentry/utils/exception_cause_chain"
|
6
|
-
require
|
6
|
+
require "sentry/utils/custom_inspection"
|
7
|
+
require "sentry/utils/env_helper"
|
7
8
|
require "sentry/dsn"
|
8
9
|
require "sentry/release_detector"
|
9
10
|
require "sentry/transport/configuration"
|
11
|
+
require "sentry/cron/configuration"
|
12
|
+
require "sentry/metrics/configuration"
|
10
13
|
require "sentry/linecache"
|
11
14
|
require "sentry/interfaces/stacktrace_builder"
|
12
15
|
|
@@ -20,6 +23,8 @@ module Sentry
|
|
20
23
|
# have an `engines` dir at the root of your project, you may want
|
21
24
|
# to set this to something like /(app|config|engines|lib)/
|
22
25
|
#
|
26
|
+
# The default is value is /(bin|exe|app|config|lib|test|spec)/
|
27
|
+
#
|
23
28
|
# @return [Regexp, nil]
|
24
29
|
attr_accessor :app_dirs_pattern
|
25
30
|
|
@@ -40,6 +45,13 @@ module Sentry
|
|
40
45
|
# @return [Integer]
|
41
46
|
attr_accessor :background_worker_threads
|
42
47
|
|
48
|
+
# The maximum queue size for the background worker.
|
49
|
+
# Jobs will be rejected above this limit.
|
50
|
+
#
|
51
|
+
# Default is {BackgroundWorker::DEFAULT_MAX_QUEUE}.
|
52
|
+
# @return [Integer]
|
53
|
+
attr_accessor :background_worker_max_queue
|
54
|
+
|
43
55
|
# a proc/lambda that takes an array of stack traces
|
44
56
|
# it'll be used to silence (reduce) backtrace of the exception
|
45
57
|
#
|
@@ -142,6 +154,14 @@ module Sentry
|
|
142
154
|
# @return [Boolean]
|
143
155
|
attr_accessor :include_local_variables
|
144
156
|
|
157
|
+
# Whether to capture events and traces into Spotlight. Default is false.
|
158
|
+
# If you set this to true, Sentry will send events and traces to the local
|
159
|
+
# Sidecar proxy at http://localhost:8969/stream.
|
160
|
+
# If you want to use a different Sidecar proxy address, set this to String
|
161
|
+
# with the proxy URL.
|
162
|
+
# @return [Boolean, String]
|
163
|
+
attr_accessor :spotlight
|
164
|
+
|
145
165
|
# @deprecated Use {#include_local_variables} instead.
|
146
166
|
alias_method :capture_exception_frame_locals, :include_local_variables
|
147
167
|
|
@@ -170,6 +190,11 @@ module Sentry
|
|
170
190
|
# @return [String]
|
171
191
|
attr_accessor :project_root
|
172
192
|
|
193
|
+
# Whether to strip the load path while constructing the backtrace frame filename.
|
194
|
+
# Defaults to true.
|
195
|
+
# @return [Boolean]
|
196
|
+
attr_accessor :strip_backtrace_load_path
|
197
|
+
|
173
198
|
# Insert sentry-trace to outgoing requests' headers
|
174
199
|
# @return [Boolean]
|
175
200
|
attr_accessor :propagate_traces
|
@@ -211,10 +236,18 @@ module Sentry
|
|
211
236
|
# @return [String]
|
212
237
|
attr_accessor :server_name
|
213
238
|
|
214
|
-
#
|
215
|
-
# @return [Transport]
|
239
|
+
# Transport related configuration.
|
240
|
+
# @return [Transport::Configuration]
|
216
241
|
attr_reader :transport
|
217
242
|
|
243
|
+
# Cron related configuration.
|
244
|
+
# @return [Cron::Configuration]
|
245
|
+
attr_reader :cron
|
246
|
+
|
247
|
+
# Metrics related configuration.
|
248
|
+
# @return [Metrics::Configuration]
|
249
|
+
attr_reader :metrics
|
250
|
+
|
218
251
|
# Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
|
219
252
|
# @return [Float, nil]
|
220
253
|
attr_reader :traces_sample_rate
|
@@ -243,6 +276,12 @@ module Sentry
|
|
243
276
|
# @return [Boolean]
|
244
277
|
attr_accessor :auto_session_tracking
|
245
278
|
|
279
|
+
# Whether to downsample transactions automatically because of backpressure.
|
280
|
+
# Starts a new monitor thread to check health of the SDK every 10 seconds.
|
281
|
+
# Default is false
|
282
|
+
# @return [Boolean]
|
283
|
+
attr_accessor :enable_backpressure_handling
|
284
|
+
|
246
285
|
# Allowlist of outgoing request targets to which sentry-trace and baggage headers are attached.
|
247
286
|
# Default is all (/.*/)
|
248
287
|
# @return [Array<String, Regexp>]
|
@@ -252,6 +291,10 @@ module Sentry
|
|
252
291
|
# @return [Symbol]
|
253
292
|
attr_reader :instrumenter
|
254
293
|
|
294
|
+
# The profiler class
|
295
|
+
# @return [Class]
|
296
|
+
attr_reader :profiler_class
|
297
|
+
|
255
298
|
# Take a float between 0.0 and 1.0 as the sample rate for capturing profiles.
|
256
299
|
# Note that this rate is relative to traces_sample_rate / traces_sampler,
|
257
300
|
# i.e. the profile is sampled by this rate after the transaction is sampled.
|
@@ -271,38 +314,40 @@ module Sentry
|
|
271
314
|
# But they are mostly considered as noise and should be ignored by default
|
272
315
|
# Please see https://github.com/getsentry/sentry-ruby/pull/2026 for more information
|
273
316
|
PUMA_IGNORE_DEFAULT = [
|
274
|
-
|
275
|
-
|
276
|
-
|
317
|
+
"Puma::MiniSSL::SSLError",
|
318
|
+
"Puma::HttpParserError",
|
319
|
+
"Puma::HttpParserError501"
|
277
320
|
].freeze
|
278
321
|
|
279
322
|
# Most of these errors generate 4XX responses. In general, Sentry clients
|
280
323
|
# only automatically report 5xx responses.
|
281
324
|
IGNORE_DEFAULT = [
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
325
|
+
"Mongoid::Errors::DocumentNotFound",
|
326
|
+
"Rack::QueryParser::InvalidParameterError",
|
327
|
+
"Rack::QueryParser::ParameterTypeError",
|
328
|
+
"Sinatra::NotFound"
|
286
329
|
].freeze
|
287
330
|
|
288
|
-
RACK_ENV_WHITELIST_DEFAULT = %w
|
331
|
+
RACK_ENV_WHITELIST_DEFAULT = %w[
|
289
332
|
REMOTE_ADDR
|
290
333
|
SERVER_NAME
|
291
334
|
SERVER_PORT
|
292
|
-
|
335
|
+
].freeze
|
293
336
|
|
294
337
|
HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
|
295
|
-
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
|
338
|
+
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
|
296
339
|
|
297
|
-
LOG_PREFIX = "** [Sentry] "
|
298
|
-
MODULE_SEPARATOR = "::"
|
340
|
+
LOG_PREFIX = "** [Sentry] "
|
341
|
+
MODULE_SEPARATOR = "::"
|
299
342
|
SKIP_INSPECTION_ATTRIBUTES = [:@linecache, :@stacktrace_builder]
|
300
343
|
|
301
344
|
INSTRUMENTERS = [:sentry, :otel]
|
302
345
|
|
303
|
-
PROPAGATION_TARGETS_MATCH_ALL =
|
346
|
+
PROPAGATION_TARGETS_MATCH_ALL = /.*/
|
347
|
+
|
348
|
+
DEFAULT_PATCHES = %i[redis puma http].freeze
|
304
349
|
|
305
|
-
|
350
|
+
APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/
|
306
351
|
|
307
352
|
class << self
|
308
353
|
# Post initialization callbacks are called at the end of initialization process
|
@@ -311,17 +356,19 @@ module Sentry
|
|
311
356
|
@post_initialization_callbacks ||= []
|
312
357
|
end
|
313
358
|
|
314
|
-
|
359
|
+
# allow extensions to add their hooks to the Configuration class
|
315
360
|
def add_post_initialization_callback(&block)
|
316
361
|
post_initialization_callbacks << block
|
317
362
|
end
|
318
363
|
end
|
319
364
|
|
320
365
|
def initialize
|
321
|
-
self.app_dirs_pattern =
|
322
|
-
self.debug =
|
323
|
-
self.background_worker_threads =
|
366
|
+
self.app_dirs_pattern = APP_DIRS_PATTERN
|
367
|
+
self.debug = Sentry::Utils::EnvHelper.env_to_bool(ENV["SENTRY_DEBUG"])
|
368
|
+
self.background_worker_threads = (processor_count / 2.0).ceil
|
369
|
+
self.background_worker_max_queue = BackgroundWorker::DEFAULT_MAX_QUEUE
|
324
370
|
self.backtrace_cleanup_callback = nil
|
371
|
+
self.strip_backtrace_load_path = true
|
325
372
|
self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
|
326
373
|
self.breadcrumbs_logger = []
|
327
374
|
self.context_lines = 3
|
@@ -342,8 +389,13 @@ module Sentry
|
|
342
389
|
self.skip_rake_integration = false
|
343
390
|
self.send_client_reports = true
|
344
391
|
self.auto_session_tracking = true
|
392
|
+
self.enable_backpressure_handling = false
|
345
393
|
self.trusted_proxies = []
|
346
|
-
self.dsn = ENV[
|
394
|
+
self.dsn = ENV["SENTRY_DSN"]
|
395
|
+
|
396
|
+
spotlight_env = ENV["SENTRY_SPOTLIGHT"]
|
397
|
+
spotlight_bool = Sentry::Utils::EnvHelper.env_to_bool(spotlight_env, strict: true)
|
398
|
+
self.spotlight = spotlight_bool.nil? ? (spotlight_env || false) : spotlight_bool
|
347
399
|
self.server_name = server_name_from_env
|
348
400
|
self.instrumenter = :sentry
|
349
401
|
self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
|
@@ -355,7 +407,11 @@ module Sentry
|
|
355
407
|
self.traces_sampler = nil
|
356
408
|
self.enable_tracing = nil
|
357
409
|
|
410
|
+
self.profiler_class = Sentry::Profiler
|
411
|
+
|
358
412
|
@transport = Transport::Configuration.new
|
413
|
+
@cron = Cron::Configuration.new
|
414
|
+
@metrics = Metrics::Configuration.new
|
359
415
|
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
360
416
|
|
361
417
|
run_post_initialization_callbacks
|
@@ -444,11 +500,27 @@ module Sentry
|
|
444
500
|
|
445
501
|
def profiles_sample_rate=(profiles_sample_rate)
|
446
502
|
raise ArgumentError, "profiles_sample_rate must be a Numeric or nil" unless is_numeric_or_nil?(profiles_sample_rate)
|
447
|
-
|
503
|
+
log_warn("Please make sure to include the 'stackprof' gem in your Gemfile to use Profiling with Sentry.") unless defined?(StackProf)
|
448
504
|
@profiles_sample_rate = profiles_sample_rate
|
449
505
|
end
|
450
506
|
|
507
|
+
def profiler_class=(profiler_class)
|
508
|
+
if profiler_class == Sentry::Vernier::Profiler
|
509
|
+
begin
|
510
|
+
require "vernier"
|
511
|
+
rescue LoadError
|
512
|
+
raise ArgumentError, "Please add the 'vernier' gem to your Gemfile to use the Vernier profiler with Sentry."
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
@profiler_class = profiler_class
|
517
|
+
end
|
518
|
+
|
451
519
|
def sending_allowed?
|
520
|
+
spotlight || sending_to_dsn_allowed?
|
521
|
+
end
|
522
|
+
|
523
|
+
def sending_to_dsn_allowed?
|
452
524
|
@errors = []
|
453
525
|
|
454
526
|
valid? && capture_in_environment?
|
@@ -460,6 +532,10 @@ module Sentry
|
|
460
532
|
Random.rand < sample_rate
|
461
533
|
end
|
462
534
|
|
535
|
+
def session_tracking?
|
536
|
+
auto_session_tracking && enabled_in_current_env?
|
537
|
+
end
|
538
|
+
|
463
539
|
def exception_class_allowed?(exc)
|
464
540
|
if exc.is_a?(Sentry::Error)
|
465
541
|
# Try to prevent error reporting loops
|
@@ -511,7 +587,8 @@ module Sentry
|
|
511
587
|
app_dirs_pattern: @app_dirs_pattern,
|
512
588
|
linecache: @linecache,
|
513
589
|
context_lines: @context_lines,
|
514
|
-
backtrace_cleanup_callback: @backtrace_cleanup_callback
|
590
|
+
backtrace_cleanup_callback: @backtrace_cleanup_callback,
|
591
|
+
strip_backtrace_load_path: @strip_backtrace_load_path
|
515
592
|
)
|
516
593
|
end
|
517
594
|
|
@@ -536,12 +613,6 @@ module Sentry
|
|
536
613
|
|
537
614
|
private
|
538
615
|
|
539
|
-
def check_callable!(name, value)
|
540
|
-
unless value == nil || value.respond_to?(:call)
|
541
|
-
raise ArgumentError, "#{name} must be callable (or nil to disable)"
|
542
|
-
end
|
543
|
-
end
|
544
|
-
|
545
616
|
def init_dsn(dsn_string)
|
546
617
|
return if dsn_string.nil? || dsn_string.empty?
|
547
618
|
|
@@ -594,12 +665,12 @@ module Sentry
|
|
594
665
|
end
|
595
666
|
|
596
667
|
def environment_from_env
|
597
|
-
ENV[
|
668
|
+
ENV["SENTRY_CURRENT_ENV"] || ENV["SENTRY_ENVIRONMENT"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
598
669
|
end
|
599
670
|
|
600
671
|
def server_name_from_env
|
601
672
|
if running_on_heroku?
|
602
|
-
ENV[
|
673
|
+
ENV["DYNO"]
|
603
674
|
else
|
604
675
|
# Try to resolve the hostname to an FQDN, but fall back to whatever
|
605
676
|
# the load name is.
|
@@ -616,5 +687,10 @@ module Sentry
|
|
616
687
|
instance_eval(&hook)
|
617
688
|
end
|
618
689
|
end
|
690
|
+
|
691
|
+
def processor_count
|
692
|
+
available_processor_count = Concurrent.available_processor_count if Concurrent.respond_to?(:available_processor_count)
|
693
|
+
available_processor_count || Concurrent.processor_count
|
694
|
+
end
|
619
695
|
end
|
620
696
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
module Cron
|
5
|
+
class Configuration
|
6
|
+
# Defaults set here will apply to all {Cron::MonitorConfig} objects unless overwritten.
|
7
|
+
|
8
|
+
# How long (in minutes) after the expected checkin time will we wait
|
9
|
+
# until we consider the checkin to have been missed.
|
10
|
+
# @return [Integer, nil]
|
11
|
+
attr_accessor :default_checkin_margin
|
12
|
+
|
13
|
+
# How long (in minutes) is the checkin allowed to run for in in_progress
|
14
|
+
# before it is considered failed.
|
15
|
+
# @return [Integer, nil]
|
16
|
+
attr_accessor :default_max_runtime
|
17
|
+
|
18
|
+
# tz database style timezone string
|
19
|
+
# @return [String, nil]
|
20
|
+
attr_accessor :default_timezone
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,9 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
module Cron
|
3
5
|
module MonitorCheckIns
|
6
|
+
MAX_SLUG_LENGTH = 50
|
7
|
+
|
4
8
|
module Patch
|
5
|
-
def perform(*args)
|
6
|
-
slug = self.class.sentry_monitor_slug
|
9
|
+
def perform(*args, **opts)
|
10
|
+
slug = self.class.sentry_monitor_slug
|
7
11
|
monitor_config = self.class.sentry_monitor_config
|
8
12
|
|
9
13
|
check_in_id = Sentry.capture_check_in(slug,
|
@@ -11,39 +15,53 @@ module Sentry
|
|
11
15
|
monitor_config: monitor_config)
|
12
16
|
|
13
17
|
start = Sentry.utc_now.to_i
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
18
|
+
|
19
|
+
begin
|
20
|
+
# need to do this on ruby <= 2.6 sadly
|
21
|
+
ret = method(:perform).super_method.arity == 0 ? super() : super
|
22
|
+
duration = Sentry.utc_now.to_i - start
|
23
|
+
|
24
|
+
Sentry.capture_check_in(slug,
|
25
|
+
:ok,
|
26
|
+
check_in_id: check_in_id,
|
27
|
+
duration: duration,
|
28
|
+
monitor_config: monitor_config)
|
29
|
+
|
30
|
+
ret
|
31
|
+
rescue Exception
|
32
|
+
duration = Sentry.utc_now.to_i - start
|
33
|
+
|
34
|
+
Sentry.capture_check_in(slug,
|
35
|
+
:error,
|
36
|
+
check_in_id: check_in_id,
|
37
|
+
duration: duration,
|
38
|
+
monitor_config: monitor_config)
|
39
|
+
|
40
|
+
raise
|
41
|
+
end
|
34
42
|
end
|
35
43
|
end
|
36
44
|
|
37
45
|
module ClassMethods
|
38
46
|
def sentry_monitor_check_ins(slug: nil, monitor_config: nil)
|
47
|
+
if monitor_config && Sentry.configuration
|
48
|
+
cron_config = Sentry.configuration.cron
|
49
|
+
monitor_config.checkin_margin ||= cron_config.default_checkin_margin
|
50
|
+
monitor_config.max_runtime ||= cron_config.default_max_runtime
|
51
|
+
monitor_config.timezone ||= cron_config.default_timezone
|
52
|
+
end
|
53
|
+
|
39
54
|
@sentry_monitor_slug = slug
|
40
55
|
@sentry_monitor_config = monitor_config
|
41
56
|
|
42
57
|
prepend Patch
|
43
58
|
end
|
44
59
|
|
45
|
-
def sentry_monitor_slug
|
46
|
-
@sentry_monitor_slug
|
60
|
+
def sentry_monitor_slug(name: self.name)
|
61
|
+
@sentry_monitor_slug ||= begin
|
62
|
+
slug = name.gsub("::", "-").downcase
|
63
|
+
slug[-MAX_SLUG_LENGTH..-1] || slug
|
64
|
+
end
|
47
65
|
end
|
48
66
|
|
49
67
|
def sentry_monitor_config
|
@@ -51,8 +69,6 @@ module Sentry
|
|
51
69
|
end
|
52
70
|
end
|
53
71
|
|
54
|
-
extend ClassMethods
|
55
|
-
|
56
72
|
def self.included(base)
|
57
73
|
base.extend(ClassMethods)
|
58
74
|
end
|
data/lib/sentry/dsn.rb
CHANGED
@@ -4,8 +4,8 @@ require "uri"
|
|
4
4
|
|
5
5
|
module Sentry
|
6
6
|
class DSN
|
7
|
-
PORT_MAP = {
|
8
|
-
REQUIRED_ATTRIBUTES = %w
|
7
|
+
PORT_MAP = { "http" => 80, "https" => 443 }.freeze
|
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
|
|
@@ -13,7 +13,7 @@ module Sentry
|
|
13
13
|
@raw_value = dsn_string
|
14
14
|
|
15
15
|
uri = URI.parse(dsn_string)
|
16
|
-
uri_path = uri.path.split(
|
16
|
+
uri_path = uri.path.split("/")
|
17
17
|
|
18
18
|
if uri.user
|
19
19
|
# DSN-style string
|
@@ -25,7 +25,7 @@ module Sentry
|
|
25
25
|
@scheme = uri.scheme
|
26
26
|
@host = uri.host
|
27
27
|
@port = uri.port if uri.port
|
28
|
-
@path = uri_path.join(
|
28
|
+
@path = uri_path.join("/")
|
29
29
|
end
|
30
30
|
|
31
31
|
def valid?
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
# @api private
|
5
|
+
class Envelope::Item
|
6
|
+
STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
|
7
|
+
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000
|
8
|
+
|
9
|
+
SIZE_LIMITS = Hash.new(MAX_SERIALIZED_PAYLOAD_SIZE).update(
|
10
|
+
"profile" => 1024 * 1000 * 50
|
11
|
+
)
|
12
|
+
|
13
|
+
attr_reader :size_limit, :headers, :payload, :type, :data_category
|
14
|
+
|
15
|
+
# rate limits and client reports use the data_category rather than envelope item type
|
16
|
+
def self.data_category(type)
|
17
|
+
case type
|
18
|
+
when "session", "attachment", "transaction", "profile", "span" then type
|
19
|
+
when "sessions" then "session"
|
20
|
+
when "check_in" then "monitor"
|
21
|
+
when "statsd", "metric_meta" then "metric_bucket"
|
22
|
+
when "event" then "error"
|
23
|
+
when "client_report" then "internal"
|
24
|
+
else "default"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(headers, payload)
|
29
|
+
@headers = headers
|
30
|
+
@payload = payload
|
31
|
+
@type = headers[:type] || "event"
|
32
|
+
@data_category = self.class.data_category(type)
|
33
|
+
@size_limit = SIZE_LIMITS[type]
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
[JSON.generate(@headers), @payload.is_a?(String) ? @payload : JSON.generate(@payload)].join("\n")
|
38
|
+
end
|
39
|
+
|
40
|
+
def serialize
|
41
|
+
result = to_s
|
42
|
+
|
43
|
+
if result.bytesize > size_limit
|
44
|
+
remove_breadcrumbs!
|
45
|
+
result = to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
if result.bytesize > size_limit
|
49
|
+
reduce_stacktrace!
|
50
|
+
result = to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
[result, result.bytesize > size_limit]
|
54
|
+
end
|
55
|
+
|
56
|
+
def size_breakdown
|
57
|
+
payload.map do |key, value|
|
58
|
+
"#{key}: #{JSON.generate(value).bytesize}"
|
59
|
+
end.join(", ")
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def remove_breadcrumbs!
|
65
|
+
if payload.key?(:breadcrumbs)
|
66
|
+
payload.delete(:breadcrumbs)
|
67
|
+
elsif payload.key?("breadcrumbs")
|
68
|
+
payload.delete("breadcrumbs")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def reduce_stacktrace!
|
73
|
+
if exceptions = payload.dig(:exception, :values) || payload.dig("exception", "values")
|
74
|
+
exceptions.each do |exception|
|
75
|
+
# in most cases there is only one exception (2 or 3 when have multiple causes), so we won't loop through this double condition much
|
76
|
+
traces = exception.dig(:stacktrace, :frames) || exception.dig("stacktrace", "frames")
|
77
|
+
|
78
|
+
if traces && traces.size > STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD
|
79
|
+
size_on_both_ends = STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD / 2
|
80
|
+
traces.replace(
|
81
|
+
traces[0..(size_on_both_ends - 1)] + traces[-size_on_both_ends..-1],
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/sentry/envelope.rb
CHANGED
@@ -3,74 +3,6 @@
|
|
3
3
|
module Sentry
|
4
4
|
# @api private
|
5
5
|
class Envelope
|
6
|
-
class Item
|
7
|
-
STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
|
8
|
-
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000
|
9
|
-
|
10
|
-
attr_accessor :headers, :payload
|
11
|
-
|
12
|
-
def initialize(headers, payload)
|
13
|
-
@headers = headers
|
14
|
-
@payload = payload
|
15
|
-
end
|
16
|
-
|
17
|
-
def type
|
18
|
-
@headers[:type] || 'event'
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_s
|
22
|
-
[JSON.generate(@headers), JSON.generate(@payload)].join("\n")
|
23
|
-
end
|
24
|
-
|
25
|
-
def serialize
|
26
|
-
result = to_s
|
27
|
-
|
28
|
-
if result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE
|
29
|
-
remove_breadcrumbs!
|
30
|
-
result = to_s
|
31
|
-
end
|
32
|
-
|
33
|
-
if result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE
|
34
|
-
reduce_stacktrace!
|
35
|
-
result = to_s
|
36
|
-
end
|
37
|
-
|
38
|
-
[result, result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE]
|
39
|
-
end
|
40
|
-
|
41
|
-
def size_breakdown
|
42
|
-
payload.map do |key, value|
|
43
|
-
"#{key}: #{JSON.generate(value).bytesize}"
|
44
|
-
end.join(", ")
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def remove_breadcrumbs!
|
50
|
-
if payload.key?(:breadcrumbs)
|
51
|
-
payload.delete(:breadcrumbs)
|
52
|
-
elsif payload.key?("breadcrumbs")
|
53
|
-
payload.delete("breadcrumbs")
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def reduce_stacktrace!
|
58
|
-
if exceptions = payload.dig(:exception, :values) || payload.dig("exception", "values")
|
59
|
-
exceptions.each do |exception|
|
60
|
-
# in most cases there is only one exception (2 or 3 when have multiple causes), so we won't loop through this double condition much
|
61
|
-
traces = exception.dig(:stacktrace, :frames) || exception.dig("stacktrace", "frames")
|
62
|
-
|
63
|
-
if traces && traces.size > STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD
|
64
|
-
size_on_both_ends = STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD / 2
|
65
|
-
traces.replace(
|
66
|
-
traces[0..(size_on_both_ends - 1)] + traces[-size_on_both_ends..-1],
|
67
|
-
)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
6
|
attr_accessor :headers, :items
|
75
7
|
|
76
8
|
def initialize(headers = {})
|
@@ -91,3 +23,5 @@ module Sentry
|
|
91
23
|
end
|
92
24
|
end
|
93
25
|
end
|
26
|
+
|
27
|
+
require_relative "envelope/item"
|
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
|