sentry-ruby 5.26.0 → 6.3.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 +26 -4
- data/README.md +2 -2
- 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/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 +168 -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 +32 -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/rspec.rb +1 -1
- data/lib/sentry/scope.rb +32 -5
- data/lib/sentry/sequel.rb +35 -0
- data/lib/sentry/span.rb +2 -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 +9 -5
- data/lib/sentry/transport.rb +3 -5
- 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 +25 -30
- data/sentry-ruby-core.gemspec +1 -1
- data/sentry-ruby.gemspec +1 -1
- metadata +17 -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
|
@@ -9,11 +9,12 @@ require "sentry/dsn"
|
|
|
9
9
|
require "sentry/release_detector"
|
|
10
10
|
require "sentry/transport/configuration"
|
|
11
11
|
require "sentry/cron/configuration"
|
|
12
|
-
require "sentry/metrics/configuration"
|
|
13
12
|
require "sentry/linecache"
|
|
14
13
|
require "sentry/interfaces/stacktrace_builder"
|
|
15
14
|
require "sentry/logger"
|
|
15
|
+
require "sentry/structured_logger"
|
|
16
16
|
require "sentry/log_event_buffer"
|
|
17
|
+
require "sentry/metric_event_buffer"
|
|
17
18
|
|
|
18
19
|
module Sentry
|
|
19
20
|
class Configuration
|
|
@@ -30,13 +31,6 @@ module Sentry
|
|
|
30
31
|
# @return [Regexp, nil]
|
|
31
32
|
attr_accessor :app_dirs_pattern
|
|
32
33
|
|
|
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
34
|
# to send events in a non-blocking way, sentry-ruby has its own background worker
|
|
41
35
|
# by default, the worker holds a thread pool that has [the number of processors] threads
|
|
42
36
|
# but you can configure it with this configuration option
|
|
@@ -74,11 +68,10 @@ module Sentry
|
|
|
74
68
|
# @return [Proc]
|
|
75
69
|
attr_reader :before_breadcrumb
|
|
76
70
|
|
|
77
|
-
# Optional Proc, called before sending an event to the server
|
|
71
|
+
# Optional Proc, called before sending an error event to the server
|
|
78
72
|
# @example
|
|
79
73
|
# config.before_send = lambda do |event, hint|
|
|
80
74
|
# # skip ZeroDivisionError exceptions
|
|
81
|
-
# # note: hint[:exception] would be a String if you use async callback
|
|
82
75
|
# if hint[:exception].is_a?(ZeroDivisionError)
|
|
83
76
|
# nil
|
|
84
77
|
# else
|
|
@@ -88,7 +81,7 @@ module Sentry
|
|
|
88
81
|
# @return [Proc]
|
|
89
82
|
attr_reader :before_send
|
|
90
83
|
|
|
91
|
-
# Optional Proc, called before sending
|
|
84
|
+
# Optional Proc, called before sending a transaction event to the server
|
|
92
85
|
# @example
|
|
93
86
|
# config.before_send_transaction = lambda do |event, hint|
|
|
94
87
|
# # skip unimportant transactions or strip sensitive data
|
|
@@ -101,6 +94,18 @@ module Sentry
|
|
|
101
94
|
# @return [Proc]
|
|
102
95
|
attr_reader :before_send_transaction
|
|
103
96
|
|
|
97
|
+
# Optional Proc, called before sending a check-in event to the server
|
|
98
|
+
# @example
|
|
99
|
+
# config.before_send_check_in = lambda do |event, hint|
|
|
100
|
+
# if event.monitor_slug == "unimportant_job"
|
|
101
|
+
# nil
|
|
102
|
+
# else
|
|
103
|
+
# event
|
|
104
|
+
# end
|
|
105
|
+
# end
|
|
106
|
+
# @return [Proc]
|
|
107
|
+
attr_reader :before_send_check_in
|
|
108
|
+
|
|
104
109
|
# Optional Proc, called before sending an event to the server
|
|
105
110
|
# @example
|
|
106
111
|
# config.before_send_log = lambda do |log|
|
|
@@ -117,7 +122,6 @@ module Sentry
|
|
|
117
122
|
#
|
|
118
123
|
# And if you also use sentry-rails:
|
|
119
124
|
# - :active_support_logger
|
|
120
|
-
# - :monotonic_active_support_logger
|
|
121
125
|
#
|
|
122
126
|
# @return [Array<Symbol>]
|
|
123
127
|
attr_reader :breadcrumbs_logger
|
|
@@ -144,7 +148,7 @@ module Sentry
|
|
|
144
148
|
attr_reader :dsn
|
|
145
149
|
|
|
146
150
|
# Whitelist of enabled_environments that will send notifications to Sentry. Array of Strings.
|
|
147
|
-
# @return [Array<String
|
|
151
|
+
# @return [Array<String>, nil]
|
|
148
152
|
attr_accessor :enabled_environments
|
|
149
153
|
|
|
150
154
|
# Logger 'progname's to exclude from breadcrumbs
|
|
@@ -173,18 +177,6 @@ module Sentry
|
|
|
173
177
|
# @return [Boolean, String]
|
|
174
178
|
attr_accessor :spotlight
|
|
175
179
|
|
|
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
180
|
# You may provide your own LineCache for matching paths with source files.
|
|
189
181
|
# This may be useful if you need to get source code from places other than the disk.
|
|
190
182
|
# @see LineCache
|
|
@@ -196,17 +188,10 @@ module Sentry
|
|
|
196
188
|
# @return [Logger]
|
|
197
189
|
attr_accessor :sdk_logger
|
|
198
190
|
|
|
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
|
|
191
|
+
# File path for DebugTransport to log events to. If not set, defaults to a temporary file.
|
|
192
|
+
# This is useful for debugging and testing purposes.
|
|
193
|
+
# @return [String, nil]
|
|
194
|
+
attr_accessor :sdk_debug_transport_log_file
|
|
210
195
|
|
|
211
196
|
# Project directory root for in_app detection. Could be Rails root, etc.
|
|
212
197
|
# Set automatically for Rails.
|
|
@@ -267,10 +252,6 @@ module Sentry
|
|
|
267
252
|
# @return [Cron::Configuration]
|
|
268
253
|
attr_reader :cron
|
|
269
254
|
|
|
270
|
-
# Metrics related configuration.
|
|
271
|
-
# @return [Metrics::Configuration]
|
|
272
|
-
attr_reader :metrics
|
|
273
|
-
|
|
274
255
|
# Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
|
|
275
256
|
# @return [Float, nil]
|
|
276
257
|
attr_reader :traces_sample_rate
|
|
@@ -289,11 +270,9 @@ module Sentry
|
|
|
289
270
|
# @return [Boolean]
|
|
290
271
|
attr_accessor :enable_logs
|
|
291
272
|
|
|
292
|
-
#
|
|
293
|
-
#
|
|
294
|
-
|
|
295
|
-
# @return [Boolean, nil]
|
|
296
|
-
attr_reader :enable_tracing
|
|
273
|
+
# Structured logging configuration.
|
|
274
|
+
# @return [StructuredLoggingConfiguration]
|
|
275
|
+
attr_reader :structured_logging
|
|
297
276
|
|
|
298
277
|
# Send diagnostic client reports about dropped events, true by default
|
|
299
278
|
# tries to attach to an existing envelope max once every 30s
|
|
@@ -315,6 +294,18 @@ module Sentry
|
|
|
315
294
|
# @return [Array<String, Regexp>]
|
|
316
295
|
attr_accessor :trace_propagation_targets
|
|
317
296
|
|
|
297
|
+
# Collection of HTTP status codes or ranges of codes to ignore when tracing incoming requests.
|
|
298
|
+
# If a transaction's http.response.status_code matches one of these values,
|
|
299
|
+
# the transaction will be dropped and marked as not sampled.
|
|
300
|
+
# Defaults to TRACE_IGNORE_STATUS_CODES_DEFAULT.
|
|
301
|
+
#
|
|
302
|
+
# @example
|
|
303
|
+
# # ignore 404 and 502 <= status_code <= 511
|
|
304
|
+
# config.trace_ignore_status_codes = [404, (502..511)]
|
|
305
|
+
#
|
|
306
|
+
# @return [Array<Integer>, Array<Range>]
|
|
307
|
+
attr_reader :trace_ignore_status_codes
|
|
308
|
+
|
|
318
309
|
# The instrumenter to use, :sentry or :otel
|
|
319
310
|
# @return [Symbol]
|
|
320
311
|
attr_reader :instrumenter
|
|
@@ -329,6 +320,15 @@ module Sentry
|
|
|
329
320
|
# @return [Float, nil]
|
|
330
321
|
attr_reader :profiles_sample_rate
|
|
331
322
|
|
|
323
|
+
# Interval in microseconds at which to take samples.
|
|
324
|
+
# The default is 1e6 / 101, or 101Hz.
|
|
325
|
+
# Note that the 101 is intentional to avoid lockstep sampling.
|
|
326
|
+
#
|
|
327
|
+
# @example
|
|
328
|
+
# config.profiles_sample_interval = 1e5 / 101
|
|
329
|
+
# @return [Float]
|
|
330
|
+
attr_accessor :profiles_sample_interval
|
|
331
|
+
|
|
332
332
|
# Array of patches to apply.
|
|
333
333
|
# Default is {DEFAULT_PATCHES}
|
|
334
334
|
# @return [Array<Symbol>]
|
|
@@ -338,6 +338,32 @@ module Sentry
|
|
|
338
338
|
# @return [Integer]
|
|
339
339
|
attr_accessor :max_log_events
|
|
340
340
|
|
|
341
|
+
# Enable metrics collection, defaults to true
|
|
342
|
+
# @return [Boolean]
|
|
343
|
+
attr_accessor :enable_metrics
|
|
344
|
+
|
|
345
|
+
# Maximum number of metric events to buffer before sending
|
|
346
|
+
# @return [Integer]
|
|
347
|
+
attr_accessor :max_metric_events
|
|
348
|
+
|
|
349
|
+
# Optional Proc, called before sending a metric
|
|
350
|
+
# @example
|
|
351
|
+
# config.before_send_metric = lambda do |metric|
|
|
352
|
+
# # return nil to drop the metric
|
|
353
|
+
# metric
|
|
354
|
+
# end
|
|
355
|
+
# @return [Proc, nil]
|
|
356
|
+
attr_reader :before_send_metric
|
|
357
|
+
|
|
358
|
+
# Optional Proc, called to filter log messages before sending to Sentry
|
|
359
|
+
# @example
|
|
360
|
+
# config.std_lib_logger_filter = lambda do |logger, message, level|
|
|
361
|
+
# # Only send error and fatal logs to Sentry
|
|
362
|
+
# [:error, :fatal].include?(level)
|
|
363
|
+
# end
|
|
364
|
+
# @return [Proc, nil]
|
|
365
|
+
attr_reader :std_lib_logger_filter
|
|
366
|
+
|
|
341
367
|
# these are not config options
|
|
342
368
|
# @!visibility private
|
|
343
369
|
attr_reader :errors, :gem_specs
|
|
@@ -366,6 +392,8 @@ module Sentry
|
|
|
366
392
|
SERVER_PORT
|
|
367
393
|
].freeze
|
|
368
394
|
|
|
395
|
+
TRACE_IGNORE_STATUS_CODES_DEFAULT = [(301..303), (305..399), (401..404)]
|
|
396
|
+
|
|
369
397
|
HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
|
|
370
398
|
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`"
|
|
371
399
|
|
|
@@ -381,6 +409,9 @@ module Sentry
|
|
|
381
409
|
|
|
382
410
|
APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/
|
|
383
411
|
|
|
412
|
+
# 101 Hz in microseconds
|
|
413
|
+
DEFAULT_PROFILES_SAMPLE_INTERVAL = 1e6 / 101
|
|
414
|
+
|
|
384
415
|
class << self
|
|
385
416
|
# Post initialization callbacks are called at the end of initialization process
|
|
386
417
|
# allowing extending the configuration of sentry-ruby by multiple extensions
|
|
@@ -390,7 +421,23 @@ module Sentry
|
|
|
390
421
|
|
|
391
422
|
# allow extensions to add their hooks to the Configuration class
|
|
392
423
|
def add_post_initialization_callback(&block)
|
|
393
|
-
|
|
424
|
+
callbacks[:initialize][:after] << block
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def before(event, &block)
|
|
428
|
+
callbacks[event.to_sym][:before] << block
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def after(event, &block)
|
|
432
|
+
callbacks[event.to_sym][:after] << block
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# @!visibility private
|
|
436
|
+
def callbacks
|
|
437
|
+
@callbacks ||= {
|
|
438
|
+
initialize: { before: [], after: [] },
|
|
439
|
+
configured: { before: [], after: [] }
|
|
440
|
+
}
|
|
394
441
|
end
|
|
395
442
|
|
|
396
443
|
def validations
|
|
@@ -434,6 +481,8 @@ module Sentry
|
|
|
434
481
|
validate :profiles_sample_rate, optional: true, type: :numeric
|
|
435
482
|
|
|
436
483
|
def initialize
|
|
484
|
+
run_callbacks(:before, :initialize)
|
|
485
|
+
|
|
437
486
|
self.app_dirs_pattern = APP_DIRS_PATTERN
|
|
438
487
|
self.debug = Sentry::Utils::EnvHelper.env_to_bool(ENV["SENTRY_DEBUG"])
|
|
439
488
|
self.background_worker_threads = (processor_count / 2.0).ceil
|
|
@@ -445,7 +494,7 @@ module Sentry
|
|
|
445
494
|
self.context_lines = 3
|
|
446
495
|
self.include_local_variables = false
|
|
447
496
|
self.environment = environment_from_env
|
|
448
|
-
self.enabled_environments =
|
|
497
|
+
self.enabled_environments = nil
|
|
449
498
|
self.exclude_loggers = []
|
|
450
499
|
self.excluded_exceptions = IGNORE_DEFAULT + PUMA_IGNORE_DEFAULT
|
|
451
500
|
self.inspect_exception_causes_for_exclusion = true
|
|
@@ -470,26 +519,36 @@ module Sentry
|
|
|
470
519
|
self.server_name = server_name_from_env
|
|
471
520
|
self.instrumenter = :sentry
|
|
472
521
|
self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
|
|
522
|
+
self.trace_ignore_status_codes = TRACE_IGNORE_STATUS_CODES_DEFAULT
|
|
473
523
|
self.enabled_patches = DEFAULT_PATCHES.dup
|
|
474
524
|
|
|
475
525
|
self.before_send = nil
|
|
476
526
|
self.before_send_transaction = nil
|
|
527
|
+
self.before_send_check_in = nil
|
|
477
528
|
self.before_send_log = nil
|
|
529
|
+
self.before_send_metric = nil
|
|
530
|
+
self.std_lib_logger_filter = nil
|
|
478
531
|
self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
|
|
479
532
|
self.traces_sampler = nil
|
|
480
|
-
self.enable_tracing = nil
|
|
481
533
|
self.enable_logs = false
|
|
534
|
+
self.enable_metrics = true
|
|
482
535
|
|
|
483
536
|
self.profiler_class = Sentry::Profiler
|
|
537
|
+
self.profiles_sample_interval = DEFAULT_PROFILES_SAMPLE_INTERVAL
|
|
484
538
|
|
|
485
539
|
@transport = Transport::Configuration.new
|
|
486
540
|
@cron = Cron::Configuration.new
|
|
487
|
-
@
|
|
541
|
+
@structured_logging = StructuredLoggingConfiguration.new
|
|
488
542
|
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
|
489
543
|
|
|
490
|
-
run_post_initialization_callbacks
|
|
491
|
-
|
|
492
544
|
self.max_log_events = LogEventBuffer::DEFAULT_MAX_EVENTS
|
|
545
|
+
self.max_metric_events = MetricEventBuffer::DEFAULT_MAX_METRICS
|
|
546
|
+
|
|
547
|
+
run_callbacks(:after, :initialize)
|
|
548
|
+
|
|
549
|
+
yield(self) if block_given?
|
|
550
|
+
|
|
551
|
+
run_callbacks(:after, :configured)
|
|
493
552
|
end
|
|
494
553
|
|
|
495
554
|
def validate
|
|
@@ -522,22 +581,6 @@ module Sentry
|
|
|
522
581
|
@release = value
|
|
523
582
|
end
|
|
524
583
|
|
|
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
584
|
def breadcrumbs_logger=(logger)
|
|
542
585
|
loggers =
|
|
543
586
|
if logger.is_a?(Array)
|
|
@@ -563,12 +606,30 @@ module Sentry
|
|
|
563
606
|
@before_send_transaction = value
|
|
564
607
|
end
|
|
565
608
|
|
|
609
|
+
def before_send_check_in=(value)
|
|
610
|
+
check_callable!("before_send_check_in", value)
|
|
611
|
+
|
|
612
|
+
@before_send_check_in = value
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
def before_send_metric=(value)
|
|
616
|
+
check_callable!("before_send_metric", value)
|
|
617
|
+
|
|
618
|
+
@before_send_metric = value
|
|
619
|
+
end
|
|
620
|
+
|
|
566
621
|
def before_breadcrumb=(value)
|
|
567
622
|
check_callable!("before_breadcrumb", value)
|
|
568
623
|
|
|
569
624
|
@before_breadcrumb = value
|
|
570
625
|
end
|
|
571
626
|
|
|
627
|
+
def std_lib_logger_filter=(value)
|
|
628
|
+
check_callable!("std_lib_logger_filter", value)
|
|
629
|
+
|
|
630
|
+
@std_lib_logger_filter = value
|
|
631
|
+
end
|
|
632
|
+
|
|
572
633
|
def environment=(environment)
|
|
573
634
|
@environment = environment.to_s
|
|
574
635
|
end
|
|
@@ -577,15 +638,12 @@ module Sentry
|
|
|
577
638
|
@instrumenter = INSTRUMENTERS.include?(instrumenter) ? instrumenter : :sentry
|
|
578
639
|
end
|
|
579
640
|
|
|
580
|
-
def
|
|
581
|
-
unless
|
|
582
|
-
|
|
583
|
-
`enable_tracing` is now deprecated in favor of `traces_sample_rate = 1.0`.
|
|
584
|
-
MSG
|
|
641
|
+
def trace_ignore_status_codes=(codes)
|
|
642
|
+
unless codes.is_a?(Array) && codes.all? { |code| valid_status_code_entry?(code) }
|
|
643
|
+
raise ArgumentError, "trace_ignore_status_codes must be an Array of integers or ranges between (100-599) where begin <= end"
|
|
585
644
|
end
|
|
586
645
|
|
|
587
|
-
@
|
|
588
|
-
@traces_sample_rate ||= 1.0 if enable_tracing
|
|
646
|
+
@trace_ignore_status_codes = codes
|
|
589
647
|
end
|
|
590
648
|
|
|
591
649
|
def traces_sample_rate=(traces_sample_rate)
|
|
@@ -641,7 +699,7 @@ module Sentry
|
|
|
641
699
|
end
|
|
642
700
|
|
|
643
701
|
def enabled_in_current_env?
|
|
644
|
-
enabled_environments.
|
|
702
|
+
enabled_environments.nil? || enabled_environments.include?(environment)
|
|
645
703
|
end
|
|
646
704
|
|
|
647
705
|
def valid_sample_rate?(sample_rate)
|
|
@@ -652,7 +710,7 @@ module Sentry
|
|
|
652
710
|
def tracing_enabled?
|
|
653
711
|
valid_sampler = !!((valid_sample_rate?(@traces_sample_rate)) || @traces_sampler)
|
|
654
712
|
|
|
655
|
-
|
|
713
|
+
valid_sampler && sending_allowed?
|
|
656
714
|
end
|
|
657
715
|
|
|
658
716
|
def profiling_enabled?
|
|
@@ -773,8 +831,8 @@ module Sentry
|
|
|
773
831
|
File.directory?("/etc/heroku") && !ENV["CI"]
|
|
774
832
|
end
|
|
775
833
|
|
|
776
|
-
def
|
|
777
|
-
self.class.
|
|
834
|
+
def run_callbacks(hook, event)
|
|
835
|
+
self.class.callbacks[event][hook].each do |hook|
|
|
778
836
|
instance_eval(&hook)
|
|
779
837
|
end
|
|
780
838
|
end
|
|
@@ -783,5 +841,37 @@ module Sentry
|
|
|
783
841
|
available_processor_count = Concurrent.available_processor_count if Concurrent.respond_to?(:available_processor_count)
|
|
784
842
|
available_processor_count || Concurrent.processor_count
|
|
785
843
|
end
|
|
844
|
+
|
|
845
|
+
def valid_http_status_code?(code)
|
|
846
|
+
code.is_a?(Integer) && code >= 100 && code <= 599
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
def valid_status_code_entry?(entry)
|
|
850
|
+
case entry
|
|
851
|
+
when Integer
|
|
852
|
+
valid_http_status_code?(entry)
|
|
853
|
+
when Range
|
|
854
|
+
valid_http_status_code?(entry.begin) &&
|
|
855
|
+
valid_http_status_code?(entry.end) &&
|
|
856
|
+
entry.begin <= entry.end
|
|
857
|
+
else
|
|
858
|
+
false
|
|
859
|
+
end
|
|
860
|
+
end
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
class StructuredLoggingConfiguration
|
|
864
|
+
# File path for DebugStructuredLogger to log events to
|
|
865
|
+
# @return [String, Pathname, nil]
|
|
866
|
+
attr_accessor :file_path
|
|
867
|
+
|
|
868
|
+
# The class to use as a structured logger.
|
|
869
|
+
# @return [Class]
|
|
870
|
+
attr_accessor :logger_class
|
|
871
|
+
|
|
872
|
+
def initialize
|
|
873
|
+
@file_path = nil
|
|
874
|
+
@logger_class = Sentry::StructuredLogger
|
|
875
|
+
end
|
|
786
876
|
end
|
|
787
877
|
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,15 @@
|
|
|
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
|
|
7
9
|
PORT_MAP = { "http" => 80, "https" => 443 }.freeze
|
|
8
10
|
REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
|
|
11
|
+
LOCALHOST_NAMES = %w[localhost 127.0.0.1 ::1 [::1]].freeze
|
|
12
|
+
LOCALHOST_PATTERN = /\.local(host|domain)?$/i
|
|
9
13
|
|
|
10
14
|
attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
|
|
11
15
|
|
|
@@ -49,5 +53,33 @@ module Sentry
|
|
|
49
53
|
def envelope_endpoint
|
|
50
54
|
"#{path}/api/#{project_id}/envelope/"
|
|
51
55
|
end
|
|
56
|
+
|
|
57
|
+
def local?
|
|
58
|
+
@local ||= (localhost? || private_ip? || resolved_ips_private?)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def localhost?
|
|
62
|
+
LOCALHOST_NAMES.include?(host.downcase) || LOCALHOST_PATTERN.match?(host)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def private_ip?
|
|
66
|
+
@private_ip ||= begin
|
|
67
|
+
begin
|
|
68
|
+
IPAddr.new(host).private?
|
|
69
|
+
rescue IPAddr::InvalidAddressError
|
|
70
|
+
false
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def resolved_ips_private?
|
|
76
|
+
@resolved_ips_private ||= begin
|
|
77
|
+
begin
|
|
78
|
+
Resolv.getaddresses(host).any? { |ip| IPAddr.new(ip).private? }
|
|
79
|
+
rescue Resolv::ResolvError, IPAddr::InvalidAddressError
|
|
80
|
+
false
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
52
84
|
end
|
|
53
85
|
end
|
data/lib/sentry/envelope/item.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Sentry
|
|
4
4
|
# @api private
|
|
5
5
|
class Envelope::Item
|
|
6
|
-
STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD =
|
|
6
|
+
STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 1000
|
|
7
7
|
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000
|
|
8
8
|
|
|
9
9
|
SIZE_LIMITS = Hash.new(MAX_SERIALIZED_PAYLOAD_SIZE).update(
|
|
@@ -15,10 +15,10 @@ module Sentry
|
|
|
15
15
|
# rate limits and client reports use the data_category rather than envelope item type
|
|
16
16
|
def self.data_category(type)
|
|
17
17
|
case type
|
|
18
|
-
when "session", "attachment", "transaction", "profile", "span", "
|
|
18
|
+
when "session", "attachment", "transaction", "profile", "span", "trace_metric" then type
|
|
19
|
+
when "log" then "log_item"
|
|
19
20
|
when "sessions" then "session"
|
|
20
21
|
when "check_in" then "monitor"
|
|
21
|
-
when "statsd", "metric_meta" then "metric_bucket"
|
|
22
22
|
when "event" then "error"
|
|
23
23
|
when "client_report" then "internal"
|
|
24
24
|
else "default"
|
data/lib/sentry/error_event.rb
CHANGED
|
@@ -10,10 +10,10 @@ module Sentry
|
|
|
10
10
|
attr_reader :threads
|
|
11
11
|
|
|
12
12
|
# @return [Hash]
|
|
13
|
-
def
|
|
13
|
+
def to_h
|
|
14
14
|
data = super
|
|
15
|
-
data[:threads] = threads.
|
|
16
|
-
data[:exception] = exception.
|
|
15
|
+
data[:threads] = threads.to_h if threads
|
|
16
|
+
data[:exception] = exception.to_h if exception
|
|
17
17
|
data
|
|
18
18
|
end
|
|
19
19
|
|