sentry-ruby 5.9.0 → 5.26.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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +3 -1
  3. data/Gemfile +12 -10
  4. data/README.md +26 -11
  5. data/Rakefile +9 -11
  6. data/bin/console +2 -0
  7. data/lib/sentry/attachment.rb +40 -0
  8. data/lib/sentry/background_worker.rb +11 -5
  9. data/lib/sentry/backpressure_monitor.rb +45 -0
  10. data/lib/sentry/backtrace.rb +12 -9
  11. data/lib/sentry/baggage.rb +7 -7
  12. data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
  13. data/lib/sentry/breadcrumb.rb +13 -6
  14. data/lib/sentry/check_in_event.rb +61 -0
  15. data/lib/sentry/client.rb +214 -25
  16. data/lib/sentry/configuration.rb +251 -42
  17. data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
  18. data/lib/sentry/cron/configuration.rb +23 -0
  19. data/lib/sentry/cron/monitor_check_ins.rb +77 -0
  20. data/lib/sentry/cron/monitor_config.rb +53 -0
  21. data/lib/sentry/cron/monitor_schedule.rb +42 -0
  22. data/lib/sentry/dsn.rb +4 -4
  23. data/lib/sentry/envelope/item.rb +88 -0
  24. data/lib/sentry/envelope.rb +2 -68
  25. data/lib/sentry/error_event.rb +2 -2
  26. data/lib/sentry/event.rb +28 -47
  27. data/lib/sentry/excon/middleware.rb +77 -0
  28. data/lib/sentry/excon.rb +10 -0
  29. data/lib/sentry/faraday.rb +77 -0
  30. data/lib/sentry/graphql.rb +9 -0
  31. data/lib/sentry/hub.rb +143 -7
  32. data/lib/sentry/integrable.rb +10 -0
  33. data/lib/sentry/interface.rb +1 -0
  34. data/lib/sentry/interfaces/exception.rb +5 -3
  35. data/lib/sentry/interfaces/mechanism.rb +20 -0
  36. data/lib/sentry/interfaces/request.rb +8 -8
  37. data/lib/sentry/interfaces/single_exception.rb +13 -9
  38. data/lib/sentry/interfaces/stacktrace.rb +3 -1
  39. data/lib/sentry/interfaces/stacktrace_builder.rb +23 -2
  40. data/lib/sentry/linecache.rb +3 -3
  41. data/lib/sentry/log_event.rb +206 -0
  42. data/lib/sentry/log_event_buffer.rb +75 -0
  43. data/lib/sentry/logger.rb +1 -1
  44. data/lib/sentry/metrics/aggregator.rb +248 -0
  45. data/lib/sentry/metrics/configuration.rb +47 -0
  46. data/lib/sentry/metrics/counter_metric.rb +25 -0
  47. data/lib/sentry/metrics/distribution_metric.rb +25 -0
  48. data/lib/sentry/metrics/gauge_metric.rb +35 -0
  49. data/lib/sentry/metrics/local_aggregator.rb +53 -0
  50. data/lib/sentry/metrics/metric.rb +19 -0
  51. data/lib/sentry/metrics/set_metric.rb +28 -0
  52. data/lib/sentry/metrics/timing.rb +51 -0
  53. data/lib/sentry/metrics.rb +56 -0
  54. data/lib/sentry/net/http.rb +28 -42
  55. data/lib/sentry/profiler/helpers.rb +46 -0
  56. data/lib/sentry/profiler.rb +41 -60
  57. data/lib/sentry/propagation_context.rb +135 -0
  58. data/lib/sentry/puma.rb +12 -5
  59. data/lib/sentry/rack/capture_exceptions.rb +17 -8
  60. data/lib/sentry/rack.rb +2 -2
  61. data/lib/sentry/rake.rb +4 -15
  62. data/lib/sentry/redis.rb +11 -4
  63. data/lib/sentry/release_detector.rb +5 -5
  64. data/lib/sentry/rspec.rb +91 -0
  65. data/lib/sentry/scope.rb +75 -39
  66. data/lib/sentry/session.rb +2 -2
  67. data/lib/sentry/session_flusher.rb +15 -43
  68. data/lib/sentry/span.rb +92 -8
  69. data/lib/sentry/std_lib_logger.rb +50 -0
  70. data/lib/sentry/structured_logger.rb +138 -0
  71. data/lib/sentry/test_helper.rb +42 -13
  72. data/lib/sentry/threaded_periodic_worker.rb +39 -0
  73. data/lib/sentry/transaction.rb +44 -43
  74. data/lib/sentry/transaction_event.rb +10 -6
  75. data/lib/sentry/transport/configuration.rb +73 -1
  76. data/lib/sentry/transport/http_transport.rb +71 -41
  77. data/lib/sentry/transport/spotlight_transport.rb +50 -0
  78. data/lib/sentry/transport.rb +53 -49
  79. data/lib/sentry/utils/argument_checking_helper.rb +15 -3
  80. data/lib/sentry/utils/env_helper.rb +21 -0
  81. data/lib/sentry/utils/http_tracing.rb +74 -0
  82. data/lib/sentry/utils/logging_helper.rb +10 -7
  83. data/lib/sentry/utils/real_ip.rb +2 -2
  84. data/lib/sentry/utils/request_id.rb +1 -1
  85. data/lib/sentry/utils/uuid.rb +13 -0
  86. data/lib/sentry/vernier/output.rb +89 -0
  87. data/lib/sentry/vernier/profiler.rb +132 -0
  88. data/lib/sentry/version.rb +1 -1
  89. data/lib/sentry-ruby.rb +206 -35
  90. data/sentry-ruby-core.gemspec +3 -1
  91. data/sentry-ruby.gemspec +15 -6
  92. metadata +61 -12
  93. data/CODE_OF_CONDUCT.md +0 -74
@@ -3,21 +3,30 @@
3
3
  require "concurrent/utility/processor_counter"
4
4
 
5
5
  require "sentry/utils/exception_cause_chain"
6
- require 'sentry/utils/custom_inspection'
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"
15
+ require "sentry/logger"
16
+ require "sentry/log_event_buffer"
12
17
 
13
18
  module Sentry
14
19
  class Configuration
15
20
  include CustomInspection
16
21
  include LoggingHelper
22
+ include ArgumentCheckingHelper
23
+
17
24
  # Directories to be recognized as part of your app. e.g. if you
18
25
  # have an `engines` dir at the root of your project, you may want
19
26
  # to set this to something like /(app|config|engines|lib)/
20
27
  #
28
+ # The default is value is /(bin|exe|app|config|lib|test|spec)/
29
+ #
21
30
  # @return [Regexp, nil]
22
31
  attr_accessor :app_dirs_pattern
23
32
 
@@ -38,6 +47,13 @@ module Sentry
38
47
  # @return [Integer]
39
48
  attr_accessor :background_worker_threads
40
49
 
50
+ # The maximum queue size for the background worker.
51
+ # Jobs will be rejected above this limit.
52
+ #
53
+ # Default is {BackgroundWorker::DEFAULT_MAX_QUEUE}.
54
+ # @return [Integer]
55
+ attr_accessor :background_worker_max_queue
56
+
41
57
  # a proc/lambda that takes an array of stack traces
42
58
  # it'll be used to silence (reduce) backtrace of the exception
43
59
  #
@@ -85,6 +101,15 @@ module Sentry
85
101
  # @return [Proc]
86
102
  attr_reader :before_send_transaction
87
103
 
104
+ # Optional Proc, called before sending an event to the server
105
+ # @example
106
+ # config.before_send_log = lambda do |log|
107
+ # log.attributes["sentry"] = true
108
+ # log
109
+ # end
110
+ # @return [Proc]
111
+ attr_accessor :before_send_log
112
+
88
113
  # An array of breadcrumbs loggers to be used. Available options are:
89
114
  # - :sentry_logger
90
115
  # - :http_logger
@@ -140,6 +165,14 @@ module Sentry
140
165
  # @return [Boolean]
141
166
  attr_accessor :include_local_variables
142
167
 
168
+ # Whether to capture events and traces into Spotlight. Default is false.
169
+ # If you set this to true, Sentry will send events and traces to the local
170
+ # Sidecar proxy at http://localhost:8969/stream.
171
+ # If you want to use a different Sidecar proxy address, set this to String
172
+ # with the proxy URL.
173
+ # @return [Boolean, String]
174
+ attr_accessor :spotlight
175
+
143
176
  # @deprecated Use {#include_local_variables} instead.
144
177
  alias_method :capture_exception_frame_locals, :include_local_variables
145
178
 
@@ -161,13 +194,30 @@ module Sentry
161
194
  # Logger used by Sentry. In Rails, this is the Rails logger, otherwise
162
195
  # Sentry provides its own Sentry::Logger.
163
196
  # @return [Logger]
164
- attr_accessor :logger
197
+ attr_accessor :sdk_logger
198
+
199
+ # @deprecated Use {#sdk_logger=} instead.
200
+ def logger=(logger)
201
+ warn "[sentry] `config.logger=` is deprecated. Please use `config.sdk_logger=` instead."
202
+ self.sdk_logger = logger
203
+ end
204
+
205
+ # @deprecated Use {#sdk_logger} instead.
206
+ def logger
207
+ warn "[sentry] `config.logger` is deprecated. Please use `config.sdk_logger` instead."
208
+ self.sdk_logger
209
+ end
165
210
 
166
211
  # Project directory root for in_app detection. Could be Rails root, etc.
167
212
  # Set automatically for Rails.
168
213
  # @return [String]
169
214
  attr_accessor :project_root
170
215
 
216
+ # Whether to strip the load path while constructing the backtrace frame filename.
217
+ # Defaults to true.
218
+ # @return [Boolean]
219
+ attr_accessor :strip_backtrace_load_path
220
+
171
221
  # Insert sentry-trace to outgoing requests' headers
172
222
  # @return [Boolean]
173
223
  attr_accessor :propagate_traces
@@ -179,7 +229,7 @@ module Sentry
179
229
  # Release tag to be passed with every event sent to Sentry.
180
230
  # We automatically try to set this to a git SHA or Capistrano release.
181
231
  # @return [String]
182
- attr_accessor :release
232
+ attr_reader :release
183
233
 
184
234
  # The sampling factor to apply to events. A value of 0.0 will not send
185
235
  # any events, and a value of 1.0 will send 100% of events.
@@ -209,13 +259,21 @@ module Sentry
209
259
  # @return [String]
210
260
  attr_accessor :server_name
211
261
 
212
- # Return a Transport::Configuration object for transport-related configurations.
213
- # @return [Transport]
262
+ # Transport related configuration.
263
+ # @return [Transport::Configuration]
214
264
  attr_reader :transport
215
265
 
266
+ # Cron related configuration.
267
+ # @return [Cron::Configuration]
268
+ attr_reader :cron
269
+
270
+ # Metrics related configuration.
271
+ # @return [Metrics::Configuration]
272
+ attr_reader :metrics
273
+
216
274
  # Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
217
- # @return [Float]
218
- attr_accessor :traces_sample_rate
275
+ # @return [Float, nil]
276
+ attr_reader :traces_sample_rate
219
277
 
220
278
  # Take a Proc that controls the sample rate for every tracing event, e.g.
221
279
  # @example
@@ -227,8 +285,13 @@ module Sentry
227
285
  # @return [Proc]
228
286
  attr_accessor :traces_sampler
229
287
 
288
+ # Enable Structured Logging
289
+ # @return [Boolean]
290
+ attr_accessor :enable_logs
291
+
230
292
  # Easier way to use performance tracing
231
293
  # If set to true, will set traces_sample_rate to 1.0
294
+ # @deprecated It will be removed in the next major release.
232
295
  # @return [Boolean, nil]
233
296
  attr_reader :enable_tracing
234
297
 
@@ -241,44 +304,83 @@ module Sentry
241
304
  # @return [Boolean]
242
305
  attr_accessor :auto_session_tracking
243
306
 
307
+ # Whether to downsample transactions automatically because of backpressure.
308
+ # Starts a new monitor thread to check health of the SDK every 10 seconds.
309
+ # Default is false
310
+ # @return [Boolean]
311
+ attr_accessor :enable_backpressure_handling
312
+
313
+ # Allowlist of outgoing request targets to which sentry-trace and baggage headers are attached.
314
+ # Default is all (/.*/)
315
+ # @return [Array<String, Regexp>]
316
+ attr_accessor :trace_propagation_targets
317
+
244
318
  # The instrumenter to use, :sentry or :otel
245
319
  # @return [Symbol]
246
320
  attr_reader :instrumenter
247
321
 
322
+ # The profiler class
323
+ # @return [Class]
324
+ attr_reader :profiler_class
325
+
248
326
  # Take a float between 0.0 and 1.0 as the sample rate for capturing profiles.
249
327
  # Note that this rate is relative to traces_sample_rate / traces_sampler,
250
328
  # i.e. the profile is sampled by this rate after the transaction is sampled.
251
329
  # @return [Float, nil]
252
330
  attr_reader :profiles_sample_rate
253
331
 
332
+ # Array of patches to apply.
333
+ # Default is {DEFAULT_PATCHES}
334
+ # @return [Array<Symbol>]
335
+ attr_accessor :enabled_patches
336
+
337
+ # Maximum number of log events to buffer before sending
338
+ # @return [Integer]
339
+ attr_accessor :max_log_events
340
+
254
341
  # these are not config options
255
342
  # @!visibility private
256
343
  attr_reader :errors, :gem_specs
257
344
 
345
+ # These exceptions could enter Puma's `lowlevel_error_handler` callback and the SDK's Puma integration
346
+ # But they are mostly considered as noise and should be ignored by default
347
+ # Please see https://github.com/getsentry/sentry-ruby/pull/2026 for more information
348
+ PUMA_IGNORE_DEFAULT = [
349
+ "Puma::MiniSSL::SSLError",
350
+ "Puma::HttpParserError",
351
+ "Puma::HttpParserError501"
352
+ ].freeze
353
+
258
354
  # Most of these errors generate 4XX responses. In general, Sentry clients
259
355
  # only automatically report 5xx responses.
260
356
  IGNORE_DEFAULT = [
261
- 'Mongoid::Errors::DocumentNotFound',
262
- 'Rack::QueryParser::InvalidParameterError',
263
- 'Rack::QueryParser::ParameterTypeError',
264
- 'Sinatra::NotFound'
357
+ "Mongoid::Errors::DocumentNotFound",
358
+ "Rack::QueryParser::InvalidParameterError",
359
+ "Rack::QueryParser::ParameterTypeError",
360
+ "Sinatra::NotFound"
265
361
  ].freeze
266
362
 
267
- RACK_ENV_WHITELIST_DEFAULT = %w(
363
+ RACK_ENV_WHITELIST_DEFAULT = %w[
268
364
  REMOTE_ADDR
269
365
  SERVER_NAME
270
366
  SERVER_PORT
271
- ).freeze
367
+ ].freeze
272
368
 
273
369
  HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
274
- "release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`".freeze
370
+ "release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
275
371
 
276
- LOG_PREFIX = "** [Sentry] ".freeze
277
- MODULE_SEPARATOR = "::".freeze
372
+ LOG_PREFIX = "** [Sentry] "
373
+ MODULE_SEPARATOR = "::"
278
374
  SKIP_INSPECTION_ATTRIBUTES = [:@linecache, :@stacktrace_builder]
279
375
 
280
376
  INSTRUMENTERS = [:sentry, :otel]
281
377
 
378
+ PROPAGATION_TARGETS_MATCH_ALL = /.*/
379
+
380
+ DEFAULT_PATCHES = %i[redis puma http].freeze
381
+
382
+ APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/
383
+
282
384
  class << self
283
385
  # Post initialization callbacks are called at the end of initialization process
284
386
  # allowing extending the configuration of sentry-ruby by multiple extensions
@@ -286,17 +388,58 @@ module Sentry
286
388
  @post_initialization_callbacks ||= []
287
389
  end
288
390
 
289
- # allow extensions to add their hooks to the Configuration class
391
+ # allow extensions to add their hooks to the Configuration class
290
392
  def add_post_initialization_callback(&block)
291
393
  post_initialization_callbacks << block
292
394
  end
395
+
396
+ def validations
397
+ @validations ||= {}
398
+ end
399
+
400
+ def validate(attribute, optional: false, type: nil)
401
+ validations[attribute] = {
402
+ optional: optional,
403
+ type: type,
404
+ proc: build_validation_proc(optional, type)
405
+ }
406
+ end
407
+
408
+ private
409
+
410
+ def build_validation_proc(optional, type)
411
+ case type
412
+ when :numeric
413
+ ->(value) do
414
+ if optional && value.nil?
415
+ true
416
+ else
417
+ unless value.is_a?(Numeric)
418
+ message = "must be a Numeric"
419
+ message += " or nil" if optional
420
+
421
+ { error: message, value: value }
422
+ else
423
+ true
424
+ end
425
+ end
426
+ end
427
+ else
428
+ ->(value) { true }
429
+ end
430
+ end
293
431
  end
294
432
 
433
+ validate :traces_sample_rate, optional: true, type: :numeric
434
+ validate :profiles_sample_rate, optional: true, type: :numeric
435
+
295
436
  def initialize
296
- self.app_dirs_pattern = nil
297
- self.debug = false
298
- self.background_worker_threads = Concurrent.processor_count
437
+ self.app_dirs_pattern = APP_DIRS_PATTERN
438
+ self.debug = Sentry::Utils::EnvHelper.env_to_bool(ENV["SENTRY_DEBUG"])
439
+ self.background_worker_threads = (processor_count / 2.0).ceil
440
+ self.background_worker_max_queue = BackgroundWorker::DEFAULT_MAX_QUEUE
299
441
  self.backtrace_cleanup_callback = nil
442
+ self.strip_backtrace_load_path = true
300
443
  self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
301
444
  self.breadcrumbs_logger = []
302
445
  self.context_lines = 3
@@ -304,10 +447,10 @@ module Sentry
304
447
  self.environment = environment_from_env
305
448
  self.enabled_environments = []
306
449
  self.exclude_loggers = []
307
- self.excluded_exceptions = IGNORE_DEFAULT.dup
450
+ self.excluded_exceptions = IGNORE_DEFAULT + PUMA_IGNORE_DEFAULT
308
451
  self.inspect_exception_causes_for_exclusion = true
309
452
  self.linecache = ::Sentry::LineCache.new
310
- self.logger = ::Sentry::Logger.new(STDOUT)
453
+ self.sdk_logger = ::Sentry::Logger.new(STDOUT)
311
454
  self.project_root = Dir.pwd
312
455
  self.propagate_traces = true
313
456
 
@@ -317,22 +460,54 @@ module Sentry
317
460
  self.skip_rake_integration = false
318
461
  self.send_client_reports = true
319
462
  self.auto_session_tracking = true
463
+ self.enable_backpressure_handling = false
320
464
  self.trusted_proxies = []
321
- self.dsn = ENV['SENTRY_DSN']
465
+ self.dsn = ENV["SENTRY_DSN"]
466
+
467
+ spotlight_env = ENV["SENTRY_SPOTLIGHT"]
468
+ spotlight_bool = Sentry::Utils::EnvHelper.env_to_bool(spotlight_env, strict: true)
469
+ self.spotlight = spotlight_bool.nil? ? (spotlight_env || false) : spotlight_bool
322
470
  self.server_name = server_name_from_env
323
471
  self.instrumenter = :sentry
472
+ self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
473
+ self.enabled_patches = DEFAULT_PATCHES.dup
324
474
 
325
475
  self.before_send = nil
326
476
  self.before_send_transaction = nil
477
+ self.before_send_log = nil
327
478
  self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
328
- self.traces_sample_rate = nil
329
479
  self.traces_sampler = nil
330
480
  self.enable_tracing = nil
481
+ self.enable_logs = false
482
+
483
+ self.profiler_class = Sentry::Profiler
331
484
 
332
485
  @transport = Transport::Configuration.new
486
+ @cron = Cron::Configuration.new
487
+ @metrics = Metrics::Configuration.new
333
488
  @gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
334
489
 
335
490
  run_post_initialization_callbacks
491
+
492
+ self.max_log_events = LogEventBuffer::DEFAULT_MAX_EVENTS
493
+ end
494
+
495
+ def validate
496
+ if profiler_class == Sentry::Profiler && profiles_sample_rate && !Sentry.dependency_installed?(:StackProf)
497
+ log_warn("Please add the 'stackprof' gem to your Gemfile to use the StackProf profiler with Sentry.")
498
+ end
499
+
500
+ if profiler_class == Sentry::Vernier::Profiler && profiles_sample_rate && !Sentry.dependency_installed?(:Vernier)
501
+ log_warn("Please add the 'vernier' gem to your Gemfile to use the Vernier profiler with Sentry.")
502
+ end
503
+
504
+ self.class.validations.each do |attribute, validation|
505
+ value = public_send(attribute)
506
+
507
+ next if (result = validation[:proc].call(value)) === true
508
+
509
+ raise ArgumentError, result[:error]
510
+ end
336
511
  end
337
512
 
338
513
  def dsn=(value)
@@ -341,6 +516,12 @@ module Sentry
341
516
 
342
517
  alias server= dsn=
343
518
 
519
+ def release=(value)
520
+ check_argument_type!(value, String, NilClass)
521
+
522
+ @release = value
523
+ end
524
+
344
525
  def async=(value)
345
526
  check_callable!("async", value)
346
527
 
@@ -397,16 +578,40 @@ module Sentry
397
578
  end
398
579
 
399
580
  def enable_tracing=(enable_tracing)
581
+ unless enable_tracing.nil?
582
+ log_warn <<~MSG
583
+ `enable_tracing` is now deprecated in favor of `traces_sample_rate = 1.0`.
584
+ MSG
585
+ end
586
+
400
587
  @enable_tracing = enable_tracing
401
588
  @traces_sample_rate ||= 1.0 if enable_tracing
402
589
  end
403
590
 
591
+ def traces_sample_rate=(traces_sample_rate)
592
+ @traces_sample_rate = traces_sample_rate
593
+ end
594
+
404
595
  def profiles_sample_rate=(profiles_sample_rate)
405
- log_info("Please make sure to include the 'stackprof' gem in your Gemfile to use Profiling with Sentry.") unless defined?(StackProf)
406
596
  @profiles_sample_rate = profiles_sample_rate
407
597
  end
408
598
 
599
+ def profiler_class=(profiler_class)
600
+ if profiler_class == Sentry::Vernier::Profiler
601
+ begin
602
+ require "vernier"
603
+ rescue LoadError
604
+ end
605
+ end
606
+
607
+ @profiler_class = profiler_class
608
+ end
609
+
409
610
  def sending_allowed?
611
+ spotlight || sending_to_dsn_allowed?
612
+ end
613
+
614
+ def sending_to_dsn_allowed?
410
615
  @errors = []
411
616
 
412
617
  valid? && capture_in_environment?
@@ -418,6 +623,10 @@ module Sentry
418
623
  Random.rand < sample_rate
419
624
  end
420
625
 
626
+ def session_tracking?
627
+ auto_session_tracking && enabled_in_current_env?
628
+ end
629
+
421
630
  def exception_class_allowed?(exc)
422
631
  if exc.is_a?(Sentry::Error)
423
632
  # Try to prevent error reporting loops
@@ -435,19 +644,19 @@ module Sentry
435
644
  enabled_environments.empty? || enabled_environments.include?(environment)
436
645
  end
437
646
 
647
+ def valid_sample_rate?(sample_rate)
648
+ return false unless sample_rate.is_a?(Numeric)
649
+ sample_rate >= 0.0 && sample_rate <= 1.0
650
+ end
651
+
438
652
  def tracing_enabled?
439
- valid_sampler = !!((@traces_sample_rate &&
440
- @traces_sample_rate >= 0.0 &&
441
- @traces_sample_rate <= 1.0) ||
442
- @traces_sampler)
653
+ valid_sampler = !!((valid_sample_rate?(@traces_sample_rate)) || @traces_sampler)
443
654
 
444
655
  (@enable_tracing != false) && valid_sampler && sending_allowed?
445
656
  end
446
657
 
447
658
  def profiling_enabled?
448
- valid_sampler = !!(@profiles_sample_rate &&
449
- @profiles_sample_rate >= 0.0 &&
450
- @profiles_sample_rate <= 1.0)
659
+ valid_sampler = !!(valid_sample_rate?(@profiles_sample_rate))
451
660
 
452
661
  tracing_enabled? && valid_sampler && sending_allowed?
453
662
  end
@@ -469,7 +678,8 @@ module Sentry
469
678
  app_dirs_pattern: @app_dirs_pattern,
470
679
  linecache: @linecache,
471
680
  context_lines: @context_lines,
472
- backtrace_cleanup_callback: @backtrace_cleanup_callback
681
+ backtrace_cleanup_callback: @backtrace_cleanup_callback,
682
+ strip_backtrace_load_path: @strip_backtrace_load_path
473
683
  )
474
684
  end
475
685
 
@@ -477,7 +687,7 @@ module Sentry
477
687
  def detect_release
478
688
  return unless sending_allowed?
479
689
 
480
- self.release ||= ReleaseDetector.detect_release(project_root: project_root, running_on_heroku: running_on_heroku?)
690
+ @release ||= ReleaseDetector.detect_release(project_root: project_root, running_on_heroku: running_on_heroku?)
481
691
 
482
692
  if running_on_heroku? && release.nil?
483
693
  log_warn(HEROKU_DYNO_METADATA_MESSAGE)
@@ -494,12 +704,6 @@ module Sentry
494
704
 
495
705
  private
496
706
 
497
- def check_callable!(name, value)
498
- unless value == nil || value.respond_to?(:call)
499
- raise ArgumentError, "#{name} must be callable (or nil to disable)"
500
- end
501
- end
502
-
503
707
  def init_dsn(dsn_string)
504
708
  return if dsn_string.nil? || dsn_string.empty?
505
709
 
@@ -552,12 +756,12 @@ module Sentry
552
756
  end
553
757
 
554
758
  def environment_from_env
555
- ENV['SENTRY_CURRENT_ENV'] || ENV['SENTRY_ENVIRONMENT'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
759
+ ENV["SENTRY_CURRENT_ENV"] || ENV["SENTRY_ENVIRONMENT"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
556
760
  end
557
761
 
558
762
  def server_name_from_env
559
763
  if running_on_heroku?
560
- ENV['DYNO']
764
+ ENV["DYNO"]
561
765
  else
562
766
  # Try to resolve the hostname to an FQDN, but fall back to whatever
563
767
  # the load name is.
@@ -574,5 +778,10 @@ module Sentry
574
778
  instance_eval(&hook)
575
779
  end
576
780
  end
781
+
782
+ def processor_count
783
+ available_processor_count = Concurrent.available_processor_count if Concurrent.respond_to?(:available_processor_count)
784
+ available_processor_count || Concurrent.processor_count
785
+ end
577
786
  end
578
787
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  return if Object.method_defined?(:deep_dup)
4
4
 
5
- require 'sentry/core_ext/object/duplicable'
5
+ require "sentry/core_ext/object/duplicable"
6
6
 
7
7
  #########################################
8
8
  # This file was copied from Rails 5.2 #
@@ -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
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ module Cron
5
+ module MonitorCheckIns
6
+ MAX_SLUG_LENGTH = 50
7
+
8
+ module Patch
9
+ def perform(*args, **opts)
10
+ slug = self.class.sentry_monitor_slug
11
+ monitor_config = self.class.sentry_monitor_config
12
+
13
+ check_in_id = Sentry.capture_check_in(slug,
14
+ :in_progress,
15
+ monitor_config: monitor_config)
16
+
17
+ start = Metrics::Timing.duration_start
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 = Metrics::Timing.duration_end(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 = Metrics::Timing.duration_end(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
42
+ end
43
+ end
44
+
45
+ module ClassMethods
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
+
54
+ @sentry_monitor_slug = slug
55
+ @sentry_monitor_config = monitor_config
56
+
57
+ prepend Patch
58
+ end
59
+
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
65
+ end
66
+
67
+ def sentry_monitor_config
68
+ @sentry_monitor_config
69
+ end
70
+ end
71
+
72
+ def self.included(base)
73
+ base.extend(ClassMethods)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sentry/cron/monitor_schedule"
4
+
5
+ module Sentry
6
+ module Cron
7
+ class MonitorConfig
8
+ # The monitor schedule configuration
9
+ # @return [MonitorSchedule::Crontab, MonitorSchedule::Interval]
10
+ attr_accessor :schedule
11
+
12
+ # How long (in minutes) after the expected checkin time will we wait
13
+ # until we consider the checkin to have been missed.
14
+ # @return [Integer, nil]
15
+ attr_accessor :checkin_margin
16
+
17
+ # How long (in minutes) is the checkin allowed to run for in in_progress
18
+ # before it is considered failed.
19
+ # @return [Integer, nil]
20
+ attr_accessor :max_runtime
21
+
22
+ # tz database style timezone string
23
+ # @return [String, nil]
24
+ attr_accessor :timezone
25
+
26
+ def initialize(schedule, checkin_margin: nil, max_runtime: nil, timezone: nil)
27
+ @schedule = schedule
28
+ @checkin_margin = checkin_margin
29
+ @max_runtime = max_runtime
30
+ @timezone = timezone
31
+ end
32
+
33
+ def self.from_crontab(crontab, **options)
34
+ new(MonitorSchedule::Crontab.new(crontab), **options)
35
+ end
36
+
37
+ def self.from_interval(num, unit, **options)
38
+ return nil unless MonitorSchedule::Interval::VALID_UNITS.include?(unit)
39
+
40
+ new(MonitorSchedule::Interval.new(num, unit), **options)
41
+ end
42
+
43
+ def to_hash
44
+ {
45
+ schedule: schedule.to_hash,
46
+ checkin_margin: checkin_margin,
47
+ max_runtime: max_runtime,
48
+ timezone: timezone
49
+ }.compact
50
+ end
51
+ end
52
+ end
53
+ end