sentry-ruby-core 5.19.0 → 5.20.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sentry/attachment.rb +3 -5
  3. data/lib/sentry/backtrace.rb +1 -3
  4. data/lib/sentry/baggage.rb +6 -6
  5. data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
  6. data/lib/sentry/check_in_event.rb +4 -4
  7. data/lib/sentry/client.rb +9 -9
  8. data/lib/sentry/configuration.rb +28 -13
  9. data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
  10. data/lib/sentry/cron/monitor_check_ins.rb +1 -1
  11. data/lib/sentry/cron/monitor_config.rb +1 -1
  12. data/lib/sentry/dsn.rb +3 -3
  13. data/lib/sentry/envelope.rb +8 -8
  14. data/lib/sentry/event.rb +7 -7
  15. data/lib/sentry/graphql.rb +1 -1
  16. data/lib/sentry/hub.rb +8 -1
  17. data/lib/sentry/interfaces/mechanism.rb +1 -1
  18. data/lib/sentry/interfaces/request.rb +5 -5
  19. data/lib/sentry/interfaces/single_exception.rb +1 -1
  20. data/lib/sentry/interfaces/stacktrace.rb +3 -1
  21. data/lib/sentry/interfaces/stacktrace_builder.rb +15 -2
  22. data/lib/sentry/logger.rb +1 -1
  23. data/lib/sentry/metrics/aggregator.rb +12 -12
  24. data/lib/sentry/metrics/set_metric.rb +2 -2
  25. data/lib/sentry/metrics.rb +15 -15
  26. data/lib/sentry/net/http.rb +1 -1
  27. data/lib/sentry/profiler.rb +19 -20
  28. data/lib/sentry/propagation_context.rb +1 -1
  29. data/lib/sentry/rack/capture_exceptions.rb +1 -1
  30. data/lib/sentry/rack.rb +2 -2
  31. data/lib/sentry/rake.rb +2 -2
  32. data/lib/sentry/release_detector.rb +4 -4
  33. data/lib/sentry/scope.rb +1 -0
  34. data/lib/sentry/session_flusher.rb +1 -1
  35. data/lib/sentry/span.rb +6 -0
  36. data/lib/sentry/test_helper.rb +1 -1
  37. data/lib/sentry/transaction.rb +2 -2
  38. data/lib/sentry/transaction_event.rb +1 -1
  39. data/lib/sentry/transport/http_transport.rb +12 -12
  40. data/lib/sentry/transport.rb +4 -4
  41. data/lib/sentry/utils/env_helper.rb +21 -0
  42. data/lib/sentry/utils/real_ip.rb +1 -1
  43. data/lib/sentry/version.rb +1 -1
  44. data/lib/sentry-ruby.rb +1 -1
  45. metadata +6 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b47e81567b685cb3ad64e889f638f7dd9b97ee8c7cf3e0eee5907c053cf784dc
4
- data.tar.gz: 9480a3870fce66342cffae3f818f220658d8f8368c46d481a27a9bbba9f3c8a1
3
+ metadata.gz: 58924eaaabcd9af00039a761dc76db3fdbfdad597ac5ec274cf5b09121706ffe
4
+ data.tar.gz: 931128e011f2b359bb00ff3a55e6924dc06cd083fb8944c278a2bac6186af767
5
5
  SHA512:
6
- metadata.gz: 7afc772277ecf7be43cc029f4cf988585f469f08d1fcfab696bad471a1ddb8269c18f8c946a3af94a8bf4775f93ef9851c57940b05f8c09cb90de812e15f9f6d
7
- data.tar.gz: 1f1236a73ed900dc9d38a5448c154dcf4a66ab55eb490528e214f1b3f393a99eccbaa1d303d9c8a3064060b0447c21d6d59f5fdbbcb843203c0e00a4c18adb89
6
+ metadata.gz: b1a1aa47dcc33056a50e76faaee84a299093441a7994b9f377135a1a172a40f4c581a31ed553873c8ac960eff88d61303c22b98c07772590f36bedd4711b28be
7
+ data.tar.gz: 86ebfa52b4ddadeb7307985c4312b9ada2c0180be8ff65e2cf3af3eae3b6416403269642fdb4f502baa2f56ebd4e3f63b681e9e47de8b483db460d6f232d43ee
@@ -8,13 +8,13 @@ module Sentry
8
8
 
9
9
  def initialize(bytes: nil, filename: nil, content_type: nil, path: nil)
10
10
  @bytes = bytes
11
- @filename = infer_filename(filename, path)
11
+ @filename = filename || infer_filename(path)
12
12
  @path = path
13
13
  @content_type = content_type
14
14
  end
15
15
 
16
16
  def to_envelope_headers
17
- { type: 'attachment', filename: filename, content_type: content_type, length: payload.bytesize }
17
+ { type: "attachment", filename: filename, content_type: content_type, length: payload.bytesize }
18
18
  end
19
19
 
20
20
  def payload
@@ -29,9 +29,7 @@ module Sentry
29
29
 
30
30
  private
31
31
 
32
- def infer_filename(filename, path)
33
- return filename if filename
34
-
32
+ def infer_filename(path)
35
33
  if path
36
34
  File.basename(path)
37
35
  else
@@ -80,8 +80,6 @@ module Sentry
80
80
  end
81
81
  end
82
82
 
83
- APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/.freeze
84
-
85
83
  # holder for an Array of Backtrace::Line instances
86
84
  attr_reader :lines
87
85
 
@@ -91,7 +89,7 @@ module Sentry
91
89
  ruby_lines = backtrace_cleanup_callback.call(ruby_lines) if backtrace_cleanup_callback
92
90
 
93
91
  in_app_pattern ||= begin
94
- Regexp.new("^(#{project_root}/)?#{app_dirs_pattern || APP_DIRS_PATTERN}")
92
+ Regexp.new("^(#{project_root}/)?#{app_dirs_pattern}")
95
93
  end
96
94
 
97
95
  lines = ruby_lines.to_a.map do |unparsed_line|
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'cgi'
3
+ require "cgi"
4
4
 
5
5
  module Sentry
6
6
  # A {https://www.w3.org/TR/baggage W3C Baggage Header} implementation.
7
7
  class Baggage
8
- SENTRY_PREFIX = 'sentry-'
8
+ SENTRY_PREFIX = "sentry-"
9
9
  SENTRY_PREFIX_REGEX = /^sentry-/.freeze
10
10
 
11
11
  # @return [Hash]
@@ -30,14 +30,14 @@ module Sentry
30
30
  items = {}
31
31
  mutable = true
32
32
 
33
- header.split(',').each do |item|
33
+ header.split(",").each do |item|
34
34
  item = item.strip
35
- key, val = item.split('=')
35
+ key, val = item.split("=")
36
36
 
37
37
  next unless key && val
38
38
  next unless key =~ SENTRY_PREFIX_REGEX
39
39
 
40
- baggage_key = key.split('-')[1]
40
+ baggage_key = key.split("-")[1]
41
41
  next unless baggage_key
42
42
 
43
43
  items[CGI.unescape(baggage_key)] = CGI.unescape(val)
@@ -64,7 +64,7 @@ module Sentry
64
64
  # @return [String]
65
65
  def serialize
66
66
  items = @items.map { |k, v| "#{SENTRY_PREFIX}#{CGI.escape(k)}=#{CGI.escape(v)}" }
67
- items.join(',')
67
+ items.join(",")
68
68
  end
69
69
  end
70
70
  end
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
3
+ require "logger"
4
4
 
5
5
  module Sentry
6
6
  class Breadcrumb
7
7
  module SentryLogger
8
8
  LEVELS = {
9
- ::Logger::DEBUG => 'debug',
10
- ::Logger::INFO => 'info',
11
- ::Logger::WARN => 'warn',
12
- ::Logger::ERROR => 'error',
13
- ::Logger::FATAL => 'fatal'
9
+ ::Logger::DEBUG => "debug",
10
+ ::Logger::INFO => "info",
11
+ ::Logger::WARN => "warn",
12
+ ::Logger::ERROR => "error",
13
+ ::Logger::FATAL => "fatal"
14
14
  }.freeze
15
15
 
16
16
  def add(*args, &block)
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'securerandom'
4
- require 'sentry/cron/monitor_config'
3
+ require "securerandom"
4
+ require "sentry/cron/monitor_config"
5
5
 
6
6
  module Sentry
7
7
  class CheckInEvent < Event
8
- TYPE = 'check_in'
8
+ TYPE = "check_in"
9
9
 
10
10
  # uuid to identify this check-in.
11
11
  # @return [String]
@@ -43,7 +43,7 @@ module Sentry
43
43
  self.status = status
44
44
  self.duration = duration
45
45
  self.monitor_config = monitor_config
46
- self.check_in_id = check_in_id || SecureRandom.uuid.delete('-')
46
+ self.check_in_id = check_in_id || SecureRandom.uuid.delete("-")
47
47
  end
48
48
 
49
49
  # @return [Hash]
data/lib/sentry/client.rb CHANGED
@@ -30,7 +30,7 @@ module Sentry
30
30
  else
31
31
  @transport =
32
32
  case configuration.dsn&.scheme
33
- when 'http', 'https'
33
+ when "http", "https"
34
34
  HTTPTransport.new(configuration)
35
35
  else
36
36
  DummyTransport.new(configuration)
@@ -49,7 +49,7 @@ module Sentry
49
49
  return unless configuration.sending_allowed?
50
50
 
51
51
  if event.is_a?(ErrorEvent) && !configuration.sample_allowed?
52
- transport.record_lost_event(:sample_rate, 'error')
52
+ transport.record_lost_event(:sample_rate, "error")
53
53
  return
54
54
  end
55
55
 
@@ -64,11 +64,11 @@ module Sentry
64
64
  if event.nil?
65
65
  log_debug("Discarded event because one of the event processors returned nil")
66
66
  transport.record_lost_event(:event_processor, data_category)
67
- transport.record_lost_event(:event_processor, 'span', num: spans_before + 1) if is_transaction
67
+ transport.record_lost_event(:event_processor, "span", num: spans_before + 1) if is_transaction
68
68
  return
69
69
  elsif is_transaction
70
70
  spans_delta = spans_before - event.spans.size
71
- transport.record_lost_event(:event_processor, 'span', num: spans_delta) if spans_delta > 0
71
+ transport.record_lost_event(:event_processor, "span", num: spans_delta) if spans_delta > 0
72
72
  end
73
73
 
74
74
  if async_block = configuration.async
@@ -76,7 +76,7 @@ module Sentry
76
76
  elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
77
77
  unless dispatch_background_event(event, hint)
78
78
  transport.record_lost_event(:queue_overflow, data_category)
79
- transport.record_lost_event(:queue_overflow, 'span', num: spans_before + 1) if is_transaction
79
+ transport.record_lost_event(:queue_overflow, "span", num: spans_before + 1) if is_transaction
80
80
  end
81
81
  else
82
82
  send_event(event, hint)
@@ -195,13 +195,13 @@ module Sentry
195
195
 
196
196
  if event.nil?
197
197
  log_debug("Discarded event because before_send_transaction returned nil")
198
- transport.record_lost_event(:before_send, 'transaction')
199
- transport.record_lost_event(:before_send, 'span', num: spans_before + 1)
198
+ transport.record_lost_event(:before_send, "transaction")
199
+ transport.record_lost_event(:before_send, "span", num: spans_before + 1)
200
200
  return
201
201
  else
202
202
  spans_after = event.is_a?(TransactionEvent) ? event.spans.size : 0
203
203
  spans_delta = spans_before - spans_after
204
- transport.record_lost_event(:before_send, 'span', num: spans_delta) if spans_delta > 0
204
+ transport.record_lost_event(:before_send, "span", num: spans_delta) if spans_delta > 0
205
205
  end
206
206
  end
207
207
 
@@ -212,7 +212,7 @@ module Sentry
212
212
  rescue => e
213
213
  log_error("Event sending failed", e, debug: configuration.debug)
214
214
  transport.record_lost_event(:network_error, data_category)
215
- transport.record_lost_event(:network_error, 'span', num: spans_before + 1) if event.is_a?(TransactionEvent)
215
+ transport.record_lost_event(:network_error, "span", num: spans_before + 1) if event.is_a?(TransactionEvent)
216
216
  raise
217
217
  end
218
218
 
@@ -4,6 +4,7 @@ require "concurrent/utility/processor_counter"
4
4
 
5
5
  require "sentry/utils/exception_cause_chain"
6
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"
@@ -22,6 +23,8 @@ module Sentry
22
23
  # have an `engines` dir at the root of your project, you may want
23
24
  # to set this to something like /(app|config|engines|lib)/
24
25
  #
26
+ # The default is value is /(bin|exe|app|config|lib|test|spec)/
27
+ #
25
28
  # @return [Regexp, nil]
26
29
  attr_accessor :app_dirs_pattern
27
30
 
@@ -187,6 +190,11 @@ module Sentry
187
190
  # @return [String]
188
191
  attr_accessor :project_root
189
192
 
193
+ # Whether to strip the load path while constructing the backtrace frame filename.
194
+ # Defaults to true.
195
+ # @return [Boolean]
196
+ attr_accessor :strip_backtrace_load_path
197
+
190
198
  # Insert sentry-trace to outgoing requests' headers
191
199
  # @return [Boolean]
192
200
  attr_accessor :propagate_traces
@@ -302,18 +310,18 @@ module Sentry
302
310
  # But they are mostly considered as noise and should be ignored by default
303
311
  # Please see https://github.com/getsentry/sentry-ruby/pull/2026 for more information
304
312
  PUMA_IGNORE_DEFAULT = [
305
- 'Puma::MiniSSL::SSLError',
306
- 'Puma::HttpParserError',
307
- 'Puma::HttpParserError501'
313
+ "Puma::MiniSSL::SSLError",
314
+ "Puma::HttpParserError",
315
+ "Puma::HttpParserError501"
308
316
  ].freeze
309
317
 
310
318
  # Most of these errors generate 4XX responses. In general, Sentry clients
311
319
  # only automatically report 5xx responses.
312
320
  IGNORE_DEFAULT = [
313
- 'Mongoid::Errors::DocumentNotFound',
314
- 'Rack::QueryParser::InvalidParameterError',
315
- 'Rack::QueryParser::ParameterTypeError',
316
- 'Sinatra::NotFound'
321
+ "Mongoid::Errors::DocumentNotFound",
322
+ "Rack::QueryParser::InvalidParameterError",
323
+ "Rack::QueryParser::ParameterTypeError",
324
+ "Sinatra::NotFound"
317
325
  ].freeze
318
326
 
319
327
  RACK_ENV_WHITELIST_DEFAULT = %w[
@@ -335,6 +343,8 @@ module Sentry
335
343
 
336
344
  DEFAULT_PATCHES = %i[redis puma http].freeze
337
345
 
346
+ APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test|spec)/.freeze
347
+
338
348
  class << self
339
349
  # Post initialization callbacks are called at the end of initialization process
340
350
  # allowing extending the configuration of sentry-ruby by multiple extensions
@@ -349,11 +359,12 @@ module Sentry
349
359
  end
350
360
 
351
361
  def initialize
352
- self.app_dirs_pattern = nil
353
- self.debug = false
362
+ self.app_dirs_pattern = APP_DIRS_PATTERN
363
+ self.debug = Sentry::Utils::EnvHelper.env_to_bool(ENV["SENTRY_DEBUG"])
354
364
  self.background_worker_threads = (processor_count / 2.0).ceil
355
365
  self.background_worker_max_queue = BackgroundWorker::DEFAULT_MAX_QUEUE
356
366
  self.backtrace_cleanup_callback = nil
367
+ self.strip_backtrace_load_path = true
357
368
  self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
358
369
  self.breadcrumbs_logger = []
359
370
  self.context_lines = 3
@@ -377,7 +388,10 @@ module Sentry
377
388
  self.enable_backpressure_handling = false
378
389
  self.trusted_proxies = []
379
390
  self.dsn = ENV['SENTRY_DSN']
380
- self.spotlight = false
391
+
392
+ spotlight_env = ENV['SENTRY_SPOTLIGHT']
393
+ spotlight_bool = Sentry::Utils::EnvHelper.env_to_bool(spotlight_env, strict: true)
394
+ self.spotlight = spotlight_bool.nil? ? (spotlight_env || false) : spotlight_bool
381
395
  self.server_name = server_name_from_env
382
396
  self.instrumenter = :sentry
383
397
  self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
@@ -555,7 +569,8 @@ module Sentry
555
569
  app_dirs_pattern: @app_dirs_pattern,
556
570
  linecache: @linecache,
557
571
  context_lines: @context_lines,
558
- backtrace_cleanup_callback: @backtrace_cleanup_callback
572
+ backtrace_cleanup_callback: @backtrace_cleanup_callback,
573
+ strip_backtrace_load_path: @strip_backtrace_load_path
559
574
  )
560
575
  end
561
576
 
@@ -632,12 +647,12 @@ module Sentry
632
647
  end
633
648
 
634
649
  def environment_from_env
635
- ENV['SENTRY_CURRENT_ENV'] || ENV['SENTRY_ENVIRONMENT'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
650
+ ENV["SENTRY_CURRENT_ENV"] || ENV["SENTRY_ENVIRONMENT"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
636
651
  end
637
652
 
638
653
  def server_name_from_env
639
654
  if running_on_heroku?
640
- ENV['DYNO']
655
+ ENV["DYNO"]
641
656
  else
642
657
  # Try to resolve the hostname to an FQDN, but fall back to whatever
643
658
  # the load name is.
@@ -2,7 +2,7 @@
2
2
 
3
3
  return if Object.method_defined?(:deep_dup)
4
4
 
5
- require 'sentry/core_ext/object/duplicable'
5
+ require "sentry/core_ext/object/duplicable"
6
6
 
7
7
  #########################################
8
8
  # This file was copied from Rails 5.2 #
@@ -57,7 +57,7 @@ module Sentry
57
57
 
58
58
  def sentry_monitor_slug(name: self.name)
59
59
  @sentry_monitor_slug ||= begin
60
- slug = name.gsub('::', '-').downcase
60
+ slug = name.gsub("::", "-").downcase
61
61
  slug[-MAX_SLUG_LENGTH..-1] || slug
62
62
  end
63
63
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'sentry/cron/monitor_schedule'
3
+ require "sentry/cron/monitor_schedule"
4
4
 
5
5
  module Sentry
6
6
  module Cron
data/lib/sentry/dsn.rb CHANGED
@@ -4,7 +4,7 @@ require "uri"
4
4
 
5
5
  module Sentry
6
6
  class DSN
7
- PORT_MAP = { 'http' => 80, 'https' => 443 }.freeze
7
+ PORT_MAP = { "http" => 80, "https" => 443 }.freeze
8
8
  REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
9
9
 
10
10
  attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
@@ -13,7 +13,7 @@ module Sentry
13
13
  @raw_value = dsn_string
14
14
 
15
15
  uri = URI.parse(dsn_string)
16
- uri_path = uri.path.split('/')
16
+ uri_path = uri.path.split("/")
17
17
 
18
18
  if uri.user
19
19
  # DSN-style string
@@ -25,7 +25,7 @@ module Sentry
25
25
  @scheme = uri.scheme
26
26
  @host = uri.host
27
27
  @port = uri.port if uri.port
28
- @path = uri_path.join('/')
28
+ @path = uri_path.join("/")
29
29
  end
30
30
 
31
31
  def valid?
@@ -15,19 +15,19 @@ module Sentry
15
15
  end
16
16
 
17
17
  def type
18
- @headers[:type] || 'event'
18
+ @headers[:type] || "event"
19
19
  end
20
20
 
21
21
  # rate limits and client reports use the data_category rather than envelope item type
22
22
  def self.data_category(type)
23
23
  case type
24
- when 'session', 'attachment', 'transaction', 'profile', 'span' then type
25
- when 'sessions' then 'session'
26
- when 'check_in' then 'monitor'
27
- when 'statsd', 'metric_meta' then 'metric_bucket'
28
- when 'event' then 'error'
29
- when 'client_report' then 'internal'
30
- else 'default'
24
+ when "session", "attachment", "transaction", "profile", "span" then type
25
+ when "sessions" then "session"
26
+ when "check_in" then "monitor"
27
+ when "statsd", "metric_meta" then "metric_bucket"
28
+ when "event" then "error"
29
+ when "client_report" then "internal"
30
+ else "default"
31
31
  end
32
32
  end
33
33
 
data/lib/sentry/event.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'socket'
4
- require 'securerandom'
5
- require 'sentry/interface'
6
- require 'sentry/backtrace'
7
- require 'sentry/utils/real_ip'
8
- require 'sentry/utils/request_id'
9
- require 'sentry/utils/custom_inspection'
3
+ require "socket"
4
+ require "securerandom"
5
+ require "sentry/interface"
6
+ require "sentry/backtrace"
7
+ require "sentry/utils/real_ip"
8
+ require "sentry/utils/request_id"
9
+ require "sentry/utils/custom_inspection"
10
10
 
11
11
  module Sentry
12
12
  # This is an abstract class that defines the shared attributes of an event.
@@ -4,6 +4,6 @@ Sentry.register_patch(:graphql) do |config|
4
4
  if defined?(::GraphQL::Schema) && defined?(::GraphQL::Tracing::SentryTrace) && ::GraphQL::Schema.respond_to?(:trace_with)
5
5
  ::GraphQL::Schema.trace_with(::GraphQL::Tracing::SentryTrace, set_transaction_name: true)
6
6
  else
7
- config.logger.warn(Sentry::LOGGER_PROGNAME) { 'You tried to enable the GraphQL integration but no GraphQL gem was detected. Make sure you have the `graphql` gem (>= 2.2.6) in your Gemfile.' }
7
+ config.logger.warn(Sentry::LOGGER_PROGNAME) { "You tried to enable the GraphQL integration but no GraphQL gem was detected. Make sure you have the `graphql` gem (>= 2.2.6) in your Gemfile." }
8
8
  end
9
9
  end
data/lib/sentry/hub.rb CHANGED
@@ -73,7 +73,13 @@ module Sentry
73
73
  end
74
74
 
75
75
  def pop_scope
76
- @stack.pop
76
+ if @stack.size > 1
77
+ @stack.pop
78
+ else
79
+ # We never want to enter a situation where we have no scope and no client
80
+ client = current_client
81
+ @stack = [Layer.new(client, Scope.new)]
82
+ end
77
83
  end
78
84
 
79
85
  def start_transaction(transaction: nil, custom_sampling_context: {}, instrumenter: :sentry, **options)
@@ -214,6 +220,7 @@ module Sentry
214
220
  end
215
221
 
216
222
  def add_breadcrumb(breadcrumb, hint: {})
223
+ return unless current_client
217
224
  return unless configuration.enabled_in_current_env?
218
225
 
219
226
  if before_breadcrumb = current_client.configuration.before_breadcrumb
@@ -12,7 +12,7 @@ module Sentry
12
12
  # @return [Boolean]
13
13
  attr_accessor :handled
14
14
 
15
- def initialize(type: 'generic', handled: true)
15
+ def initialize(type: "generic", handled: true)
16
16
  @type = type
17
17
  @handled = handled
18
18
  end
@@ -59,7 +59,7 @@ module Sentry
59
59
  self.query_string = request.query_string
60
60
  end
61
61
 
62
- self.url = request.scheme && request.url.split('?').first
62
+ self.url = request.scheme && request.url.split("?").first
63
63
  self.method = request.request_method
64
64
 
65
65
  self.headers = filter_and_format_headers(env, send_default_pii)
@@ -85,14 +85,14 @@ module Sentry
85
85
  env.each_with_object({}) do |(key, value), memo|
86
86
  begin
87
87
  key = key.to_s # rack env can contain symbols
88
- next memo['X-Request-Id'] ||= Utils::RequestId.read_from(env) if Utils::RequestId::REQUEST_ID_HEADERS.include?(key)
88
+ next memo["X-Request-Id"] ||= Utils::RequestId.read_from(env) if Utils::RequestId::REQUEST_ID_HEADERS.include?(key)
89
89
  next if is_server_protocol?(key, value, env["SERVER_PROTOCOL"])
90
90
  next if is_skippable_header?(key)
91
91
  next if key == "HTTP_AUTHORIZATION" && !send_default_pii
92
92
 
93
93
  # Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
94
94
  key = key.sub(/^HTTP_/, "")
95
- key = key.split('_').map(&:capitalize).join('-')
95
+ key = key.split("_").map(&:capitalize).join("-")
96
96
 
97
97
  memo[key] = Utils::EncodingHelper.encode_to_utf_8(value.to_s)
98
98
  rescue StandardError => e
@@ -108,7 +108,7 @@ module Sentry
108
108
  def is_skippable_header?(key)
109
109
  key.upcase != key || # lower-case envs aren't real http headers
110
110
  key == "HTTP_COOKIE" || # Cookies don't go here, they go somewhere else
111
- !(key.start_with?('HTTP_') || CONTENT_HEADERS.include?(key))
111
+ !(key.start_with?("HTTP_") || CONTENT_HEADERS.include?(key))
112
112
  end
113
113
 
114
114
  # In versions < 3, Rack adds in an incorrect HTTP_VERSION key, which causes downstream
@@ -120,7 +120,7 @@ module Sentry
120
120
  rack_version = Gem::Version.new(::Rack.release)
121
121
  return false if rack_version >= Gem::Version.new("3.0")
122
122
 
123
- key == 'HTTP_VERSION' && value == protocol_version
123
+ key == "HTTP_VERSION" && value == protocol_version
124
124
  end
125
125
 
126
126
  def filter_and_format_env(env, rack_env_whitelist)
@@ -26,7 +26,7 @@ module Sentry
26
26
 
27
27
  @value = Utils::EncodingHelper.encode_to_utf_8(exception_message.byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES))
28
28
 
29
- @module = exception.class.to_s.split('::')[0...-1].join('::')
29
+ @module = exception.class.to_s.split("::")[0...-1].join("::")
30
30
  @thread_id = Thread.current.object_id
31
31
  @stacktrace = stacktrace
32
32
  @mechanism = mechanism
@@ -27,8 +27,9 @@ module Sentry
27
27
  attr_accessor :abs_path, :context_line, :function, :in_app, :filename,
28
28
  :lineno, :module, :pre_context, :post_context, :vars
29
29
 
30
- def initialize(project_root, line)
30
+ def initialize(project_root, line, strip_backtrace_load_path = true)
31
31
  @project_root = project_root
32
+ @strip_backtrace_load_path = strip_backtrace_load_path
32
33
 
33
34
  @abs_path = line.file
34
35
  @function = line.method if line.method
@@ -44,6 +45,7 @@ module Sentry
44
45
 
45
46
  def compute_filename
46
47
  return if abs_path.nil?
48
+ return abs_path unless @strip_backtrace_load_path
47
49
 
48
50
  prefix =
49
51
  if under_project_root? && in_app
@@ -17,22 +17,35 @@ module Sentry
17
17
  # @return [Proc, nil]
18
18
  attr_reader :backtrace_cleanup_callback
19
19
 
20
+ # @return [Boolean]
21
+ attr_reader :strip_backtrace_load_path
22
+
20
23
  # @param project_root [String]
21
24
  # @param app_dirs_pattern [Regexp, nil]
22
25
  # @param linecache [LineCache]
23
26
  # @param context_lines [Integer, nil]
24
27
  # @param backtrace_cleanup_callback [Proc, nil]
28
+ # @param strip_backtrace_load_path [Boolean]
25
29
  # @see Configuration#project_root
26
30
  # @see Configuration#app_dirs_pattern
27
31
  # @see Configuration#linecache
28
32
  # @see Configuration#context_lines
29
33
  # @see Configuration#backtrace_cleanup_callback
30
- def initialize(project_root:, app_dirs_pattern:, linecache:, context_lines:, backtrace_cleanup_callback: nil)
34
+ # @see Configuration#strip_backtrace_load_path
35
+ def initialize(
36
+ project_root:,
37
+ app_dirs_pattern:,
38
+ linecache:,
39
+ context_lines:,
40
+ backtrace_cleanup_callback: nil,
41
+ strip_backtrace_load_path: true
42
+ )
31
43
  @project_root = project_root
32
44
  @app_dirs_pattern = app_dirs_pattern
33
45
  @linecache = linecache
34
46
  @context_lines = context_lines
35
47
  @backtrace_cleanup_callback = backtrace_cleanup_callback
48
+ @strip_backtrace_load_path = strip_backtrace_load_path
36
49
  end
37
50
 
38
51
  # Generates a StacktraceInterface with the given backtrace.
@@ -73,7 +86,7 @@ module Sentry
73
86
  private
74
87
 
75
88
  def convert_parsed_line_into_frame(line)
76
- frame = StacktraceInterface::Frame.new(project_root, line)
89
+ frame = StacktraceInterface::Frame.new(project_root, line, strip_backtrace_load_path)
77
90
  frame.set_context(linecache, context_lines) if context_lines
78
91
  frame
79
92
  end
data/lib/sentry/logger.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
3
+ require "logger"
4
4
 
5
5
  module Sentry
6
6
  class Logger < ::Logger
@@ -41,8 +41,8 @@ module Sentry
41
41
  @stacktrace_builder = configuration.stacktrace_builder
42
42
 
43
43
  @default_tags = {}
44
- @default_tags['release'] = configuration.release if configuration.release
45
- @default_tags['environment'] = configuration.environment if configuration.environment
44
+ @default_tags["release"] = configuration.release if configuration.release
45
+ @default_tags["environment"] = configuration.environment if configuration.environment
46
46
 
47
47
  @mutex = Mutex.new
48
48
 
@@ -59,7 +59,7 @@ module Sentry
59
59
  def add(type,
60
60
  key,
61
61
  value,
62
- unit: 'none',
62
+ unit: "none",
63
63
  tags: {},
64
64
  timestamp: nil,
65
65
  stacklevel: nil)
@@ -98,7 +98,7 @@ module Sentry
98
98
  unless flushable_buckets.empty?
99
99
  payload = serialize_buckets(flushable_buckets)
100
100
  envelope.add_item(
101
- { type: 'statsd', length: payload.bytesize },
101
+ { type: "statsd", length: payload.bytesize },
102
102
  payload
103
103
  )
104
104
  end
@@ -107,7 +107,7 @@ module Sentry
107
107
  code_locations.each do |timestamp, locations|
108
108
  payload = serialize_locations(timestamp, locations)
109
109
  envelope.add_item(
110
- { type: 'metric_meta', content_type: 'application/json' },
110
+ { type: "metric_meta", content_type: "application/json" },
111
111
  payload
112
112
  )
113
113
  end
@@ -161,8 +161,8 @@ module Sentry
161
161
  buckets.map do |timestamp, timestamp_buckets|
162
162
  timestamp_buckets.map do |metric_key, metric|
163
163
  type, key, unit, tags = metric_key
164
- values = metric.serialize.join(':')
165
- sanitized_tags = tags.map { |k, v| "#{sanitize_tag_key(k)}:#{sanitize_tag_value(v)}" }.join(',')
164
+ values = metric.serialize.join(":")
165
+ sanitized_tags = tags.map { |k, v| "#{sanitize_tag_key(k)}:#{sanitize_tag_value(v)}" }.join(",")
166
166
 
167
167
  "#{sanitize_key(key)}@#{sanitize_unit(unit)}:#{values}|#{type}|\##{sanitized_tags}|T#{timestamp}"
168
168
  end
@@ -175,22 +175,22 @@ module Sentry
175
175
  mri = "#{type}:#{sanitize_key(key)}@#{sanitize_unit(unit)}"
176
176
 
177
177
  # note this needs to be an array but it really doesn't serve a purpose right now
178
- [mri, [location.merge(type: 'location')]]
178
+ [mri, [location.merge(type: "location")]]
179
179
  end.to_h
180
180
 
181
181
  { timestamp: timestamp, mapping: mapping }
182
182
  end
183
183
 
184
184
  def sanitize_key(key)
185
- key.gsub(KEY_SANITIZATION_REGEX, '_')
185
+ key.gsub(KEY_SANITIZATION_REGEX, "_")
186
186
  end
187
187
 
188
188
  def sanitize_unit(unit)
189
- unit.gsub(UNIT_SANITIZATION_REGEX, '')
189
+ unit.gsub(UNIT_SANITIZATION_REGEX, "")
190
190
  end
191
191
 
192
192
  def sanitize_tag_key(key)
193
- key.gsub(TAG_KEY_SANITIZATION_REGEX, '')
193
+ key.gsub(TAG_KEY_SANITIZATION_REGEX, "")
194
194
  end
195
195
 
196
196
  def sanitize_tag_value(value)
@@ -209,7 +209,7 @@ module Sentry
209
209
  updated_tags = @default_tags.merge(tags)
210
210
 
211
211
  transaction_name = get_transaction_name
212
- updated_tags['transaction'] = transaction_name if transaction_name
212
+ updated_tags["transaction"] = transaction_name if transaction_name
213
213
 
214
214
  updated_tags
215
215
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
4
- require 'zlib'
3
+ require "set"
4
+ require "zlib"
5
5
 
6
6
  module Sentry
7
7
  module Metrics
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'sentry/metrics/metric'
4
- require 'sentry/metrics/counter_metric'
5
- require 'sentry/metrics/distribution_metric'
6
- require 'sentry/metrics/gauge_metric'
7
- require 'sentry/metrics/set_metric'
8
- require 'sentry/metrics/timing'
9
- require 'sentry/metrics/aggregator'
3
+ require "sentry/metrics/metric"
4
+ require "sentry/metrics/counter_metric"
5
+ require "sentry/metrics/distribution_metric"
6
+ require "sentry/metrics/gauge_metric"
7
+ require "sentry/metrics/set_metric"
8
+ require "sentry/metrics/timing"
9
+ require "sentry/metrics/aggregator"
10
10
 
11
11
  module Sentry
12
12
  module Metrics
@@ -14,32 +14,32 @@ module Sentry
14
14
  INFORMATION_UNITS = %w[bit byte kilobyte kibibyte megabyte mebibyte gigabyte gibibyte terabyte tebibyte petabyte pebibyte exabyte exbibyte]
15
15
  FRACTIONAL_UNITS = %w[ratio percent]
16
16
 
17
- OP_NAME = 'metric.timing'
18
- SPAN_ORIGIN = 'auto.metric.timing'
17
+ OP_NAME = "metric.timing"
18
+ SPAN_ORIGIN = "auto.metric.timing"
19
19
 
20
20
  class << self
21
- def increment(key, value = 1.0, unit: 'none', tags: {}, timestamp: nil)
21
+ def increment(key, value = 1.0, unit: "none", tags: {}, timestamp: nil)
22
22
  Sentry.metrics_aggregator&.add(:c, key, value, unit: unit, tags: tags, timestamp: timestamp)
23
23
  end
24
24
 
25
- def distribution(key, value, unit: 'none', tags: {}, timestamp: nil)
25
+ def distribution(key, value, unit: "none", tags: {}, timestamp: nil)
26
26
  Sentry.metrics_aggregator&.add(:d, key, value, unit: unit, tags: tags, timestamp: timestamp)
27
27
  end
28
28
 
29
- def set(key, value, unit: 'none', tags: {}, timestamp: nil)
29
+ def set(key, value, unit: "none", tags: {}, timestamp: nil)
30
30
  Sentry.metrics_aggregator&.add(:s, key, value, unit: unit, tags: tags, timestamp: timestamp)
31
31
  end
32
32
 
33
- def gauge(key, value, unit: 'none', tags: {}, timestamp: nil)
33
+ def gauge(key, value, unit: "none", tags: {}, timestamp: nil)
34
34
  Sentry.metrics_aggregator&.add(:g, key, value, unit: unit, tags: tags, timestamp: timestamp)
35
35
  end
36
36
 
37
- def timing(key, unit: 'second', tags: {}, timestamp: nil, &block)
37
+ def timing(key, unit: "second", tags: {}, timestamp: nil, &block)
38
38
  return unless block_given?
39
39
  return yield unless DURATION_UNITS.include?(unit)
40
40
 
41
41
  result, value = Sentry.with_child_span(op: OP_NAME, description: key, origin: SPAN_ORIGIN) do |span|
42
- tags.each { |k, v| span.set_tag(k, v.is_a?(Array) ? v.join(', ') : v.to_s) } if span
42
+ tags.each { |k, v| span.set_tag(k, v.is_a?(Array) ? v.join(", ") : v.to_s) } if span
43
43
 
44
44
  start = Timing.send(unit.to_sym)
45
45
  result = yield
@@ -66,7 +66,7 @@ module Sentry
66
66
  # IPv6 url could look like '::1/path', and that won't parse without
67
67
  # wrapping it in square brackets.
68
68
  hostname = address =~ Resolv::IPv6::Regex ? "[#{address}]" : address
69
- uri = req.uri || URI.parse("#{use_ssl? ? 'https' : 'http'}://#{hostname}#{req.path}")
69
+ uri = req.uri || URI.parse(URI::DEFAULT_PARSER.escape("#{use_ssl? ? 'https' : 'http'}://#{hostname}#{req.path}"))
70
70
  url = "#{uri.scheme}://#{uri.host}#{uri.path}" rescue uri.to_s
71
71
 
72
72
  result = { method: req.method, url: url }
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'securerandom'
3
+ require "securerandom"
4
4
 
5
5
  module Sentry
6
6
  class Profiler
7
- VERSION = '1'
8
- PLATFORM = 'ruby'
7
+ VERSION = "1"
8
+ PLATFORM = "ruby"
9
9
  # 101 Hz in microseconds
10
10
  DEFAULT_INTERVAL = 1e6 / 101
11
11
  MICRO_TO_NANO_SECONDS = 1e3
@@ -14,14 +14,14 @@ module Sentry
14
14
  attr_reader :sampled, :started, :event_id
15
15
 
16
16
  def initialize(configuration)
17
- @event_id = SecureRandom.uuid.delete('-')
17
+ @event_id = SecureRandom.uuid.delete("-")
18
18
  @started = false
19
19
  @sampled = nil
20
20
 
21
21
  @profiling_enabled = defined?(StackProf) && configuration.profiling_enabled?
22
22
  @profiles_sample_rate = configuration.profiles_sample_rate
23
23
  @project_root = configuration.project_root
24
- @app_dirs_pattern = configuration.app_dirs_pattern || Backtrace::APP_DIRS_PATTERN
24
+ @app_dirs_pattern = configuration.app_dirs_pattern
25
25
  @in_app_pattern = Regexp.new("^(#{@project_root}/)?#{@app_dirs_pattern}")
26
26
  end
27
27
 
@@ -33,7 +33,7 @@ module Sentry
33
33
  raw: true,
34
34
  aggregate: false)
35
35
 
36
- @started ? log('Started') : log('Not started since running elsewhere')
36
+ @started ? log("Started") : log("Not started since running elsewhere")
37
37
  end
38
38
 
39
39
  def stop
@@ -41,7 +41,7 @@ module Sentry
41
41
  return unless @started
42
42
 
43
43
  StackProf.stop
44
- log('Stopped')
44
+ log("Stopped")
45
45
  end
46
46
 
47
47
  # Sets initial sampling decision of the profile.
@@ -54,14 +54,14 @@ module Sentry
54
54
 
55
55
  unless transaction_sampled
56
56
  @sampled = false
57
- log('Discarding profile because transaction not sampled')
57
+ log("Discarding profile because transaction not sampled")
58
58
  return
59
59
  end
60
60
 
61
61
  case @profiles_sample_rate
62
62
  when 0.0
63
63
  @sampled = false
64
- log('Discarding profile because sample_rate is 0')
64
+ log("Discarding profile because sample_rate is 0")
65
65
  return
66
66
  when 1.0
67
67
  @sampled = true
@@ -70,7 +70,7 @@ module Sentry
70
70
  @sampled = Random.rand < @profiles_sample_rate
71
71
  end
72
72
 
73
- log('Discarding profile due to sampling decision') unless @sampled
73
+ log("Discarding profile due to sampling decision") unless @sampled
74
74
  end
75
75
 
76
76
  def to_hash
@@ -90,13 +90,12 @@ module Sentry
90
90
 
91
91
  frame_map = {}
92
92
 
93
- frames = results[:frames].to_enum.with_index.map do |frame, idx|
94
- frame_id, frame_data = frame
95
-
93
+ frames = results[:frames].map.with_index do |(frame_id, frame_data), idx|
96
94
  # need to map over stackprof frame ids to ours
97
95
  frame_map[frame_id] = idx
98
96
 
99
97
  file_path = frame_data[:file]
98
+ lineno = frame_data[:line]
100
99
  in_app = in_app?(file_path)
101
100
  filename = compute_filename(file_path, in_app)
102
101
  function, mod = split_module(frame_data[:name])
@@ -109,7 +108,7 @@ module Sentry
109
108
  }
110
109
 
111
110
  frame_hash[:module] = mod if mod
112
- frame_hash[:lineno] = frame_data[:line] if frame_data[:line] && frame_data[:line] >= 0
111
+ frame_hash[:lineno] = lineno if lineno && lineno >= 0
113
112
 
114
113
  frame_hash
115
114
  end
@@ -130,7 +129,7 @@ module Sentry
130
129
  num_seen << results[:raw][idx + len]
131
130
  idx += len + 1
132
131
 
133
- log('Unknown frame in stack') if stack.size != len
132
+ log("Unknown frame in stack") if stack.size != len
134
133
  end
135
134
 
136
135
  idx = 0
@@ -155,16 +154,16 @@ module Sentry
155
154
  # Till then, on multi-threaded servers like puma, we will get frames from other active threads when the one
156
155
  # we're profiling is idle/sleeping/waiting for IO etc.
157
156
  # https://bugs.ruby-lang.org/issues/10602
158
- thread_id: '0',
157
+ thread_id: "0",
159
158
  elapsed_since_start_ns: elapsed_since_start_ns.to_s
160
159
  }
161
160
  end
162
161
  end
163
162
 
164
- log('Some samples thrown away') if samples.size != results[:samples]
163
+ log("Some samples thrown away") if samples.size != results[:samples]
165
164
 
166
165
  if samples.size <= MIN_SAMPLES_REQUIRED
167
- log('Not enough samples, discarding profiler')
166
+ log("Not enough samples, discarding profiler")
168
167
  record_lost_event(:insufficient_data)
169
168
  return {}
170
169
  end
@@ -219,7 +218,7 @@ module Sentry
219
218
 
220
219
  def split_module(name)
221
220
  # last module plus class/instance method
222
- i = name.rindex('::')
221
+ i = name.rindex("::")
223
222
  function = i ? name[(i + 2)..-1] : name
224
223
  mod = i ? name[0...i] : nil
225
224
 
@@ -227,7 +226,7 @@ module Sentry
227
226
  end
228
227
 
229
228
  def record_lost_event(reason)
230
- Sentry.get_current_client&.transport&.record_lost_event(reason, 'profile')
229
+ Sentry.get_current_client&.transport&.record_lost_event(reason, "profile")
231
230
  end
232
231
  end
233
232
  end
@@ -108,7 +108,7 @@ module Sentry
108
108
  end
109
109
 
110
110
  # Returns the Dynamic Sampling Context from the baggage.
111
- # @return [String, nil]
111
+ # @return [Hash, nil]
112
112
  def get_dynamic_sampling_context
113
113
  get_baggage&.dynamic_sampling_context
114
114
  end
@@ -50,7 +50,7 @@ module Sentry
50
50
  private
51
51
 
52
52
  def collect_exception(env)
53
- env['rack.exception'] || env['sinatra.error']
53
+ env["rack.exception"] || env["sinatra.error"]
54
54
  end
55
55
 
56
56
  def transaction_op
data/lib/sentry/rack.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rack'
3
+ require "rack"
4
4
 
5
- require 'sentry/rack/capture_exceptions'
5
+ require "sentry/rack/capture_exceptions"
data/lib/sentry/rake.rb CHANGED
@@ -8,10 +8,10 @@ module Sentry
8
8
  module Application
9
9
  # @api private
10
10
  def display_error_message(ex)
11
- mechanism = Sentry::Mechanism.new(type: 'rake', handled: false)
11
+ mechanism = Sentry::Mechanism.new(type: "rake", handled: false)
12
12
 
13
13
  Sentry.capture_exception(ex, hint: { mechanism: mechanism }) do |scope|
14
- task_name = top_level_tasks.join(' ')
14
+ task_name = top_level_tasks.join(" ")
15
15
  scope.set_transaction_name(task_name, source: :task)
16
16
  scope.set_tag("rake_task", task_name)
17
17
  end if Sentry.initialized? && !Sentry.configuration.skip_rake_integration
@@ -13,12 +13,12 @@ module Sentry
13
13
 
14
14
  def detect_release_from_heroku(running_on_heroku)
15
15
  return unless running_on_heroku
16
- ENV['HEROKU_SLUG_COMMIT']
16
+ ENV["HEROKU_SLUG_COMMIT"]
17
17
  end
18
18
 
19
19
  def detect_release_from_capistrano(project_root)
20
- revision_file = File.join(project_root, 'REVISION')
21
- revision_log = File.join(project_root, '..', 'revisions.log')
20
+ revision_file = File.join(project_root, "REVISION")
21
+ revision_log = File.join(project_root, "..", "revisions.log")
22
22
 
23
23
  if File.exist?(revision_file)
24
24
  File.read(revision_file).strip
@@ -32,7 +32,7 @@ module Sentry
32
32
  end
33
33
 
34
34
  def detect_release_from_env
35
- ENV['SENTRY_RELEASE']
35
+ ENV["SENTRY_RELEASE"]
36
36
  end
37
37
  end
38
38
  end
data/lib/sentry/scope.rb CHANGED
@@ -62,6 +62,7 @@ module Sentry
62
62
 
63
63
  if span
64
64
  event.contexts[:trace] ||= span.get_trace_context
65
+ event.dynamic_sampling_context ||= span.get_dynamic_sampling_context
65
66
  else
66
67
  event.contexts[:trace] ||= propagation_context.get_trace_context
67
68
  event.dynamic_sampling_context ||= propagation_context.get_dynamic_sampling_context
@@ -44,7 +44,7 @@ module Sentry
44
44
  def pending_envelope
45
45
  envelope = Envelope.new
46
46
 
47
- header = { type: 'sessions' }
47
+ header = { type: "sessions" }
48
48
  payload = { attrs: attrs, aggregates: @pending_aggregates.values }
49
49
 
50
50
  envelope.add_item(header, payload)
data/lib/sentry/span.rb CHANGED
@@ -160,6 +160,12 @@ module Sentry
160
160
  transaction.get_baggage&.serialize
161
161
  end
162
162
 
163
+ # Returns the Dynamic Sampling Context from the transaction baggage.
164
+ # @return [Hash, nil]
165
+ def get_dynamic_sampling_context
166
+ transaction.get_baggage&.dynamic_sampling_context
167
+ end
168
+
163
169
  # @return [Hash]
164
170
  def to_hash
165
171
  hash = {
@@ -1,6 +1,6 @@
1
1
  module Sentry
2
2
  module TestHelper
3
- DUMMY_DSN = 'http://12345:67890@sentry.localdomain/sentry/42'
3
+ DUMMY_DSN = "http://12345:67890@sentry.localdomain/sentry/42"
4
4
 
5
5
  # Alters the existing SDK configuration with test-suitable options. Mainly:
6
6
  # - Sets a dummy DSN instead of `nil` or an actual DSN.
@@ -265,8 +265,8 @@ module Sentry
265
265
  else
266
266
  is_backpressure = Sentry.backpressure_monitor&.downsample_factor&.positive?
267
267
  reason = is_backpressure ? :backpressure : :sample_rate
268
- hub.current_client.transport.record_lost_event(reason, 'transaction')
269
- hub.current_client.transport.record_lost_event(reason, 'span')
268
+ hub.current_client.transport.record_lost_event(reason, "transaction")
269
+ hub.current_client.transport.record_lost_event(reason, "span")
270
270
  end
271
271
  end
272
272
 
@@ -75,7 +75,7 @@ module Sentry
75
75
  name: transaction.name,
76
76
  trace_id: transaction.trace_id,
77
77
  # TODO-neel-profiler stubbed for now, see thread_id note in profiler.rb
78
- active_thead_id: '0'
78
+ active_thead_id: "0"
79
79
  }
80
80
  )
81
81
 
@@ -7,7 +7,7 @@ module Sentry
7
7
  class HTTPTransport < Transport
8
8
  GZIP_ENCODING = "gzip"
9
9
  GZIP_THRESHOLD = 1024 * 30
10
- CONTENT_TYPE = 'application/x-sentry-envelope'
10
+ CONTENT_TYPE = "application/x-sentry-envelope"
11
11
 
12
12
  DEFAULT_DELAY = 60
13
13
  RETRY_AFTER_HEADER = "retry-after"
@@ -38,13 +38,13 @@ module Sentry
38
38
  end
39
39
 
40
40
  headers = {
41
- 'Content-Type' => CONTENT_TYPE,
42
- 'Content-Encoding' => encoding,
43
- 'User-Agent' => USER_AGENT
41
+ "Content-Type" => CONTENT_TYPE,
42
+ "Content-Encoding" => encoding,
43
+ "User-Agent" => USER_AGENT
44
44
  }
45
45
 
46
46
  auth_header = generate_auth_header
47
- headers['X-Sentry-Auth'] = auth_header if auth_header
47
+ headers["X-Sentry-Auth"] = auth_header if auth_header
48
48
 
49
49
  response = conn.start do |http|
50
50
  request = ::Net::HTTP::Post.new(endpoint, headers)
@@ -60,7 +60,7 @@ module Sentry
60
60
  else
61
61
  error_info = "the server responded with status #{response.code}"
62
62
  error_info += "\nbody: #{response.body}"
63
- error_info += " Error in headers is: #{response['x-sentry-error']}" if response['x-sentry-error']
63
+ error_info += " Error in headers is: #{response['x-sentry-error']}" if response["x-sentry-error"]
64
64
 
65
65
  raise Sentry::ExternalError, error_info
66
66
  end
@@ -78,13 +78,13 @@ module Sentry
78
78
 
79
79
  now = Sentry.utc_now.to_i
80
80
  fields = {
81
- 'sentry_version' => PROTOCOL_VERSION,
82
- 'sentry_client' => USER_AGENT,
83
- 'sentry_timestamp' => now,
84
- 'sentry_key' => @dsn.public_key
81
+ "sentry_version" => PROTOCOL_VERSION,
82
+ "sentry_client" => USER_AGENT,
83
+ "sentry_timestamp" => now,
84
+ "sentry_key" => @dsn.public_key
85
85
  }
86
- fields['sentry_secret'] = @dsn.secret_key if @dsn.secret_key
87
- 'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
86
+ fields["sentry_secret"] = @dsn.secret_key if @dsn.secret_key
87
+ "Sentry " + fields.map { |key, value| "#{key}=#{value}" }.join(", ")
88
88
  end
89
89
 
90
90
  def conn
@@ -5,7 +5,7 @@ require "sentry/envelope"
5
5
 
6
6
  module Sentry
7
7
  class Transport
8
- PROTOCOL_VERSION = '7'
8
+ PROTOCOL_VERSION = "7"
9
9
  USER_AGENT = "sentry-ruby/#{Sentry::VERSION}"
10
10
  CLIENT_REPORT_INTERVAL = 30
11
11
 
@@ -134,13 +134,13 @@ module Sentry
134
134
  envelope = Envelope.new(envelope_headers)
135
135
 
136
136
  envelope.add_item(
137
- { type: item_type, content_type: 'application/json' },
137
+ { type: item_type, content_type: "application/json" },
138
138
  event_payload
139
139
  )
140
140
 
141
141
  if event.is_a?(TransactionEvent) && event.profile
142
142
  envelope.add_item(
143
- { type: 'profile', content_type: 'application/json' },
143
+ { type: "profile", content_type: "application/json" },
144
144
  event.profile
145
145
  )
146
146
  end
@@ -185,7 +185,7 @@ module Sentry
185
185
  { reason: reason, category: category, quantity: val }
186
186
  end
187
187
 
188
- item_header = { type: 'client_report' }
188
+ item_header = { type: "client_report" }
189
189
  item_payload = {
190
190
  timestamp: Sentry.utc_now.iso8601,
191
191
  discarded_events: discarded_events_hash
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ module Utils
5
+ module EnvHelper
6
+ TRUTHY_ENV_VALUES = %w[t true yes y 1 on].freeze
7
+ FALSY_ENV_VALUES = %w[f false no n 0 off].freeze
8
+
9
+ def self.env_to_bool(value, strict: false)
10
+ value = value.to_s
11
+ normalized = value.downcase
12
+
13
+ return false if FALSY_ENV_VALUES.include?(normalized)
14
+
15
+ return true if TRUTHY_ENV_VALUES.include?(normalized)
16
+
17
+ strict ? nil : !(value.nil? || value.empty?)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ipaddr'
3
+ require "ipaddr"
4
4
 
5
5
  # Based on ActionDispatch::RemoteIp. All security-related precautions from that
6
6
  # middleware have been removed, because the Event IP just needs to be accurate,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "5.19.0"
4
+ VERSION = "5.20.0"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -563,7 +563,7 @@ module Sentry
563
563
  #
564
564
  # @return [String]
565
565
  def get_trace_propagation_meta
566
- return '' unless initialized?
566
+ return "" unless initialized?
567
567
  get_current_hub.get_trace_propagation_meta
568
568
  end
569
569
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-ruby-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.19.0
4
+ version: 5.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-13 00:00:00.000000000 Z
11
+ date: 2024-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sentry-ruby
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 5.19.0
19
+ version: 5.20.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 5.19.0
26
+ version: 5.20.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: concurrent-ruby
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -129,6 +129,7 @@ files:
129
129
  - lib/sentry/utils/argument_checking_helper.rb
130
130
  - lib/sentry/utils/custom_inspection.rb
131
131
  - lib/sentry/utils/encoding_helper.rb
132
+ - lib/sentry/utils/env_helper.rb
132
133
  - lib/sentry/utils/exception_cause_chain.rb
133
134
  - lib/sentry/utils/http_tracing.rb
134
135
  - lib/sentry/utils/logging_helper.rb
@@ -159,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
160
  - !ruby/object:Gem::Version
160
161
  version: '0'
161
162
  requirements: []
162
- rubygems_version: 3.5.11
163
+ rubygems_version: 3.5.16
163
164
  signing_key:
164
165
  specification_version: 4
165
166
  summary: A gem that provides a client interface for the Sentry error logger