sentry-ruby 5.26.0 → 6.4.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 +27 -5
- data/README.md +3 -3
- data/lib/sentry/background_worker.rb +1 -4
- data/lib/sentry/backtrace/line.rb +99 -0
- data/lib/sentry/backtrace.rb +44 -76
- data/lib/sentry/baggage.rb +1 -1
- data/lib/sentry/breadcrumb.rb +1 -1
- data/lib/sentry/breadcrumb_buffer.rb +2 -2
- data/lib/sentry/check_in_event.rb +2 -2
- data/lib/sentry/client.rb +59 -136
- data/lib/sentry/configuration.rb +176 -78
- data/lib/sentry/cron/monitor_check_ins.rb +3 -3
- data/lib/sentry/cron/monitor_config.rb +2 -2
- data/lib/sentry/cron/monitor_schedule.rb +2 -2
- data/lib/sentry/debug_structured_logger.rb +94 -0
- data/lib/sentry/dsn.rb +52 -0
- data/lib/sentry/envelope/item.rb +3 -3
- data/lib/sentry/error_event.rb +3 -3
- data/lib/sentry/event.rb +4 -10
- data/lib/sentry/graphql.rb +1 -1
- data/lib/sentry/hub.rb +29 -5
- data/lib/sentry/interface.rb +1 -1
- data/lib/sentry/interfaces/exception.rb +2 -2
- data/lib/sentry/interfaces/request.rb +2 -0
- data/lib/sentry/interfaces/single_exception.rb +4 -4
- data/lib/sentry/interfaces/stacktrace.rb +3 -3
- data/lib/sentry/interfaces/stacktrace_builder.rb +0 -8
- data/lib/sentry/interfaces/threads.rb +2 -2
- data/lib/sentry/log_event.rb +33 -138
- data/lib/sentry/log_event_buffer.rb +13 -60
- data/lib/sentry/metric_event.rb +49 -0
- data/lib/sentry/metric_event_buffer.rb +28 -0
- data/lib/sentry/metrics.rb +47 -42
- data/lib/sentry/profiler.rb +4 -5
- data/lib/sentry/propagation_context.rb +55 -18
- data/lib/sentry/rack/capture_exceptions.rb +88 -2
- data/lib/sentry/rspec.rb +1 -1
- data/lib/sentry/scope.rb +50 -18
- data/lib/sentry/sequel.rb +35 -0
- data/lib/sentry/span.rb +5 -17
- data/lib/sentry/std_lib_logger.rb +10 -1
- data/lib/sentry/telemetry_event_buffer.rb +130 -0
- data/lib/sentry/test_helper.rb +30 -0
- data/lib/sentry/transaction.rb +72 -95
- data/lib/sentry/transaction_event.rb +4 -9
- data/lib/sentry/transport/debug_transport.rb +70 -0
- data/lib/sentry/transport/dummy_transport.rb +1 -0
- data/lib/sentry/transport/http_transport.rb +10 -16
- data/lib/sentry/transport.rb +4 -6
- data/lib/sentry/utils/encoding_helper.rb +6 -0
- data/lib/sentry/utils/logging_helper.rb +25 -9
- data/lib/sentry/utils/sample_rand.rb +97 -0
- data/lib/sentry/utils/telemetry_attributes.rb +30 -0
- data/lib/sentry/vernier/profiler.rb +4 -3
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +57 -30
- data/sentry-ruby-core.gemspec +1 -1
- data/sentry-ruby.gemspec +2 -1
- metadata +31 -17
- data/lib/sentry/metrics/aggregator.rb +0 -248
- data/lib/sentry/metrics/configuration.rb +0 -47
- data/lib/sentry/metrics/counter_metric.rb +0 -25
- data/lib/sentry/metrics/distribution_metric.rb +0 -25
- data/lib/sentry/metrics/gauge_metric.rb +0 -35
- data/lib/sentry/metrics/local_aggregator.rb +0 -53
- data/lib/sentry/metrics/metric.rb +0 -19
- data/lib/sentry/metrics/set_metric.rb +0 -28
- data/lib/sentry/metrics/timing.rb +0 -51
data/lib/sentry/configuration.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "cgi/escape"
|
|
3
4
|
require "concurrent/utility/processor_counter"
|
|
4
5
|
|
|
5
6
|
require "sentry/utils/exception_cause_chain"
|
|
@@ -9,11 +10,12 @@ require "sentry/dsn"
|
|
|
9
10
|
require "sentry/release_detector"
|
|
10
11
|
require "sentry/transport/configuration"
|
|
11
12
|
require "sentry/cron/configuration"
|
|
12
|
-
require "sentry/metrics/configuration"
|
|
13
13
|
require "sentry/linecache"
|
|
14
14
|
require "sentry/interfaces/stacktrace_builder"
|
|
15
15
|
require "sentry/logger"
|
|
16
|
+
require "sentry/structured_logger"
|
|
16
17
|
require "sentry/log_event_buffer"
|
|
18
|
+
require "sentry/metric_event_buffer"
|
|
17
19
|
|
|
18
20
|
module Sentry
|
|
19
21
|
class Configuration
|
|
@@ -30,13 +32,6 @@ module Sentry
|
|
|
30
32
|
# @return [Regexp, nil]
|
|
31
33
|
attr_accessor :app_dirs_pattern
|
|
32
34
|
|
|
33
|
-
# Provide an object that responds to `call` to send events asynchronously.
|
|
34
|
-
# E.g.: lambda { |event| Thread.new { Sentry.send_event(event) } }
|
|
35
|
-
#
|
|
36
|
-
# @deprecated It will be removed in the next major release. Please read https://github.com/getsentry/sentry-ruby/issues/1522 for more information
|
|
37
|
-
# @return [Proc, nil]
|
|
38
|
-
attr_reader :async
|
|
39
|
-
|
|
40
35
|
# to send events in a non-blocking way, sentry-ruby has its own background worker
|
|
41
36
|
# by default, the worker holds a thread pool that has [the number of processors] threads
|
|
42
37
|
# but you can configure it with this configuration option
|
|
@@ -74,11 +69,10 @@ module Sentry
|
|
|
74
69
|
# @return [Proc]
|
|
75
70
|
attr_reader :before_breadcrumb
|
|
76
71
|
|
|
77
|
-
# Optional Proc, called before sending an event to the server
|
|
72
|
+
# Optional Proc, called before sending an error event to the server
|
|
78
73
|
# @example
|
|
79
74
|
# config.before_send = lambda do |event, hint|
|
|
80
75
|
# # skip ZeroDivisionError exceptions
|
|
81
|
-
# # note: hint[:exception] would be a String if you use async callback
|
|
82
76
|
# if hint[:exception].is_a?(ZeroDivisionError)
|
|
83
77
|
# nil
|
|
84
78
|
# else
|
|
@@ -88,7 +82,7 @@ module Sentry
|
|
|
88
82
|
# @return [Proc]
|
|
89
83
|
attr_reader :before_send
|
|
90
84
|
|
|
91
|
-
# Optional Proc, called before sending
|
|
85
|
+
# Optional Proc, called before sending a transaction event to the server
|
|
92
86
|
# @example
|
|
93
87
|
# config.before_send_transaction = lambda do |event, hint|
|
|
94
88
|
# # skip unimportant transactions or strip sensitive data
|
|
@@ -101,6 +95,18 @@ module Sentry
|
|
|
101
95
|
# @return [Proc]
|
|
102
96
|
attr_reader :before_send_transaction
|
|
103
97
|
|
|
98
|
+
# Optional Proc, called before sending a check-in event to the server
|
|
99
|
+
# @example
|
|
100
|
+
# config.before_send_check_in = lambda do |event, hint|
|
|
101
|
+
# if event.monitor_slug == "unimportant_job"
|
|
102
|
+
# nil
|
|
103
|
+
# else
|
|
104
|
+
# event
|
|
105
|
+
# end
|
|
106
|
+
# end
|
|
107
|
+
# @return [Proc]
|
|
108
|
+
attr_reader :before_send_check_in
|
|
109
|
+
|
|
104
110
|
# Optional Proc, called before sending an event to the server
|
|
105
111
|
# @example
|
|
106
112
|
# config.before_send_log = lambda do |log|
|
|
@@ -117,7 +123,6 @@ module Sentry
|
|
|
117
123
|
#
|
|
118
124
|
# And if you also use sentry-rails:
|
|
119
125
|
# - :active_support_logger
|
|
120
|
-
# - :monotonic_active_support_logger
|
|
121
126
|
#
|
|
122
127
|
# @return [Array<Symbol>]
|
|
123
128
|
attr_reader :breadcrumbs_logger
|
|
@@ -144,7 +149,7 @@ module Sentry
|
|
|
144
149
|
attr_reader :dsn
|
|
145
150
|
|
|
146
151
|
# Whitelist of enabled_environments that will send notifications to Sentry. Array of Strings.
|
|
147
|
-
# @return [Array<String
|
|
152
|
+
# @return [Array<String>, nil]
|
|
148
153
|
attr_accessor :enabled_environments
|
|
149
154
|
|
|
150
155
|
# Logger 'progname's to exclude from breadcrumbs
|
|
@@ -173,18 +178,6 @@ module Sentry
|
|
|
173
178
|
# @return [Boolean, String]
|
|
174
179
|
attr_accessor :spotlight
|
|
175
180
|
|
|
176
|
-
# @deprecated Use {#include_local_variables} instead.
|
|
177
|
-
alias_method :capture_exception_frame_locals, :include_local_variables
|
|
178
|
-
|
|
179
|
-
# @deprecated Use {#include_local_variables=} instead.
|
|
180
|
-
def capture_exception_frame_locals=(value)
|
|
181
|
-
log_warn <<~MSG
|
|
182
|
-
`capture_exception_frame_locals` is now deprecated in favor of `include_local_variables`.
|
|
183
|
-
MSG
|
|
184
|
-
|
|
185
|
-
self.include_local_variables = value
|
|
186
|
-
end
|
|
187
|
-
|
|
188
181
|
# You may provide your own LineCache for matching paths with source files.
|
|
189
182
|
# This may be useful if you need to get source code from places other than the disk.
|
|
190
183
|
# @see LineCache
|
|
@@ -196,17 +189,10 @@ module Sentry
|
|
|
196
189
|
# @return [Logger]
|
|
197
190
|
attr_accessor :sdk_logger
|
|
198
191
|
|
|
199
|
-
#
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
|
192
|
+
# File path for DebugTransport to log events to. If not set, defaults to a temporary file.
|
|
193
|
+
# This is useful for debugging and testing purposes.
|
|
194
|
+
# @return [String, nil]
|
|
195
|
+
attr_accessor :sdk_debug_transport_log_file
|
|
210
196
|
|
|
211
197
|
# Project directory root for in_app detection. Could be Rails root, etc.
|
|
212
198
|
# Set automatically for Rails.
|
|
@@ -249,6 +235,12 @@ module Sentry
|
|
|
249
235
|
# @return [Boolean]
|
|
250
236
|
attr_accessor :send_default_pii
|
|
251
237
|
|
|
238
|
+
# Capture queue time from X-Request-Start header set by reverse proxies.
|
|
239
|
+
# Works with any Rack app behind Nginx, HAProxy, Heroku router, etc.
|
|
240
|
+
# Defaults to true.
|
|
241
|
+
# @return [Boolean]
|
|
242
|
+
attr_accessor :capture_queue_time
|
|
243
|
+
|
|
252
244
|
# Allow to skip Sentry emails within rake tasks
|
|
253
245
|
# @return [Boolean]
|
|
254
246
|
attr_accessor :skip_rake_integration
|
|
@@ -267,10 +259,6 @@ module Sentry
|
|
|
267
259
|
# @return [Cron::Configuration]
|
|
268
260
|
attr_reader :cron
|
|
269
261
|
|
|
270
|
-
# Metrics related configuration.
|
|
271
|
-
# @return [Metrics::Configuration]
|
|
272
|
-
attr_reader :metrics
|
|
273
|
-
|
|
274
262
|
# Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
|
|
275
263
|
# @return [Float, nil]
|
|
276
264
|
attr_reader :traces_sample_rate
|
|
@@ -289,11 +277,9 @@ module Sentry
|
|
|
289
277
|
# @return [Boolean]
|
|
290
278
|
attr_accessor :enable_logs
|
|
291
279
|
|
|
292
|
-
#
|
|
293
|
-
#
|
|
294
|
-
|
|
295
|
-
# @return [Boolean, nil]
|
|
296
|
-
attr_reader :enable_tracing
|
|
280
|
+
# Structured logging configuration.
|
|
281
|
+
# @return [StructuredLoggingConfiguration]
|
|
282
|
+
attr_reader :structured_logging
|
|
297
283
|
|
|
298
284
|
# Send diagnostic client reports about dropped events, true by default
|
|
299
285
|
# tries to attach to an existing envelope max once every 30s
|
|
@@ -315,6 +301,18 @@ module Sentry
|
|
|
315
301
|
# @return [Array<String, Regexp>]
|
|
316
302
|
attr_accessor :trace_propagation_targets
|
|
317
303
|
|
|
304
|
+
# Collection of HTTP status codes or ranges of codes to ignore when tracing incoming requests.
|
|
305
|
+
# If a transaction's http.response.status_code matches one of these values,
|
|
306
|
+
# the transaction will be dropped and marked as not sampled.
|
|
307
|
+
# Defaults to TRACE_IGNORE_STATUS_CODES_DEFAULT.
|
|
308
|
+
#
|
|
309
|
+
# @example
|
|
310
|
+
# # ignore 404 and 502 <= status_code <= 511
|
|
311
|
+
# config.trace_ignore_status_codes = [404, (502..511)]
|
|
312
|
+
#
|
|
313
|
+
# @return [Array<Integer>, Array<Range>]
|
|
314
|
+
attr_reader :trace_ignore_status_codes
|
|
315
|
+
|
|
318
316
|
# The instrumenter to use, :sentry or :otel
|
|
319
317
|
# @return [Symbol]
|
|
320
318
|
attr_reader :instrumenter
|
|
@@ -329,6 +327,15 @@ module Sentry
|
|
|
329
327
|
# @return [Float, nil]
|
|
330
328
|
attr_reader :profiles_sample_rate
|
|
331
329
|
|
|
330
|
+
# Interval in microseconds at which to take samples.
|
|
331
|
+
# The default is 1e6 / 101, or 101Hz.
|
|
332
|
+
# Note that the 101 is intentional to avoid lockstep sampling.
|
|
333
|
+
#
|
|
334
|
+
# @example
|
|
335
|
+
# config.profiles_sample_interval = 1e5 / 101
|
|
336
|
+
# @return [Float]
|
|
337
|
+
attr_accessor :profiles_sample_interval
|
|
338
|
+
|
|
332
339
|
# Array of patches to apply.
|
|
333
340
|
# Default is {DEFAULT_PATCHES}
|
|
334
341
|
# @return [Array<Symbol>]
|
|
@@ -338,6 +345,32 @@ module Sentry
|
|
|
338
345
|
# @return [Integer]
|
|
339
346
|
attr_accessor :max_log_events
|
|
340
347
|
|
|
348
|
+
# Enable metrics collection, defaults to true
|
|
349
|
+
# @return [Boolean]
|
|
350
|
+
attr_accessor :enable_metrics
|
|
351
|
+
|
|
352
|
+
# Maximum number of metric events to buffer before sending
|
|
353
|
+
# @return [Integer]
|
|
354
|
+
attr_accessor :max_metric_events
|
|
355
|
+
|
|
356
|
+
# Optional Proc, called before sending a metric
|
|
357
|
+
# @example
|
|
358
|
+
# config.before_send_metric = lambda do |metric|
|
|
359
|
+
# # return nil to drop the metric
|
|
360
|
+
# metric
|
|
361
|
+
# end
|
|
362
|
+
# @return [Proc, nil]
|
|
363
|
+
attr_reader :before_send_metric
|
|
364
|
+
|
|
365
|
+
# Optional Proc, called to filter log messages before sending to Sentry
|
|
366
|
+
# @example
|
|
367
|
+
# config.std_lib_logger_filter = lambda do |logger, message, level|
|
|
368
|
+
# # Only send error and fatal logs to Sentry
|
|
369
|
+
# [:error, :fatal].include?(level)
|
|
370
|
+
# end
|
|
371
|
+
# @return [Proc, nil]
|
|
372
|
+
attr_reader :std_lib_logger_filter
|
|
373
|
+
|
|
341
374
|
# these are not config options
|
|
342
375
|
# @!visibility private
|
|
343
376
|
attr_reader :errors, :gem_specs
|
|
@@ -366,6 +399,8 @@ module Sentry
|
|
|
366
399
|
SERVER_PORT
|
|
367
400
|
].freeze
|
|
368
401
|
|
|
402
|
+
TRACE_IGNORE_STATUS_CODES_DEFAULT = [(301..303), (305..399), (401..404)]
|
|
403
|
+
|
|
369
404
|
HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
|
|
370
405
|
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
|
|
371
406
|
|
|
@@ -381,6 +416,9 @@ module Sentry
|
|
|
381
416
|
|
|
382
417
|
APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/
|
|
383
418
|
|
|
419
|
+
# 101 Hz in microseconds
|
|
420
|
+
DEFAULT_PROFILES_SAMPLE_INTERVAL = 1e6 / 101
|
|
421
|
+
|
|
384
422
|
class << self
|
|
385
423
|
# Post initialization callbacks are called at the end of initialization process
|
|
386
424
|
# allowing extending the configuration of sentry-ruby by multiple extensions
|
|
@@ -390,7 +428,23 @@ module Sentry
|
|
|
390
428
|
|
|
391
429
|
# allow extensions to add their hooks to the Configuration class
|
|
392
430
|
def add_post_initialization_callback(&block)
|
|
393
|
-
|
|
431
|
+
callbacks[:initialize][:after] << block
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def before(event, &block)
|
|
435
|
+
callbacks[event.to_sym][:before] << block
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def after(event, &block)
|
|
439
|
+
callbacks[event.to_sym][:after] << block
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# @!visibility private
|
|
443
|
+
def callbacks
|
|
444
|
+
@callbacks ||= {
|
|
445
|
+
initialize: { before: [], after: [] },
|
|
446
|
+
configured: { before: [], after: [] }
|
|
447
|
+
}
|
|
394
448
|
end
|
|
395
449
|
|
|
396
450
|
def validations
|
|
@@ -434,6 +488,8 @@ module Sentry
|
|
|
434
488
|
validate :profiles_sample_rate, optional: true, type: :numeric
|
|
435
489
|
|
|
436
490
|
def initialize
|
|
491
|
+
run_callbacks(:before, :initialize)
|
|
492
|
+
|
|
437
493
|
self.app_dirs_pattern = APP_DIRS_PATTERN
|
|
438
494
|
self.debug = Sentry::Utils::EnvHelper.env_to_bool(ENV["SENTRY_DEBUG"])
|
|
439
495
|
self.background_worker_threads = (processor_count / 2.0).ceil
|
|
@@ -445,7 +501,7 @@ module Sentry
|
|
|
445
501
|
self.context_lines = 3
|
|
446
502
|
self.include_local_variables = false
|
|
447
503
|
self.environment = environment_from_env
|
|
448
|
-
self.enabled_environments =
|
|
504
|
+
self.enabled_environments = nil
|
|
449
505
|
self.exclude_loggers = []
|
|
450
506
|
self.excluded_exceptions = IGNORE_DEFAULT + PUMA_IGNORE_DEFAULT
|
|
451
507
|
self.inspect_exception_causes_for_exclusion = true
|
|
@@ -463,6 +519,7 @@ module Sentry
|
|
|
463
519
|
self.enable_backpressure_handling = false
|
|
464
520
|
self.trusted_proxies = []
|
|
465
521
|
self.dsn = ENV["SENTRY_DSN"]
|
|
522
|
+
self.capture_queue_time = true
|
|
466
523
|
|
|
467
524
|
spotlight_env = ENV["SENTRY_SPOTLIGHT"]
|
|
468
525
|
spotlight_bool = Sentry::Utils::EnvHelper.env_to_bool(spotlight_env, strict: true)
|
|
@@ -470,26 +527,36 @@ module Sentry
|
|
|
470
527
|
self.server_name = server_name_from_env
|
|
471
528
|
self.instrumenter = :sentry
|
|
472
529
|
self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
|
|
530
|
+
self.trace_ignore_status_codes = TRACE_IGNORE_STATUS_CODES_DEFAULT
|
|
473
531
|
self.enabled_patches = DEFAULT_PATCHES.dup
|
|
474
532
|
|
|
475
533
|
self.before_send = nil
|
|
476
534
|
self.before_send_transaction = nil
|
|
535
|
+
self.before_send_check_in = nil
|
|
477
536
|
self.before_send_log = nil
|
|
537
|
+
self.before_send_metric = nil
|
|
538
|
+
self.std_lib_logger_filter = nil
|
|
478
539
|
self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
|
|
479
540
|
self.traces_sampler = nil
|
|
480
|
-
self.enable_tracing = nil
|
|
481
541
|
self.enable_logs = false
|
|
542
|
+
self.enable_metrics = true
|
|
482
543
|
|
|
483
544
|
self.profiler_class = Sentry::Profiler
|
|
545
|
+
self.profiles_sample_interval = DEFAULT_PROFILES_SAMPLE_INTERVAL
|
|
484
546
|
|
|
485
547
|
@transport = Transport::Configuration.new
|
|
486
548
|
@cron = Cron::Configuration.new
|
|
487
|
-
@
|
|
549
|
+
@structured_logging = StructuredLoggingConfiguration.new
|
|
488
550
|
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
|
489
551
|
|
|
490
|
-
run_post_initialization_callbacks
|
|
491
|
-
|
|
492
552
|
self.max_log_events = LogEventBuffer::DEFAULT_MAX_EVENTS
|
|
553
|
+
self.max_metric_events = MetricEventBuffer::DEFAULT_MAX_METRICS
|
|
554
|
+
|
|
555
|
+
run_callbacks(:after, :initialize)
|
|
556
|
+
|
|
557
|
+
yield(self) if block_given?
|
|
558
|
+
|
|
559
|
+
run_callbacks(:after, :configured)
|
|
493
560
|
end
|
|
494
561
|
|
|
495
562
|
def validate
|
|
@@ -522,22 +589,6 @@ module Sentry
|
|
|
522
589
|
@release = value
|
|
523
590
|
end
|
|
524
591
|
|
|
525
|
-
def async=(value)
|
|
526
|
-
check_callable!("async", value)
|
|
527
|
-
|
|
528
|
-
log_warn <<~MSG
|
|
529
|
-
|
|
530
|
-
sentry-ruby now sends events asynchronously by default with its background worker (supported since 4.1.0).
|
|
531
|
-
The `config.async` callback has become redundant while continuing to cause issues.
|
|
532
|
-
(The problems of `async` are detailed in https://github.com/getsentry/sentry-ruby/issues/1522)
|
|
533
|
-
|
|
534
|
-
Therefore, we encourage you to remove it and let the background worker take care of async job sending.
|
|
535
|
-
It's deprecation is planned in the next major release (6.0), which is scheduled around the 3rd quarter of 2022.
|
|
536
|
-
MSG
|
|
537
|
-
|
|
538
|
-
@async = value
|
|
539
|
-
end
|
|
540
|
-
|
|
541
592
|
def breadcrumbs_logger=(logger)
|
|
542
593
|
loggers =
|
|
543
594
|
if logger.is_a?(Array)
|
|
@@ -563,12 +614,30 @@ module Sentry
|
|
|
563
614
|
@before_send_transaction = value
|
|
564
615
|
end
|
|
565
616
|
|
|
617
|
+
def before_send_check_in=(value)
|
|
618
|
+
check_callable!("before_send_check_in", value)
|
|
619
|
+
|
|
620
|
+
@before_send_check_in = value
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
def before_send_metric=(value)
|
|
624
|
+
check_callable!("before_send_metric", value)
|
|
625
|
+
|
|
626
|
+
@before_send_metric = value
|
|
627
|
+
end
|
|
628
|
+
|
|
566
629
|
def before_breadcrumb=(value)
|
|
567
630
|
check_callable!("before_breadcrumb", value)
|
|
568
631
|
|
|
569
632
|
@before_breadcrumb = value
|
|
570
633
|
end
|
|
571
634
|
|
|
635
|
+
def std_lib_logger_filter=(value)
|
|
636
|
+
check_callable!("std_lib_logger_filter", value)
|
|
637
|
+
|
|
638
|
+
@std_lib_logger_filter = value
|
|
639
|
+
end
|
|
640
|
+
|
|
572
641
|
def environment=(environment)
|
|
573
642
|
@environment = environment.to_s
|
|
574
643
|
end
|
|
@@ -577,15 +646,12 @@ module Sentry
|
|
|
577
646
|
@instrumenter = INSTRUMENTERS.include?(instrumenter) ? instrumenter : :sentry
|
|
578
647
|
end
|
|
579
648
|
|
|
580
|
-
def
|
|
581
|
-
unless
|
|
582
|
-
|
|
583
|
-
`enable_tracing` is now deprecated in favor of `traces_sample_rate = 1.0`.
|
|
584
|
-
MSG
|
|
649
|
+
def trace_ignore_status_codes=(codes)
|
|
650
|
+
unless codes.is_a?(Array) && codes.all? { |code| valid_status_code_entry?(code) }
|
|
651
|
+
raise ArgumentError, "trace_ignore_status_codes must be an Array of integers or ranges between (100-599) where begin <= end"
|
|
585
652
|
end
|
|
586
653
|
|
|
587
|
-
@
|
|
588
|
-
@traces_sample_rate ||= 1.0 if enable_tracing
|
|
654
|
+
@trace_ignore_status_codes = codes
|
|
589
655
|
end
|
|
590
656
|
|
|
591
657
|
def traces_sample_rate=(traces_sample_rate)
|
|
@@ -641,7 +707,7 @@ module Sentry
|
|
|
641
707
|
end
|
|
642
708
|
|
|
643
709
|
def enabled_in_current_env?
|
|
644
|
-
enabled_environments.
|
|
710
|
+
enabled_environments.nil? || enabled_environments.include?(environment)
|
|
645
711
|
end
|
|
646
712
|
|
|
647
713
|
def valid_sample_rate?(sample_rate)
|
|
@@ -652,7 +718,7 @@ module Sentry
|
|
|
652
718
|
def tracing_enabled?
|
|
653
719
|
valid_sampler = !!((valid_sample_rate?(@traces_sample_rate)) || @traces_sampler)
|
|
654
720
|
|
|
655
|
-
|
|
721
|
+
valid_sampler && sending_allowed?
|
|
656
722
|
end
|
|
657
723
|
|
|
658
724
|
def profiling_enabled?
|
|
@@ -773,8 +839,8 @@ module Sentry
|
|
|
773
839
|
File.directory?("/etc/heroku") && !ENV["CI"]
|
|
774
840
|
end
|
|
775
841
|
|
|
776
|
-
def
|
|
777
|
-
self.class.
|
|
842
|
+
def run_callbacks(hook, event)
|
|
843
|
+
self.class.callbacks[event][hook].each do |hook|
|
|
778
844
|
instance_eval(&hook)
|
|
779
845
|
end
|
|
780
846
|
end
|
|
@@ -783,5 +849,37 @@ module Sentry
|
|
|
783
849
|
available_processor_count = Concurrent.available_processor_count if Concurrent.respond_to?(:available_processor_count)
|
|
784
850
|
available_processor_count || Concurrent.processor_count
|
|
785
851
|
end
|
|
852
|
+
|
|
853
|
+
def valid_http_status_code?(code)
|
|
854
|
+
code.is_a?(Integer) && code >= 100 && code <= 599
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
def valid_status_code_entry?(entry)
|
|
858
|
+
case entry
|
|
859
|
+
when Integer
|
|
860
|
+
valid_http_status_code?(entry)
|
|
861
|
+
when Range
|
|
862
|
+
valid_http_status_code?(entry.begin) &&
|
|
863
|
+
valid_http_status_code?(entry.end) &&
|
|
864
|
+
entry.begin <= entry.end
|
|
865
|
+
else
|
|
866
|
+
false
|
|
867
|
+
end
|
|
868
|
+
end
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
class StructuredLoggingConfiguration
|
|
872
|
+
# File path for DebugStructuredLogger to log events to
|
|
873
|
+
# @return [String, Pathname, nil]
|
|
874
|
+
attr_accessor :file_path
|
|
875
|
+
|
|
876
|
+
# The class to use as a structured logger.
|
|
877
|
+
# @return [Class]
|
|
878
|
+
attr_accessor :logger_class
|
|
879
|
+
|
|
880
|
+
def initialize
|
|
881
|
+
@file_path = nil
|
|
882
|
+
@logger_class = Sentry::StructuredLogger
|
|
883
|
+
end
|
|
786
884
|
end
|
|
787
885
|
end
|
|
@@ -14,12 +14,12 @@ module Sentry
|
|
|
14
14
|
:in_progress,
|
|
15
15
|
monitor_config: monitor_config)
|
|
16
16
|
|
|
17
|
-
start =
|
|
17
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
18
18
|
|
|
19
19
|
begin
|
|
20
20
|
# need to do this on ruby <= 2.6 sadly
|
|
21
21
|
ret = method(:perform).super_method.arity == 0 ? super() : super
|
|
22
|
-
duration =
|
|
22
|
+
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
|
23
23
|
|
|
24
24
|
Sentry.capture_check_in(slug,
|
|
25
25
|
:ok,
|
|
@@ -29,7 +29,7 @@ module Sentry
|
|
|
29
29
|
|
|
30
30
|
ret
|
|
31
31
|
rescue Exception
|
|
32
|
-
duration =
|
|
32
|
+
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
|
33
33
|
|
|
34
34
|
Sentry.capture_check_in(slug,
|
|
35
35
|
:error,
|
|
@@ -40,9 +40,9 @@ module Sentry
|
|
|
40
40
|
new(MonitorSchedule::Interval.new(num, unit), **options)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
def
|
|
43
|
+
def to_h
|
|
44
44
|
{
|
|
45
|
-
schedule: schedule.
|
|
45
|
+
schedule: schedule.to_h,
|
|
46
46
|
checkin_margin: checkin_margin,
|
|
47
47
|
max_runtime: max_runtime,
|
|
48
48
|
timezone: timezone
|
|
@@ -12,7 +12,7 @@ module Sentry
|
|
|
12
12
|
@value = value
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def
|
|
15
|
+
def to_h
|
|
16
16
|
{ type: :crontab, value: value }
|
|
17
17
|
end
|
|
18
18
|
end
|
|
@@ -33,7 +33,7 @@ module Sentry
|
|
|
33
33
|
@unit = unit
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def
|
|
36
|
+
def to_h
|
|
37
37
|
{ type: :interval, value: value, unit: unit }
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "pathname"
|
|
6
|
+
require "delegate"
|
|
7
|
+
|
|
8
|
+
module Sentry
|
|
9
|
+
# DebugStructuredLogger is a logger that captures structured log events to a file for debugging purposes.
|
|
10
|
+
#
|
|
11
|
+
# It can optionally also send log events to Sentry via the normal structured logger if logging
|
|
12
|
+
# is enabled.
|
|
13
|
+
class DebugStructuredLogger < SimpleDelegator
|
|
14
|
+
DEFAULT_LOG_FILE_PATH = File.join("log", "sentry_debug_logs.log")
|
|
15
|
+
|
|
16
|
+
attr_reader :log_file, :backend
|
|
17
|
+
|
|
18
|
+
def initialize(configuration)
|
|
19
|
+
@log_file = initialize_log_file(
|
|
20
|
+
configuration.structured_logging.file_path || DEFAULT_LOG_FILE_PATH
|
|
21
|
+
)
|
|
22
|
+
@backend = initialize_backend(configuration)
|
|
23
|
+
|
|
24
|
+
super(@backend)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Override all log level methods to capture events
|
|
28
|
+
%i[trace debug info warn error fatal].each do |level|
|
|
29
|
+
define_method(level) do |message, parameters = [], **attributes|
|
|
30
|
+
log_event = capture_log_event(level, message, parameters, **attributes)
|
|
31
|
+
backend.public_send(level, message, parameters, **attributes)
|
|
32
|
+
log_event
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def log(level, message, parameters:, **attributes)
|
|
37
|
+
log_event = capture_log_event(level, message, parameters, **attributes)
|
|
38
|
+
backend.log(level, message, parameters: parameters, **attributes)
|
|
39
|
+
log_event
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def capture_log_event(level, message, parameters, **attributes)
|
|
43
|
+
log_event_json = {
|
|
44
|
+
timestamp: Time.now.utc.iso8601,
|
|
45
|
+
level: level.to_s,
|
|
46
|
+
message: message,
|
|
47
|
+
parameters: parameters,
|
|
48
|
+
attributes: attributes
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
File.open(log_file, "a") { |file| file << JSON.dump(log_event_json) << "\n" }
|
|
52
|
+
log_event_json
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def logged_events
|
|
56
|
+
File.readlines(log_file).map do |line|
|
|
57
|
+
JSON.parse(line)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def clear
|
|
62
|
+
File.write(log_file, "")
|
|
63
|
+
if backend.respond_to?(:config)
|
|
64
|
+
backend.config.sdk_logger.debug("DebugStructuredLogger: Cleared events from #{log_file}")
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def initialize_backend(configuration)
|
|
71
|
+
if configuration.enable_logs
|
|
72
|
+
StructuredLogger.new(configuration)
|
|
73
|
+
else
|
|
74
|
+
# Create a no-op logger if logging is disabled
|
|
75
|
+
NoOpLogger.new
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def initialize_log_file(log_file_path)
|
|
80
|
+
log_file = Pathname(log_file_path)
|
|
81
|
+
|
|
82
|
+
FileUtils.mkdir_p(log_file.dirname) unless log_file.dirname.exist?
|
|
83
|
+
|
|
84
|
+
log_file
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# No-op logger for when structured logging is disabled
|
|
88
|
+
class NoOpLogger
|
|
89
|
+
%i[trace debug info warn error fatal log].each do |method|
|
|
90
|
+
define_method(method) { |*args, **kwargs| nil }
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
data/lib/sentry/dsn.rb
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "uri"
|
|
4
|
+
require "ipaddr"
|
|
5
|
+
require "resolv"
|
|
4
6
|
|
|
5
7
|
module Sentry
|
|
6
8
|
class DSN
|
|
9
|
+
PROTOCOL_VERSION = "7"
|
|
7
10
|
PORT_MAP = { "http" => 80, "https" => 443 }.freeze
|
|
8
11
|
REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
|
|
12
|
+
LOCALHOST_NAMES = %w[localhost 127.0.0.1 ::1 [::1]].freeze
|
|
13
|
+
LOCALHOST_PATTERN = /\.local(host|domain)?$/i
|
|
9
14
|
|
|
10
15
|
attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
|
|
11
16
|
|
|
@@ -49,5 +54,52 @@ module Sentry
|
|
|
49
54
|
def envelope_endpoint
|
|
50
55
|
"#{path}/api/#{project_id}/envelope/"
|
|
51
56
|
end
|
|
57
|
+
|
|
58
|
+
def otlp_traces_endpoint
|
|
59
|
+
"#{path}/api/#{project_id}/integration/otlp/v1/traces/"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def local?
|
|
63
|
+
@local ||= (localhost? || private_ip? || resolved_ips_private?)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def localhost?
|
|
67
|
+
LOCALHOST_NAMES.include?(host.downcase) || LOCALHOST_PATTERN.match?(host)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def private_ip?
|
|
71
|
+
@private_ip ||= begin
|
|
72
|
+
begin
|
|
73
|
+
IPAddr.new(host).private?
|
|
74
|
+
rescue IPAddr::InvalidAddressError
|
|
75
|
+
false
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def resolved_ips_private?
|
|
81
|
+
@resolved_ips_private ||= begin
|
|
82
|
+
begin
|
|
83
|
+
Resolv.getaddresses(host).any? { |ip| IPAddr.new(ip).private? }
|
|
84
|
+
rescue Resolv::ResolvError, IPAddr::InvalidAddressError
|
|
85
|
+
false
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def generate_auth_header(client: nil)
|
|
91
|
+
now = Sentry.utc_now.to_i
|
|
92
|
+
|
|
93
|
+
fields = {
|
|
94
|
+
"sentry_version" => PROTOCOL_VERSION,
|
|
95
|
+
"sentry_timestamp" => now,
|
|
96
|
+
"sentry_key" => @public_key
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fields["sentry_client"] = client if client
|
|
100
|
+
fields["sentry_secret"] = @secret_key if @secret_key
|
|
101
|
+
|
|
102
|
+
"Sentry " + fields.map { |key, value| "#{key}=#{value}" }.join(", ")
|
|
103
|
+
end
|
|
52
104
|
end
|
|
53
105
|
end
|