sentry-ruby 5.10.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.
- checksums.yaml +4 -4
- data/.rspec +3 -1
- data/Gemfile +12 -13
- data/README.md +26 -11
- data/Rakefile +9 -11
- data/bin/console +2 -0
- data/lib/sentry/attachment.rb +40 -0
- data/lib/sentry/background_worker.rb +11 -5
- data/lib/sentry/backpressure_monitor.rb +45 -0
- data/lib/sentry/backtrace.rb +12 -9
- data/lib/sentry/baggage.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
- data/lib/sentry/breadcrumb.rb +13 -6
- data/lib/sentry/check_in_event.rb +61 -0
- data/lib/sentry/client.rb +214 -25
- data/lib/sentry/configuration.rb +221 -38
- 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 +77 -0
- data/lib/sentry/cron/monitor_config.rb +53 -0
- data/lib/sentry/cron/monitor_schedule.rb +42 -0
- 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 +28 -47
- data/lib/sentry/excon/middleware.rb +77 -0
- data/lib/sentry/excon.rb +10 -0
- data/lib/sentry/faraday.rb +77 -0
- data/lib/sentry/graphql.rb +9 -0
- data/lib/sentry/hub.rb +138 -6
- data/lib/sentry/integrable.rb +10 -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 +8 -8
- data/lib/sentry/interfaces/single_exception.rb +13 -9
- data/lib/sentry/interfaces/stacktrace.rb +3 -1
- data/lib/sentry/interfaces/stacktrace_builder.rb +23 -2
- data/lib/sentry/linecache.rb +3 -3
- data/lib/sentry/log_event.rb +206 -0
- data/lib/sentry/log_event_buffer.rb +75 -0
- 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 +51 -0
- data/lib/sentry/metrics.rb +56 -0
- data/lib/sentry/net/http.rb +27 -44
- data/lib/sentry/profiler/helpers.rb +46 -0
- data/lib/sentry/profiler.rb +41 -60
- data/lib/sentry/propagation_context.rb +135 -0
- data/lib/sentry/puma.rb +12 -5
- data/lib/sentry/rack/capture_exceptions.rb +17 -8
- data/lib/sentry/rack.rb +2 -2
- data/lib/sentry/rake.rb +4 -15
- data/lib/sentry/redis.rb +10 -4
- data/lib/sentry/release_detector.rb +5 -5
- data/lib/sentry/rspec.rb +91 -0
- data/lib/sentry/scope.rb +75 -39
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +15 -43
- data/lib/sentry/span.rb +92 -8
- data/lib/sentry/std_lib_logger.rb +50 -0
- data/lib/sentry/structured_logger.rb +138 -0
- data/lib/sentry/test_helper.rb +42 -13
- data/lib/sentry/threaded_periodic_worker.rb +39 -0
- data/lib/sentry/transaction.rb +44 -43
- data/lib/sentry/transaction_event.rb +10 -6
- data/lib/sentry/transport/configuration.rb +73 -1
- data/lib/sentry/transport/http_transport.rb +71 -41
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +53 -49
- data/lib/sentry/utils/argument_checking_helper.rb +12 -0
- data/lib/sentry/utils/env_helper.rb +21 -0
- data/lib/sentry/utils/http_tracing.rb +74 -0
- data/lib/sentry/utils/logging_helper.rb +10 -7
- data/lib/sentry/utils/real_ip.rb +2 -2
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/utils/uuid.rb +13 -0
- data/lib/sentry/vernier/output.rb +89 -0
- data/lib/sentry/vernier/profiler.rb +132 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +206 -35
- data/sentry-ruby-core.gemspec +3 -1
- data/sentry-ruby.gemspec +15 -6
- metadata +61 -11
data/lib/sentry/configuration.rb
CHANGED
@@ -3,12 +3,17 @@
|
|
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"
|
15
|
+
require "sentry/logger"
|
16
|
+
require "sentry/log_event_buffer"
|
12
17
|
|
13
18
|
module Sentry
|
14
19
|
class Configuration
|
@@ -20,6 +25,8 @@ module Sentry
|
|
20
25
|
# have an `engines` dir at the root of your project, you may want
|
21
26
|
# to set this to something like /(app|config|engines|lib)/
|
22
27
|
#
|
28
|
+
# The default is value is /(bin|exe|app|config|lib|test|spec)/
|
29
|
+
#
|
23
30
|
# @return [Regexp, nil]
|
24
31
|
attr_accessor :app_dirs_pattern
|
25
32
|
|
@@ -40,6 +47,13 @@ module Sentry
|
|
40
47
|
# @return [Integer]
|
41
48
|
attr_accessor :background_worker_threads
|
42
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
|
+
|
43
57
|
# a proc/lambda that takes an array of stack traces
|
44
58
|
# it'll be used to silence (reduce) backtrace of the exception
|
45
59
|
#
|
@@ -87,6 +101,15 @@ module Sentry
|
|
87
101
|
# @return [Proc]
|
88
102
|
attr_reader :before_send_transaction
|
89
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
|
+
|
90
113
|
# An array of breadcrumbs loggers to be used. Available options are:
|
91
114
|
# - :sentry_logger
|
92
115
|
# - :http_logger
|
@@ -142,6 +165,14 @@ module Sentry
|
|
142
165
|
# @return [Boolean]
|
143
166
|
attr_accessor :include_local_variables
|
144
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
|
+
|
145
176
|
# @deprecated Use {#include_local_variables} instead.
|
146
177
|
alias_method :capture_exception_frame_locals, :include_local_variables
|
147
178
|
|
@@ -163,13 +194,30 @@ module Sentry
|
|
163
194
|
# Logger used by Sentry. In Rails, this is the Rails logger, otherwise
|
164
195
|
# Sentry provides its own Sentry::Logger.
|
165
196
|
# @return [Logger]
|
166
|
-
attr_accessor :
|
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
|
167
210
|
|
168
211
|
# Project directory root for in_app detection. Could be Rails root, etc.
|
169
212
|
# Set automatically for Rails.
|
170
213
|
# @return [String]
|
171
214
|
attr_accessor :project_root
|
172
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
|
+
|
173
221
|
# Insert sentry-trace to outgoing requests' headers
|
174
222
|
# @return [Boolean]
|
175
223
|
attr_accessor :propagate_traces
|
@@ -211,10 +259,18 @@ module Sentry
|
|
211
259
|
# @return [String]
|
212
260
|
attr_accessor :server_name
|
213
261
|
|
214
|
-
#
|
215
|
-
# @return [Transport]
|
262
|
+
# Transport related configuration.
|
263
|
+
# @return [Transport::Configuration]
|
216
264
|
attr_reader :transport
|
217
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
|
+
|
218
274
|
# Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
|
219
275
|
# @return [Float, nil]
|
220
276
|
attr_reader :traces_sample_rate
|
@@ -229,8 +285,13 @@ module Sentry
|
|
229
285
|
# @return [Proc]
|
230
286
|
attr_accessor :traces_sampler
|
231
287
|
|
288
|
+
# Enable Structured Logging
|
289
|
+
# @return [Boolean]
|
290
|
+
attr_accessor :enable_logs
|
291
|
+
|
232
292
|
# Easier way to use performance tracing
|
233
293
|
# If set to true, will set traces_sample_rate to 1.0
|
294
|
+
# @deprecated It will be removed in the next major release.
|
234
295
|
# @return [Boolean, nil]
|
235
296
|
attr_reader :enable_tracing
|
236
297
|
|
@@ -243,16 +304,40 @@ module Sentry
|
|
243
304
|
# @return [Boolean]
|
244
305
|
attr_accessor :auto_session_tracking
|
245
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
|
+
|
246
318
|
# The instrumenter to use, :sentry or :otel
|
247
319
|
# @return [Symbol]
|
248
320
|
attr_reader :instrumenter
|
249
321
|
|
322
|
+
# The profiler class
|
323
|
+
# @return [Class]
|
324
|
+
attr_reader :profiler_class
|
325
|
+
|
250
326
|
# Take a float between 0.0 and 1.0 as the sample rate for capturing profiles.
|
251
327
|
# Note that this rate is relative to traces_sample_rate / traces_sampler,
|
252
328
|
# i.e. the profile is sampled by this rate after the transaction is sampled.
|
253
329
|
# @return [Float, nil]
|
254
330
|
attr_reader :profiles_sample_rate
|
255
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
|
+
|
256
341
|
# these are not config options
|
257
342
|
# @!visibility private
|
258
343
|
attr_reader :errors, :gem_specs
|
@@ -261,35 +346,41 @@ module Sentry
|
|
261
346
|
# But they are mostly considered as noise and should be ignored by default
|
262
347
|
# Please see https://github.com/getsentry/sentry-ruby/pull/2026 for more information
|
263
348
|
PUMA_IGNORE_DEFAULT = [
|
264
|
-
|
265
|
-
|
266
|
-
|
349
|
+
"Puma::MiniSSL::SSLError",
|
350
|
+
"Puma::HttpParserError",
|
351
|
+
"Puma::HttpParserError501"
|
267
352
|
].freeze
|
268
353
|
|
269
354
|
# Most of these errors generate 4XX responses. In general, Sentry clients
|
270
355
|
# only automatically report 5xx responses.
|
271
356
|
IGNORE_DEFAULT = [
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
357
|
+
"Mongoid::Errors::DocumentNotFound",
|
358
|
+
"Rack::QueryParser::InvalidParameterError",
|
359
|
+
"Rack::QueryParser::ParameterTypeError",
|
360
|
+
"Sinatra::NotFound"
|
276
361
|
].freeze
|
277
362
|
|
278
|
-
RACK_ENV_WHITELIST_DEFAULT = %w
|
363
|
+
RACK_ENV_WHITELIST_DEFAULT = %w[
|
279
364
|
REMOTE_ADDR
|
280
365
|
SERVER_NAME
|
281
366
|
SERVER_PORT
|
282
|
-
|
367
|
+
].freeze
|
283
368
|
|
284
369
|
HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
|
285
|
-
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
|
370
|
+
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
|
286
371
|
|
287
|
-
LOG_PREFIX = "** [Sentry] "
|
288
|
-
MODULE_SEPARATOR = "::"
|
372
|
+
LOG_PREFIX = "** [Sentry] "
|
373
|
+
MODULE_SEPARATOR = "::"
|
289
374
|
SKIP_INSPECTION_ATTRIBUTES = [:@linecache, :@stacktrace_builder]
|
290
375
|
|
291
376
|
INSTRUMENTERS = [:sentry, :otel]
|
292
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
|
+
|
293
384
|
class << self
|
294
385
|
# Post initialization callbacks are called at the end of initialization process
|
295
386
|
# allowing extending the configuration of sentry-ruby by multiple extensions
|
@@ -297,17 +388,58 @@ module Sentry
|
|
297
388
|
@post_initialization_callbacks ||= []
|
298
389
|
end
|
299
390
|
|
300
|
-
|
391
|
+
# allow extensions to add their hooks to the Configuration class
|
301
392
|
def add_post_initialization_callback(&block)
|
302
393
|
post_initialization_callbacks << block
|
303
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
|
304
431
|
end
|
305
432
|
|
433
|
+
validate :traces_sample_rate, optional: true, type: :numeric
|
434
|
+
validate :profiles_sample_rate, optional: true, type: :numeric
|
435
|
+
|
306
436
|
def initialize
|
307
|
-
self.app_dirs_pattern =
|
308
|
-
self.debug =
|
309
|
-
self.background_worker_threads =
|
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
|
310
441
|
self.backtrace_cleanup_callback = nil
|
442
|
+
self.strip_backtrace_load_path = true
|
311
443
|
self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
|
312
444
|
self.breadcrumbs_logger = []
|
313
445
|
self.context_lines = 3
|
@@ -318,7 +450,7 @@ module Sentry
|
|
318
450
|
self.excluded_exceptions = IGNORE_DEFAULT + PUMA_IGNORE_DEFAULT
|
319
451
|
self.inspect_exception_causes_for_exclusion = true
|
320
452
|
self.linecache = ::Sentry::LineCache.new
|
321
|
-
self.
|
453
|
+
self.sdk_logger = ::Sentry::Logger.new(STDOUT)
|
322
454
|
self.project_root = Dir.pwd
|
323
455
|
self.propagate_traces = true
|
324
456
|
|
@@ -328,21 +460,54 @@ module Sentry
|
|
328
460
|
self.skip_rake_integration = false
|
329
461
|
self.send_client_reports = true
|
330
462
|
self.auto_session_tracking = true
|
463
|
+
self.enable_backpressure_handling = false
|
331
464
|
self.trusted_proxies = []
|
332
|
-
self.dsn = ENV[
|
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
|
333
470
|
self.server_name = server_name_from_env
|
334
471
|
self.instrumenter = :sentry
|
472
|
+
self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
|
473
|
+
self.enabled_patches = DEFAULT_PATCHES.dup
|
335
474
|
|
336
475
|
self.before_send = nil
|
337
476
|
self.before_send_transaction = nil
|
477
|
+
self.before_send_log = nil
|
338
478
|
self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
|
339
479
|
self.traces_sampler = nil
|
340
480
|
self.enable_tracing = nil
|
481
|
+
self.enable_logs = false
|
482
|
+
|
483
|
+
self.profiler_class = Sentry::Profiler
|
341
484
|
|
342
485
|
@transport = Transport::Configuration.new
|
486
|
+
@cron = Cron::Configuration.new
|
487
|
+
@metrics = Metrics::Configuration.new
|
343
488
|
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
344
489
|
|
345
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
|
346
511
|
end
|
347
512
|
|
348
513
|
def dsn=(value)
|
@@ -413,26 +578,40 @@ module Sentry
|
|
413
578
|
end
|
414
579
|
|
415
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
|
+
|
416
587
|
@enable_tracing = enable_tracing
|
417
588
|
@traces_sample_rate ||= 1.0 if enable_tracing
|
418
589
|
end
|
419
590
|
|
420
|
-
def is_numeric_or_nil?(value)
|
421
|
-
value.is_a?(Numeric) || value.nil?
|
422
|
-
end
|
423
|
-
|
424
591
|
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
592
|
@traces_sample_rate = traces_sample_rate
|
427
593
|
end
|
428
594
|
|
429
595
|
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
596
|
@profiles_sample_rate = profiles_sample_rate
|
433
597
|
end
|
434
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
|
+
|
435
610
|
def sending_allowed?
|
611
|
+
spotlight || sending_to_dsn_allowed?
|
612
|
+
end
|
613
|
+
|
614
|
+
def sending_to_dsn_allowed?
|
436
615
|
@errors = []
|
437
616
|
|
438
617
|
valid? && capture_in_environment?
|
@@ -444,6 +623,10 @@ module Sentry
|
|
444
623
|
Random.rand < sample_rate
|
445
624
|
end
|
446
625
|
|
626
|
+
def session_tracking?
|
627
|
+
auto_session_tracking && enabled_in_current_env?
|
628
|
+
end
|
629
|
+
|
447
630
|
def exception_class_allowed?(exc)
|
448
631
|
if exc.is_a?(Sentry::Error)
|
449
632
|
# Try to prevent error reporting loops
|
@@ -495,7 +678,8 @@ module Sentry
|
|
495
678
|
app_dirs_pattern: @app_dirs_pattern,
|
496
679
|
linecache: @linecache,
|
497
680
|
context_lines: @context_lines,
|
498
|
-
backtrace_cleanup_callback: @backtrace_cleanup_callback
|
681
|
+
backtrace_cleanup_callback: @backtrace_cleanup_callback,
|
682
|
+
strip_backtrace_load_path: @strip_backtrace_load_path
|
499
683
|
)
|
500
684
|
end
|
501
685
|
|
@@ -520,12 +704,6 @@ module Sentry
|
|
520
704
|
|
521
705
|
private
|
522
706
|
|
523
|
-
def check_callable!(name, value)
|
524
|
-
unless value == nil || value.respond_to?(:call)
|
525
|
-
raise ArgumentError, "#{name} must be callable (or nil to disable)"
|
526
|
-
end
|
527
|
-
end
|
528
|
-
|
529
707
|
def init_dsn(dsn_string)
|
530
708
|
return if dsn_string.nil? || dsn_string.empty?
|
531
709
|
|
@@ -578,12 +756,12 @@ module Sentry
|
|
578
756
|
end
|
579
757
|
|
580
758
|
def environment_from_env
|
581
|
-
ENV[
|
759
|
+
ENV["SENTRY_CURRENT_ENV"] || ENV["SENTRY_ENVIRONMENT"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
582
760
|
end
|
583
761
|
|
584
762
|
def server_name_from_env
|
585
763
|
if running_on_heroku?
|
586
|
-
ENV[
|
764
|
+
ENV["DYNO"]
|
587
765
|
else
|
588
766
|
# Try to resolve the hostname to an FQDN, but fall back to whatever
|
589
767
|
# the load name is.
|
@@ -600,5 +778,10 @@ module Sentry
|
|
600
778
|
instance_eval(&hook)
|
601
779
|
end
|
602
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
|
603
786
|
end
|
604
787
|
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
|
@@ -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
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
module Cron
|
5
|
+
module MonitorSchedule
|
6
|
+
class Crontab
|
7
|
+
# A crontab formatted string such as "0 * * * *".
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :value
|
10
|
+
|
11
|
+
def initialize(value)
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_hash
|
16
|
+
{ type: :crontab, value: value }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Interval
|
21
|
+
# The number representing duration of the interval.
|
22
|
+
# @return [Integer]
|
23
|
+
attr_accessor :value
|
24
|
+
|
25
|
+
# The unit representing duration of the interval.
|
26
|
+
# @return [Symbol]
|
27
|
+
attr_accessor :unit
|
28
|
+
|
29
|
+
VALID_UNITS = %i[year month week day hour minute]
|
30
|
+
|
31
|
+
def initialize(value, unit)
|
32
|
+
@value = value
|
33
|
+
@unit = unit
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_hash
|
37
|
+
{ type: :interval, value: value, unit: unit }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
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?
|