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.
- checksums.yaml +4 -4
- data/.rspec +3 -1
- data/Gemfile +12 -10
- 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 +251 -42
- 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 +143 -7
- 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 +28 -42
- 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 +11 -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 +15 -3
- 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 -12
- data/CODE_OF_CONDUCT.md +0 -74
data/lib/sentry/configuration.rb
CHANGED
@@ -3,21 +3,30 @@
|
|
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
|
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 :
|
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
|
-
|
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
|
-
#
|
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
|
-
|
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
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
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
|
-
|
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`"
|
370
|
+
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
|
275
371
|
|
276
|
-
LOG_PREFIX = "** [Sentry] "
|
277
|
-
MODULE_SEPARATOR = "::"
|
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
|
-
|
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 =
|
297
|
-
self.debug =
|
298
|
-
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
|
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
|
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.
|
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[
|
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
|
-
|
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[
|
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[
|
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
|
@@ -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
|