sentry-ruby 5.8.0 → 5.12.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ced2a96562a5dc27766fb35a62e43f302dd46eeabd16eae2a52106cc2151ee0
4
- data.tar.gz: 14f4b9a532cc0d1f401ee0bcb942787951f107358e9fbfadc2b1c655d00da3b2
3
+ metadata.gz: 857c6d99b1c5d9378a2522ffa1e466f91869500ae425f9d1add4aae399f1852c
4
+ data.tar.gz: 726793c0ae09ce3b137cdc7f48f6745c55176a83c8f651b8b493ee5d1290b522
5
5
  SHA512:
6
- metadata.gz: 8816a3439fd547d260e538d16c3db3f440bbdae35ec8108e2338ccd712497cbca0413ce1a365862ab510a787f5d3cae8a58eab2273dd06588284d77a5afac898
7
- data.tar.gz: 4d5e8d3fe56644431b33fbec3eeaf4ceec01eb85b21bd2abfa5a0d8bc4c812aef9beb06b89048525186f00170677b160154414d5cb9b8972725532ba35277130
6
+ metadata.gz: 13ccb78050835c829d738550bc9838347c71abc2139089c29ab466796059259740207d21504bee7cc6f4ca07dbcc982e12be05ebc0b955a4274a4a30bd0470ee
7
+ data.tar.gz: d6b4edd6c562b787b9fe652b6ba6ddb3bf16bca937bacbd22fcc44be746643a77e3595460263f72e3e76e73a7b92ff09577d7c665cfac2520886c3a62a62a2ab
data/Gemfile CHANGED
@@ -10,6 +10,8 @@ gem "rack", "~> #{Gem::Version.new(rack_version)}" unless rack_version == "0"
10
10
  redis_rb_version = ENV.fetch("REDIS_RB_VERSION", "5.0")
11
11
  gem "redis", "~> #{redis_rb_version}"
12
12
 
13
+ gem "puma"
14
+
13
15
  gem "rake", "~> 12.0"
14
16
  gem "rspec", "~> 3.0"
15
17
  gem "rspec-retry"
@@ -17,9 +19,19 @@ gem "timecop"
17
19
  gem "simplecov"
18
20
  gem "simplecov-cobertura", "~> 1.4"
19
21
  gem "rexml"
22
+ gem "stackprof" unless RUBY_PLATFORM == "java"
23
+
24
+ ruby_version = Gem::Version.new(RUBY_VERSION)
25
+
26
+ if ruby_version >= Gem::Version.new("2.6.0")
27
+ gem "debug", github: "ruby/debug", platform: :ruby
28
+ gem "irb"
29
+
30
+ if ruby_version >= Gem::Version.new("3.0.0")
31
+ gem "ruby-lsp-rspec"
32
+ end
33
+ end
20
34
 
21
- gem "object_tracer"
22
- gem "debug", github: "ruby/debug", platform: :ruby if RUBY_VERSION.to_f >= 2.6
23
35
  gem "pry"
24
36
 
25
37
  gem "benchmark-ips"
data/README.md CHANGED
@@ -13,14 +13,14 @@ _Bad software is everywhere, and we're tired of it. Sentry is on a mission to he
13
13
  Sentry SDK for Ruby
14
14
  ===========
15
15
 
16
- | current version | build | coverage | downloads |
17
- | --- | ----- | -------- | --------- |
18
- | [![Gem Version](https://img.shields.io/gem/v/sentry-ruby?label=sentry-ruby)](https://rubygems.org/gems/sentry-ruby) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-ruby%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-ruby.svg)](https://rubygems.org/gems/sentry-ruby/) |
19
- | [![Gem Version](https://img.shields.io/gem/v/sentry-rails?label=sentry-rails)](https://rubygems.org/gems/sentry-rails) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-rails%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-rails.svg)](https://rubygems.org/gems/sentry-rails/) |
20
- | [![Gem Version](https://img.shields.io/gem/v/sentry-sidekiq?label=sentry-sidekiq)](https://rubygems.org/gems/sentry-sidekiq) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-sidekiq%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq/) |
21
- | [![Gem Version](https://img.shields.io/gem/v/sentry-delayed_job?label=sentry-delayed_job)](https://rubygems.org/gems/sentry-delayed_job) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-delayed_job%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-delayed_job.svg)](https://rubygems.org/gems/sentry-delayed_job/) |
22
- | [![Gem Version](https://img.shields.io/gem/v/sentry-resque?label=sentry-resque)](https://rubygems.org/gems/sentry-resque) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-resque%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-resque.svg)](https://rubygems.org/gems/sentry-resque/) |
23
- | [![Gem Version](https://img.shields.io/gem/v/sentry-opentelemetry?label=sentry-opentelemetry)](https://rubygems.org/gems/sentry-opentelemetry) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-opentelemetry%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_opentelemetry_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-opentelemetry.svg)](https://rubygems.org/gems/sentry-opentelemetry/) |
16
+ | current version | build | coverage | downloads |
17
+ | --- | ----- | -------- | --------- |
18
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-ruby?label=sentry-ruby)](https://rubygems.org/gems/sentry-ruby) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-ruby.svg)](https://rubygems.org/gems/sentry-ruby/) |
19
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-rails?label=sentry-rails)](https://rubygems.org/gems/sentry-rails) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-rails.svg)](https://rubygems.org/gems/sentry-rails/) |
20
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-sidekiq?label=sentry-sidekiq)](https://rubygems.org/gems/sentry-sidekiq) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq/) |
21
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-delayed_job?label=sentry-delayed_job)](https://rubygems.org/gems/sentry-delayed_job) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-delayed_job.svg)](https://rubygems.org/gems/sentry-delayed_job/) |
22
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-resque?label=sentry-resque)](https://rubygems.org/gems/sentry-resque) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-resque.svg)](https://rubygems.org/gems/sentry-resque/) |
23
+ | [![Gem Version](https://img.shields.io/gem/v/sentry-opentelemetry?label=sentry-opentelemetry)](https://rubygems.org/gems/sentry-opentelemetry) | [![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_opentelemetry_test.yml/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_opentelemetry_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-opentelemetry.svg)](https://rubygems.org/gems/sentry-opentelemetry/) |
24
24
 
25
25
 
26
26
 
data/Rakefile CHANGED
@@ -8,6 +8,13 @@ require "rspec/core/rake_task"
8
8
 
9
9
  RSpec::Core::RakeTask.new(:spec).tap do |task|
10
10
  task.rspec_opts = "--order rand"
11
+ task.exclude_pattern = "spec/isolated/**/*_spec.rb"
11
12
  end
12
13
 
13
- task :default => :spec
14
+ task :isolated_specs do
15
+ Dir["spec/isolated/*"].each do |file|
16
+ sh "bundle exec rspec #{file}"
17
+ end
18
+ end
19
+
20
+ task :default => [:spec, :isolated_specs]
@@ -76,7 +76,7 @@ module Sentry
76
76
  end
77
77
  end
78
78
 
79
- APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test)/.freeze
79
+ APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/.freeze
80
80
 
81
81
  # holder for an Array of Backtrace::Line instances
82
82
  attr_reader :lines
@@ -8,17 +8,6 @@ module Sentry
8
8
  SENTRY_PREFIX = 'sentry-'
9
9
  SENTRY_PREFIX_REGEX = /^sentry-/.freeze
10
10
 
11
- DSC_KEYS = %w(
12
- trace_id
13
- public_key
14
- sample_rate
15
- release
16
- environment
17
- transaction
18
- user_id
19
- user_segment
20
- ).freeze
21
-
22
11
  # @return [Hash]
23
12
  attr_reader :items
24
13
 
@@ -68,7 +57,7 @@ module Sentry
68
57
  # hash to be used in the trace envelope header.
69
58
  # @return [Hash]
70
59
  def dynamic_sampling_context
71
- @items.select { |k, _v| DSC_KEYS.include?(k) }
60
+ @items
72
61
  end
73
62
 
74
63
  # Serialize the Baggage object back to a string.
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal
2
+
3
+ require 'securerandom'
4
+ require 'sentry/cron/monitor_config'
5
+
6
+ module Sentry
7
+ class CheckInEvent < Event
8
+ TYPE = 'check_in'
9
+
10
+ # uuid to identify this check-in.
11
+ # @return [String]
12
+ attr_accessor :check_in_id
13
+
14
+ # Identifier of the monitor for this check-in.
15
+ # @return [String]
16
+ attr_accessor :monitor_slug
17
+
18
+ # Duration of this check since it has started in seconds.
19
+ # @return [Integer, nil]
20
+ attr_accessor :duration
21
+
22
+ # Monitor configuration to support upserts.
23
+ # @return [Cron::MonitorConfig, nil]
24
+ attr_accessor :monitor_config
25
+
26
+ # Status of this check-in.
27
+ # @return [Symbol]
28
+ attr_accessor :status
29
+
30
+ VALID_STATUSES = %i(ok in_progress error)
31
+
32
+ def initialize(
33
+ slug:,
34
+ status:,
35
+ duration: nil,
36
+ monitor_config: nil,
37
+ check_in_id: nil,
38
+ **options
39
+ )
40
+ super(**options)
41
+
42
+ self.monitor_slug = slug
43
+ self.status = status
44
+ self.duration = duration
45
+ self.monitor_config = monitor_config
46
+ self.check_in_id = check_in_id || SecureRandom.uuid.delete('-')
47
+ end
48
+
49
+ # @return [Hash]
50
+ def to_hash
51
+ data = super
52
+ data[:check_in_id] = check_in_id
53
+ data[:monitor_slug] = monitor_slug
54
+ data[:status] = status
55
+ data[:duration] = duration if duration
56
+ data[:monitor_config] = monitor_config.to_hash if monitor_config
57
+ data
58
+ end
59
+ end
60
+ end
data/lib/sentry/client.rb CHANGED
@@ -76,7 +76,10 @@ module Sentry
76
76
  # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
77
77
  # @return [Event, nil]
78
78
  def event_from_exception(exception, hint = {})
79
- return unless @configuration.sending_allowed? && @configuration.exception_class_allowed?(exception)
79
+ return unless @configuration.sending_allowed?
80
+
81
+ ignore_exclusions = hint.delete(:ignore_exclusions) { false }
82
+ return if !ignore_exclusions && !@configuration.exception_class_allowed?(exception)
80
83
 
81
84
  integration_meta = Sentry.integrations[hint[:integration]]
82
85
 
@@ -101,6 +104,37 @@ module Sentry
101
104
  event
102
105
  end
103
106
 
107
+ # Initializes a CheckInEvent object with the given options.
108
+ #
109
+ # @param slug [String] identifier of this monitor
110
+ # @param status [Symbol] status of this check-in, one of {CheckInEvent::VALID_STATUSES}
111
+ # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
112
+ # @param duration [Integer, nil] seconds elapsed since this monitor started
113
+ # @param monitor_config [Cron::MonitorConfig, nil] configuration for this monitor
114
+ # @param check_in_id [String, nil] for updating the status of an existing monitor
115
+ #
116
+ # @return [Event]
117
+ def event_from_check_in(
118
+ slug,
119
+ status,
120
+ hint = {},
121
+ duration: nil,
122
+ monitor_config: nil,
123
+ check_in_id: nil
124
+ )
125
+ return unless configuration.sending_allowed?
126
+
127
+ CheckInEvent.new(
128
+ configuration: configuration,
129
+ integration_meta: Sentry.integrations[hint[:integration]],
130
+ slug: slug,
131
+ status: status,
132
+ duration: duration,
133
+ monitor_config: monitor_config,
134
+ check_in_id: check_in_id
135
+ )
136
+ end
137
+
104
138
  # Initializes an Event object with the given Transaction object.
105
139
  # @param transaction [Transaction] the transaction to be recorded.
106
140
  # @return [TransactionEvent]
@@ -145,6 +179,8 @@ module Sentry
145
179
  raise
146
180
  end
147
181
 
182
+ # @deprecated use Sentry.get_traceparent instead.
183
+ #
148
184
  # Generates a Sentry trace for distribted tracing from the given Span.
149
185
  # Returns `nil` if `config.propagate_traces` is `false`.
150
186
  # @param span [Span] the span to generate trace from.
@@ -157,7 +193,9 @@ module Sentry
157
193
  trace
158
194
  end
159
195
 
160
- # Generates a W3C Baggage header for distribted tracing from the given Span.
196
+ # @deprecated Use Sentry.get_baggage instead.
197
+ #
198
+ # Generates a W3C Baggage header for distributed tracing from the given Span.
161
199
  # Returns `nil` if `config.propagate_traces` is `false`.
162
200
  # @param span [Span] the span to generate trace from.
163
201
  # @return [String, nil]
@@ -14,6 +14,8 @@ module Sentry
14
14
  class Configuration
15
15
  include CustomInspection
16
16
  include LoggingHelper
17
+ include ArgumentCheckingHelper
18
+
17
19
  # Directories to be recognized as part of your app. e.g. if you
18
20
  # have an `engines` dir at the root of your project, you may want
19
21
  # to set this to something like /(app|config|engines|lib)/
@@ -179,7 +181,7 @@ module Sentry
179
181
  # Release tag to be passed with every event sent to Sentry.
180
182
  # We automatically try to set this to a git SHA or Capistrano release.
181
183
  # @return [String]
182
- attr_accessor :release
184
+ attr_reader :release
183
185
 
184
186
  # The sampling factor to apply to events. A value of 0.0 will not send
185
187
  # any events, and a value of 1.0 will send 100% of events.
@@ -214,8 +216,8 @@ module Sentry
214
216
  attr_reader :transport
215
217
 
216
218
  # Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
217
- # @return [Float]
218
- attr_accessor :traces_sample_rate
219
+ # @return [Float, nil]
220
+ attr_reader :traces_sample_rate
219
221
 
220
222
  # Take a Proc that controls the sample rate for every tracing event, e.g.
221
223
  # @example
@@ -227,6 +229,11 @@ module Sentry
227
229
  # @return [Proc]
228
230
  attr_accessor :traces_sampler
229
231
 
232
+ # Easier way to use performance tracing
233
+ # If set to true, will set traces_sample_rate to 1.0
234
+ # @return [Boolean, nil]
235
+ attr_reader :enable_tracing
236
+
230
237
  # Send diagnostic client reports about dropped events, true by default
231
238
  # tries to attach to an existing envelope max once every 30s
232
239
  # @return [Boolean]
@@ -236,14 +243,34 @@ module Sentry
236
243
  # @return [Boolean]
237
244
  attr_accessor :auto_session_tracking
238
245
 
246
+ # Allowlist of outgoing request targets to which sentry-trace and baggage headers are attached.
247
+ # Default is all (/.*/)
248
+ # @return [Array<String, Regexp>]
249
+ attr_accessor :trace_propagation_targets
250
+
239
251
  # The instrumenter to use, :sentry or :otel
240
252
  # @return [Symbol]
241
253
  attr_reader :instrumenter
242
254
 
255
+ # Take a float between 0.0 and 1.0 as the sample rate for capturing profiles.
256
+ # Note that this rate is relative to traces_sample_rate / traces_sampler,
257
+ # i.e. the profile is sampled by this rate after the transaction is sampled.
258
+ # @return [Float, nil]
259
+ attr_reader :profiles_sample_rate
260
+
243
261
  # these are not config options
244
262
  # @!visibility private
245
263
  attr_reader :errors, :gem_specs
246
264
 
265
+ # These exceptions could enter Puma's `lowlevel_error_handler` callback and the SDK's Puma integration
266
+ # But they are mostly considered as noise and should be ignored by default
267
+ # Please see https://github.com/getsentry/sentry-ruby/pull/2026 for more information
268
+ PUMA_IGNORE_DEFAULT = [
269
+ 'Puma::MiniSSL::SSLError',
270
+ 'Puma::HttpParserError',
271
+ 'Puma::HttpParserError501'
272
+ ].freeze
273
+
247
274
  # Most of these errors generate 4XX responses. In general, Sentry clients
248
275
  # only automatically report 5xx responses.
249
276
  IGNORE_DEFAULT = [
@@ -268,6 +295,8 @@ module Sentry
268
295
 
269
296
  INSTRUMENTERS = [:sentry, :otel]
270
297
 
298
+ PROPAGATION_TARGETS_MATCH_ALL = /.*/.freeze
299
+
271
300
  class << self
272
301
  # Post initialization callbacks are called at the end of initialization process
273
302
  # allowing extending the configuration of sentry-ruby by multiple extensions
@@ -293,7 +322,7 @@ module Sentry
293
322
  self.environment = environment_from_env
294
323
  self.enabled_environments = []
295
324
  self.exclude_loggers = []
296
- self.excluded_exceptions = IGNORE_DEFAULT.dup
325
+ self.excluded_exceptions = IGNORE_DEFAULT + PUMA_IGNORE_DEFAULT
297
326
  self.inspect_exception_causes_for_exclusion = true
298
327
  self.linecache = ::Sentry::LineCache.new
299
328
  self.logger = ::Sentry::Logger.new(STDOUT)
@@ -310,12 +339,13 @@ module Sentry
310
339
  self.dsn = ENV['SENTRY_DSN']
311
340
  self.server_name = server_name_from_env
312
341
  self.instrumenter = :sentry
342
+ self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
313
343
 
314
344
  self.before_send = nil
315
345
  self.before_send_transaction = nil
316
346
  self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
317
- self.traces_sample_rate = nil
318
347
  self.traces_sampler = nil
348
+ self.enable_tracing = nil
319
349
 
320
350
  @transport = Transport::Configuration.new
321
351
  @gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
@@ -329,6 +359,12 @@ module Sentry
329
359
 
330
360
  alias server= dsn=
331
361
 
362
+ def release=(value)
363
+ check_argument_type!(value, String, NilClass)
364
+
365
+ @release = value
366
+ end
367
+
332
368
  def async=(value)
333
369
  check_callable!("async", value)
334
370
 
@@ -384,6 +420,26 @@ module Sentry
384
420
  @instrumenter = INSTRUMENTERS.include?(instrumenter) ? instrumenter : :sentry
385
421
  end
386
422
 
423
+ def enable_tracing=(enable_tracing)
424
+ @enable_tracing = enable_tracing
425
+ @traces_sample_rate ||= 1.0 if enable_tracing
426
+ end
427
+
428
+ def is_numeric_or_nil?(value)
429
+ value.is_a?(Numeric) || value.nil?
430
+ end
431
+
432
+ def traces_sample_rate=(traces_sample_rate)
433
+ raise ArgumentError, "traces_sample_rate must be a Numeric or nil" unless is_numeric_or_nil?(traces_sample_rate)
434
+ @traces_sample_rate = traces_sample_rate
435
+ end
436
+
437
+ def profiles_sample_rate=(profiles_sample_rate)
438
+ raise ArgumentError, "profiles_sample_rate must be a Numeric or nil" unless is_numeric_or_nil?(profiles_sample_rate)
439
+ log_info("Please make sure to include the 'stackprof' gem in your Gemfile to use Profiling with Sentry.") unless defined?(StackProf)
440
+ @profiles_sample_rate = profiles_sample_rate
441
+ end
442
+
387
443
  def sending_allowed?
388
444
  @errors = []
389
445
 
@@ -413,8 +469,21 @@ module Sentry
413
469
  enabled_environments.empty? || enabled_environments.include?(environment)
414
470
  end
415
471
 
472
+ def valid_sample_rate?(sample_rate)
473
+ return false unless sample_rate.is_a?(Numeric)
474
+ sample_rate >= 0.0 && sample_rate <= 1.0
475
+ end
476
+
416
477
  def tracing_enabled?
417
- !!((@traces_sample_rate && @traces_sample_rate >= 0.0 && @traces_sample_rate <= 1.0) || @traces_sampler) && sending_allowed?
478
+ valid_sampler = !!((valid_sample_rate?(@traces_sample_rate)) || @traces_sampler)
479
+
480
+ (@enable_tracing != false) && valid_sampler && sending_allowed?
481
+ end
482
+
483
+ def profiling_enabled?
484
+ valid_sampler = !!(valid_sample_rate?(@profiles_sample_rate))
485
+
486
+ tracing_enabled? && valid_sampler && sending_allowed?
418
487
  end
419
488
 
420
489
  # @return [String, nil]
@@ -442,7 +511,7 @@ module Sentry
442
511
  def detect_release
443
512
  return unless sending_allowed?
444
513
 
445
- self.release ||= ReleaseDetector.detect_release(project_root: project_root, running_on_heroku: running_on_heroku?)
514
+ @release ||= ReleaseDetector.detect_release(project_root: project_root, running_on_heroku: running_on_heroku?)
446
515
 
447
516
  if running_on_heroku? && release.nil?
448
517
  log_warn(HEROKU_DYNO_METADATA_MESSAGE)
@@ -0,0 +1,61 @@
1
+ module Sentry
2
+ module Cron
3
+ module MonitorCheckIns
4
+ module Patch
5
+ def perform(*args)
6
+ slug = self.class.sentry_monitor_slug || self.class.name
7
+ monitor_config = self.class.sentry_monitor_config
8
+
9
+ check_in_id = Sentry.capture_check_in(slug,
10
+ :in_progress,
11
+ monitor_config: monitor_config)
12
+
13
+ start = Sentry.utc_now.to_i
14
+ ret = super
15
+ duration = Sentry.utc_now.to_i - start
16
+
17
+ Sentry.capture_check_in(slug,
18
+ :ok,
19
+ check_in_id: check_in_id,
20
+ duration: duration,
21
+ monitor_config: monitor_config)
22
+
23
+ ret
24
+ rescue Exception
25
+ duration = Sentry.utc_now.to_i - start
26
+
27
+ Sentry.capture_check_in(slug,
28
+ :error,
29
+ check_in_id: check_in_id,
30
+ duration: duration,
31
+ monitor_config: monitor_config)
32
+
33
+ raise
34
+ end
35
+ end
36
+
37
+ module ClassMethods
38
+ def sentry_monitor_check_ins(slug: nil, monitor_config: nil)
39
+ @sentry_monitor_slug = slug
40
+ @sentry_monitor_config = monitor_config
41
+
42
+ prepend Patch
43
+ end
44
+
45
+ def sentry_monitor_slug
46
+ @sentry_monitor_slug
47
+ end
48
+
49
+ def sentry_monitor_config
50
+ @sentry_monitor_config
51
+ end
52
+ end
53
+
54
+ extend ClassMethods
55
+
56
+ def self.included(base)
57
+ base.extend(ClassMethods)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal
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
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
@@ -5,7 +5,7 @@ module Sentry
5
5
  class Envelope
6
6
  class Item
7
7
  STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
8
- MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 200
8
+ MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000
9
9
 
10
10
  attr_accessor :headers, :payload
11
11
 
@@ -19,10 +19,7 @@ module Sentry
19
19
  end
20
20
 
21
21
  def to_s
22
- <<~ITEM
23
- #{JSON.generate(@headers)}
24
- #{JSON.generate(@payload)}
25
- ITEM
22
+ [JSON.generate(@headers), JSON.generate(@payload)].join("\n")
26
23
  end
27
24
 
28
25
  def serialize
data/lib/sentry/event.rb CHANGED
@@ -37,6 +37,11 @@ module Sentry
37
37
  # @return [RequestInterface]
38
38
  attr_reader :request
39
39
 
40
+ # Dynamic Sampling Context (DSC) that gets attached
41
+ # as the trace envelope header in the transport.
42
+ # @return [Hash, nil]
43
+ attr_accessor :dynamic_sampling_context
44
+
40
45
  # @param configuration [Configuration]
41
46
  # @param integration_meta [Hash, nil]
42
47
  # @param message [String, nil]
@@ -54,6 +59,7 @@ module Sentry
54
59
  @tags = {}
55
60
 
56
61
  @fingerprint = []
62
+ @dynamic_sampling_context = nil
57
63
 
58
64
  # configuration data that's directly used by events
59
65
  @server_name = configuration.server_name