sentry-ruby 5.16.1 → 5.19.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 +3 -0
- data/README.md +20 -10
- data/Rakefile +1 -1
- data/bin/console +1 -0
- data/lib/sentry/attachment.rb +42 -0
- data/lib/sentry/background_worker.rb +1 -1
- data/lib/sentry/backpressure_monitor.rb +2 -32
- data/lib/sentry/backtrace.rb +7 -3
- data/lib/sentry/check_in_event.rb +1 -1
- data/lib/sentry/client.rb +59 -9
- data/lib/sentry/configuration.rb +25 -12
- data/lib/sentry/cron/monitor_schedule.rb +1 -1
- data/lib/sentry/dsn.rb +1 -1
- data/lib/sentry/envelope.rb +18 -1
- data/lib/sentry/error_event.rb +2 -2
- data/lib/sentry/event.rb +13 -11
- data/lib/sentry/faraday.rb +77 -0
- data/lib/sentry/graphql.rb +9 -0
- data/lib/sentry/hub.rb +15 -2
- data/lib/sentry/integrable.rb +4 -0
- data/lib/sentry/interface.rb +1 -0
- data/lib/sentry/interfaces/exception.rb +5 -3
- data/lib/sentry/interfaces/mechanism.rb +20 -0
- data/lib/sentry/interfaces/request.rb +2 -2
- data/lib/sentry/interfaces/single_exception.rb +6 -4
- data/lib/sentry/interfaces/stacktrace_builder.rb +8 -0
- data/lib/sentry/metrics/aggregator.rb +248 -0
- data/lib/sentry/metrics/configuration.rb +47 -0
- data/lib/sentry/metrics/counter_metric.rb +25 -0
- data/lib/sentry/metrics/distribution_metric.rb +25 -0
- data/lib/sentry/metrics/gauge_metric.rb +35 -0
- data/lib/sentry/metrics/local_aggregator.rb +53 -0
- data/lib/sentry/metrics/metric.rb +19 -0
- data/lib/sentry/metrics/set_metric.rb +28 -0
- data/lib/sentry/metrics/timing.rb +43 -0
- data/lib/sentry/metrics.rb +56 -0
- data/lib/sentry/net/http.rb +17 -38
- data/lib/sentry/propagation_context.rb +9 -8
- data/lib/sentry/puma.rb +1 -1
- data/lib/sentry/rack/capture_exceptions.rb +14 -2
- data/lib/sentry/rake.rb +3 -1
- data/lib/sentry/redis.rb +2 -1
- data/lib/sentry/scope.rb +35 -26
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +6 -38
- data/lib/sentry/span.rb +40 -5
- data/lib/sentry/test_helper.rb +2 -1
- data/lib/sentry/threaded_periodic_worker.rb +39 -0
- data/lib/sentry/transaction.rb +16 -14
- data/lib/sentry/transaction_event.rb +5 -0
- data/lib/sentry/transport/configuration.rb +0 -1
- data/lib/sentry/transport.rb +14 -22
- data/lib/sentry/utils/argument_checking_helper.rb +6 -0
- data/lib/sentry/utils/http_tracing.rb +41 -0
- data/lib/sentry/utils/logging_helper.rb +0 -4
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +34 -3
- data/sentry-ruby.gemspec +12 -5
- metadata +39 -7
    
        data/lib/sentry/span.rb
    CHANGED
    
    | @@ -1,10 +1,10 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require "securerandom"
         | 
| 4 | 
            +
            require "sentry/metrics/local_aggregator"
         | 
| 4 5 |  | 
| 5 6 | 
             
            module Sentry
         | 
| 6 7 | 
             
              class Span
         | 
| 7 | 
            -
             | 
| 8 8 | 
             
                # We will try to be consistent with OpenTelemetry on this front going forward.
         | 
| 9 9 | 
             
                # https://develop.sentry.dev/sdk/performance/span-data-conventions/
         | 
| 10 10 | 
             
                module DataConventions
         | 
| @@ -39,6 +39,11 @@ module Sentry | |
| 39 39 | 
             
                  # Recommended: If different than server.port.
         | 
| 40 40 | 
             
                  # Example: 16456
         | 
| 41 41 | 
             
                  SERVER_SOCKET_PORT = "server.socket.port"
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  FILEPATH = "code.filepath"
         | 
| 44 | 
            +
                  LINENO = "code.lineno"
         | 
| 45 | 
            +
                  FUNCTION = "code.function"
         | 
| 46 | 
            +
                  NAMESPACE = "code.namespace"
         | 
| 42 47 | 
             
                end
         | 
| 43 48 |  | 
| 44 49 | 
             
                STATUS_MAP = {
         | 
| @@ -55,6 +60,8 @@ module Sentry | |
| 55 60 | 
             
                  504 => "deadline_exceeded"
         | 
| 56 61 | 
             
                }
         | 
| 57 62 |  | 
| 63 | 
            +
                DEFAULT_SPAN_ORIGIN = "manual"
         | 
| 64 | 
            +
             | 
| 58 65 | 
             
                # An uuid that can be used to identify a trace.
         | 
| 59 66 | 
             
                # @return [String]
         | 
| 60 67 | 
             
                attr_reader :trace_id
         | 
| @@ -88,6 +95,9 @@ module Sentry | |
| 88 95 | 
             
                # Span data
         | 
| 89 96 | 
             
                # @return [Hash]
         | 
| 90 97 | 
             
                attr_reader :data
         | 
| 98 | 
            +
                # Span origin that tracks what kind of instrumentation created a span
         | 
| 99 | 
            +
                # @return [String]
         | 
| 100 | 
            +
                attr_reader :origin
         | 
| 91 101 |  | 
| 92 102 | 
             
                # The SpanRecorder the current span belongs to.
         | 
| 93 103 | 
             
                # SpanRecorder holds all spans under the same Transaction object (including the Transaction itself).
         | 
| @@ -109,7 +119,8 @@ module Sentry | |
| 109 119 | 
             
                  parent_span_id: nil,
         | 
| 110 120 | 
             
                  sampled: nil,
         | 
| 111 121 | 
             
                  start_timestamp: nil,
         | 
| 112 | 
            -
                  timestamp: nil
         | 
| 122 | 
            +
                  timestamp: nil,
         | 
| 123 | 
            +
                  origin: nil
         | 
| 113 124 | 
             
                )
         | 
| 114 125 | 
             
                  @trace_id = trace_id || SecureRandom.uuid.delete("-")
         | 
| 115 126 | 
             
                  @span_id = span_id || SecureRandom.uuid.delete("-").slice(0, 16)
         | 
| @@ -123,6 +134,7 @@ module Sentry | |
| 123 134 | 
             
                  @status = status
         | 
| 124 135 | 
             
                  @data = {}
         | 
| 125 136 | 
             
                  @tags = {}
         | 
| 137 | 
            +
                  @origin = origin || DEFAULT_SPAN_ORIGIN
         | 
| 126 138 | 
             
                end
         | 
| 127 139 |  | 
| 128 140 | 
             
                # Finishes the span by adding a timestamp.
         | 
| @@ -150,7 +162,7 @@ module Sentry | |
| 150 162 |  | 
| 151 163 | 
             
                # @return [Hash]
         | 
| 152 164 | 
             
                def to_hash
         | 
| 153 | 
            -
                  {
         | 
| 165 | 
            +
                  hash = {
         | 
| 154 166 | 
             
                    trace_id: @trace_id,
         | 
| 155 167 | 
             
                    span_id: @span_id,
         | 
| 156 168 | 
             
                    parent_span_id: @parent_span_id,
         | 
| @@ -160,8 +172,14 @@ module Sentry | |
| 160 172 | 
             
                    op: @op,
         | 
| 161 173 | 
             
                    status: @status,
         | 
| 162 174 | 
             
                    tags: @tags,
         | 
| 163 | 
            -
                    data: @data
         | 
| 175 | 
            +
                    data: @data,
         | 
| 176 | 
            +
                    origin: @origin
         | 
| 164 177 | 
             
                  }
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                  summary = metrics_summary
         | 
| 180 | 
            +
                  hash[:_metrics_summary] = summary if summary
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                  hash
         | 
| 165 183 | 
             
                end
         | 
| 166 184 |  | 
| 167 185 | 
             
                # Returns the span's context that can be used to embed in an Event.
         | 
| @@ -173,7 +191,9 @@ module Sentry | |
| 173 191 | 
             
                    parent_span_id: @parent_span_id,
         | 
| 174 192 | 
             
                    description: @description,
         | 
| 175 193 | 
             
                    op: @op,
         | 
| 176 | 
            -
                    status: @status
         | 
| 194 | 
            +
                    status: @status,
         | 
| 195 | 
            +
                    origin: @origin,
         | 
| 196 | 
            +
                    data: @data
         | 
| 177 197 | 
             
                  }
         | 
| 178 198 | 
             
                end
         | 
| 179 199 |  | 
| @@ -269,5 +289,20 @@ module Sentry | |
| 269 289 | 
             
                def set_tag(key, value)
         | 
| 270 290 | 
             
                  @tags[key] = value
         | 
| 271 291 | 
             
                end
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                # Sets the origin of the span.
         | 
| 294 | 
            +
                # @param origin [String]
         | 
| 295 | 
            +
                def set_origin(origin)
         | 
| 296 | 
            +
                  @origin = origin
         | 
| 297 | 
            +
                end
         | 
| 298 | 
            +
             | 
| 299 | 
            +
                # Collects gauge metrics on the span for metric summaries.
         | 
| 300 | 
            +
                def metrics_local_aggregator
         | 
| 301 | 
            +
                  @metrics_local_aggregator ||= Sentry::Metrics::LocalAggregator.new
         | 
| 302 | 
            +
                end
         | 
| 303 | 
            +
             | 
| 304 | 
            +
                def metrics_summary
         | 
| 305 | 
            +
                  @metrics_local_aggregator&.to_hash
         | 
| 306 | 
            +
                end
         | 
| 272 307 | 
             
              end
         | 
| 273 308 | 
             
            end
         | 
    
        data/lib/sentry/test_helper.rb
    CHANGED
    
    | @@ -20,7 +20,7 @@ module Sentry | |
| 20 20 | 
             
                  # set transport to DummyTransport, so we can easily intercept the captured events
         | 
| 21 21 | 
             
                  dummy_config.transport.transport_class = Sentry::DummyTransport
         | 
| 22 22 | 
             
                  # make sure SDK allows sending under the current environment
         | 
| 23 | 
            -
                  dummy_config.enabled_environments  | 
| 23 | 
            +
                  dummy_config.enabled_environments += [dummy_config.environment] unless dummy_config.enabled_environments.include?(dummy_config.environment)
         | 
| 24 24 | 
             
                  # disble async event sending
         | 
| 25 25 | 
             
                  dummy_config.background_worker_threads = 0
         | 
| 26 26 |  | 
| @@ -50,6 +50,7 @@ module Sentry | |
| 50 50 | 
             
                  if Sentry.get_current_hub.instance_variable_get(:@stack).size > 1
         | 
| 51 51 | 
             
                    Sentry.get_current_hub.pop_scope
         | 
| 52 52 | 
             
                  end
         | 
| 53 | 
            +
                  Sentry::Scope.global_event_processors.clear
         | 
| 53 54 | 
             
                end
         | 
| 54 55 |  | 
| 55 56 | 
             
                # @return [Transport]
         | 
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Sentry
         | 
| 4 | 
            +
              class ThreadedPeriodicWorker
         | 
| 5 | 
            +
                include LoggingHelper
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize(logger, internal)
         | 
| 8 | 
            +
                  @thread = nil
         | 
| 9 | 
            +
                  @exited = false
         | 
| 10 | 
            +
                  @interval = internal
         | 
| 11 | 
            +
                  @logger = logger
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def ensure_thread
         | 
| 15 | 
            +
                  return false if @exited
         | 
| 16 | 
            +
                  return true if @thread&.alive?
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  @thread = Thread.new do
         | 
| 19 | 
            +
                    loop do
         | 
| 20 | 
            +
                      sleep(@interval)
         | 
| 21 | 
            +
                      run
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  true
         | 
| 26 | 
            +
                rescue ThreadError
         | 
| 27 | 
            +
                  log_debug("[#{self.class.name}] thread creation failed")
         | 
| 28 | 
            +
                  @exited = true
         | 
| 29 | 
            +
                  false
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def kill
         | 
| 33 | 
            +
                  log_debug("[#{self.class.name}] thread killed")
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  @exited = true
         | 
| 36 | 
            +
                  @thread&.kill
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
            end
         | 
    
        data/lib/sentry/transaction.rb
    CHANGED
    
    | @@ -13,7 +13,7 @@ module Sentry | |
| 13 13 | 
             
                MESSAGE_PREFIX = "[Tracing]"
         | 
| 14 14 |  | 
| 15 15 | 
             
                # https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations
         | 
| 16 | 
            -
                SOURCES = %i | 
| 16 | 
            +
                SOURCES = %i[custom url route view component task]
         | 
| 17 17 |  | 
| 18 18 | 
             
                include LoggingHelper
         | 
| 19 19 |  | 
| @@ -110,14 +110,15 @@ module Sentry | |
| 110 110 |  | 
| 111 111 | 
             
                  trace_id, parent_span_id, parent_sampled = sentry_trace_data
         | 
| 112 112 |  | 
| 113 | 
            -
                  baggage = | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 113 | 
            +
                  baggage =
         | 
| 114 | 
            +
                    if baggage && !baggage.empty?
         | 
| 115 | 
            +
                      Baggage.from_incoming_header(baggage)
         | 
| 116 | 
            +
                    else
         | 
| 117 | 
            +
                      # If there's an incoming sentry-trace but no incoming baggage header,
         | 
| 118 | 
            +
                      # for instance in traces coming from older SDKs,
         | 
| 119 | 
            +
                      # baggage will be empty and frozen and won't be populated as head SDK.
         | 
| 120 | 
            +
                      Baggage.new({})
         | 
| 121 | 
            +
                    end
         | 
| 121 122 |  | 
| 122 123 | 
             
                  baggage.freeze!
         | 
| 123 124 |  | 
| @@ -265,6 +266,7 @@ module Sentry | |
| 265 266 | 
             
                    is_backpressure = Sentry.backpressure_monitor&.downsample_factor&.positive?
         | 
| 266 267 | 
             
                    reason = is_backpressure ? :backpressure : :sample_rate
         | 
| 267 268 | 
             
                    hub.current_client.transport.record_lost_event(reason, 'transaction')
         | 
| 269 | 
            +
                    hub.current_client.transport.record_lost_event(reason, 'span')
         | 
| 268 270 | 
             
                  end
         | 
| 269 271 | 
             
                end
         | 
| 270 272 |  | 
| @@ -301,6 +303,11 @@ module Sentry | |
| 301 303 | 
             
                  profiler.start
         | 
| 302 304 | 
             
                end
         | 
| 303 305 |  | 
| 306 | 
            +
                # These are high cardinality and thus bad
         | 
| 307 | 
            +
                def source_low_quality?
         | 
| 308 | 
            +
                  source == :url
         | 
| 309 | 
            +
                end
         | 
| 310 | 
            +
             | 
| 304 311 | 
             
                protected
         | 
| 305 312 |  | 
| 306 313 | 
             
                def init_span_recorder(limit = 1000)
         | 
| @@ -336,11 +343,6 @@ module Sentry | |
| 336 343 | 
             
                  @baggage = Baggage.new(items, mutable: false)
         | 
| 337 344 | 
             
                end
         | 
| 338 345 |  | 
| 339 | 
            -
                # These are high cardinality and thus bad
         | 
| 340 | 
            -
                def source_low_quality?
         | 
| 341 | 
            -
                  source == :url
         | 
| 342 | 
            -
                end
         | 
| 343 | 
            -
             | 
| 344 346 | 
             
                class SpanRecorder
         | 
| 345 347 | 
             
                  attr_reader :max_length, :spans
         | 
| 346 348 |  | 
| @@ -17,6 +17,9 @@ module Sentry | |
| 17 17 | 
             
                # @return [Hash, nil]
         | 
| 18 18 | 
             
                attr_accessor :profile
         | 
| 19 19 |  | 
| 20 | 
            +
                # @return [Hash, nil]
         | 
| 21 | 
            +
                attr_accessor :metrics_summary
         | 
| 22 | 
            +
             | 
| 20 23 | 
             
                def initialize(transaction:, **options)
         | 
| 21 24 | 
             
                  super(**options)
         | 
| 22 25 |  | 
| @@ -29,6 +32,7 @@ module Sentry | |
| 29 32 | 
             
                  self.tags = transaction.tags
         | 
| 30 33 | 
             
                  self.dynamic_sampling_context = transaction.get_baggage.dynamic_sampling_context
         | 
| 31 34 | 
             
                  self.measurements = transaction.measurements
         | 
| 35 | 
            +
                  self.metrics_summary = transaction.metrics_summary
         | 
| 32 36 |  | 
| 33 37 | 
             
                  finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
         | 
| 34 38 | 
             
                  self.spans = finished_spans.map(&:to_hash)
         | 
| @@ -49,6 +53,7 @@ module Sentry | |
| 49 53 | 
             
                  data[:spans] = @spans.map(&:to_hash) if @spans
         | 
| 50 54 | 
             
                  data[:start_timestamp] = @start_timestamp
         | 
| 51 55 | 
             
                  data[:measurements] = @measurements
         | 
| 56 | 
            +
                  data[:_metrics_summary] = @metrics_summary if @metrics_summary
         | 
| 52 57 | 
             
                  data
         | 
| 53 58 | 
             
                end
         | 
| 54 59 |  | 
    
        data/lib/sentry/transport.rb
    CHANGED
    
    | @@ -1,7 +1,6 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require "json"
         | 
| 4 | 
            -
            require "base64"
         | 
| 5 4 | 
             
            require "sentry/envelope"
         | 
| 6 5 |  | 
| 7 6 | 
             
            module Sentry
         | 
| @@ -62,7 +61,7 @@ module Sentry | |
| 62 61 | 
             
                  data, serialized_items = serialize_envelope(envelope)
         | 
| 63 62 |  | 
| 64 63 | 
             
                  if data
         | 
| 65 | 
            -
                     | 
| 64 | 
            +
                    log_debug("[Transport] Sending envelope with items [#{serialized_items.map(&:type).join(', ')}] #{envelope.event_id} to Sentry")
         | 
| 66 65 | 
             
                    send_data(data)
         | 
| 67 66 | 
             
                  end
         | 
| 68 67 | 
             
                end
         | 
| @@ -89,18 +88,9 @@ module Sentry | |
| 89 88 | 
             
                  [data, serialized_items]
         | 
| 90 89 | 
             
                end
         | 
| 91 90 |  | 
| 92 | 
            -
                def is_rate_limited?( | 
| 91 | 
            +
                def is_rate_limited?(data_category)
         | 
| 93 92 | 
             
                  # check category-specific limit
         | 
| 94 | 
            -
                  category_delay =
         | 
| 95 | 
            -
                    case item_type
         | 
| 96 | 
            -
                    when "transaction"
         | 
| 97 | 
            -
                      @rate_limits["transaction"]
         | 
| 98 | 
            -
                    when "sessions"
         | 
| 99 | 
            -
                      @rate_limits["session"]
         | 
| 100 | 
            -
                    else
         | 
| 101 | 
            -
                      @rate_limits["error"]
         | 
| 102 | 
            -
                    end
         | 
| 103 | 
            -
             | 
| 93 | 
            +
                  category_delay = @rate_limits[data_category]
         | 
| 104 94 | 
             
                  # check universal limit if not category limit
         | 
| 105 95 | 
             
                  universal_delay = @rate_limits[nil]
         | 
| 106 96 |  | 
| @@ -155,17 +145,23 @@ module Sentry | |
| 155 145 | 
             
                    )
         | 
| 156 146 | 
             
                  end
         | 
| 157 147 |  | 
| 148 | 
            +
                  if event.is_a?(Event) && event.attachments.any?
         | 
| 149 | 
            +
                    event.attachments.each do |attachment|
         | 
| 150 | 
            +
                      envelope.add_item(attachment.to_envelope_headers, attachment.payload)
         | 
| 151 | 
            +
                    end
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
             | 
| 158 154 | 
             
                  client_report_headers, client_report_payload = fetch_pending_client_report
         | 
| 159 155 | 
             
                  envelope.add_item(client_report_headers, client_report_payload) if client_report_headers
         | 
| 160 156 |  | 
| 161 157 | 
             
                  envelope
         | 
| 162 158 | 
             
                end
         | 
| 163 159 |  | 
| 164 | 
            -
                def record_lost_event(reason,  | 
| 160 | 
            +
                def record_lost_event(reason, data_category, num: 1)
         | 
| 165 161 | 
             
                  return unless @send_client_reports
         | 
| 166 162 | 
             
                  return unless CLIENT_REPORT_REASONS.include?(reason)
         | 
| 167 163 |  | 
| 168 | 
            -
                  @discarded_events[[reason,  | 
| 164 | 
            +
                  @discarded_events[[reason, data_category]] += num
         | 
| 169 165 | 
             
                end
         | 
| 170 166 |  | 
| 171 167 | 
             
                def flush
         | 
| @@ -185,11 +181,7 @@ module Sentry | |
| 185 181 | 
             
                  return nil if @discarded_events.empty?
         | 
| 186 182 |  | 
| 187 183 | 
             
                  discarded_events_hash = @discarded_events.map do |key, val|
         | 
| 188 | 
            -
                    reason,  | 
| 189 | 
            -
             | 
| 190 | 
            -
                    # 'event' has to be mapped to 'error'
         | 
| 191 | 
            -
                    category = type == 'event' ? 'error' : type
         | 
| 192 | 
            -
             | 
| 184 | 
            +
                    reason, category = key
         | 
| 193 185 | 
             
                    { reason: reason, category: category, quantity: val }
         | 
| 194 186 | 
             
                  end
         | 
| 195 187 |  | 
| @@ -207,9 +199,9 @@ module Sentry | |
| 207 199 |  | 
| 208 200 | 
             
                def reject_rate_limited_items(envelope)
         | 
| 209 201 | 
             
                  envelope.items.reject! do |item|
         | 
| 210 | 
            -
                    if is_rate_limited?(item. | 
| 202 | 
            +
                    if is_rate_limited?(item.data_category)
         | 
| 211 203 | 
             
                      log_debug("[Transport] Envelope item [#{item.type}] not sent: rate limiting")
         | 
| 212 | 
            -
                      record_lost_event(:ratelimit_backoff, item. | 
| 204 | 
            +
                      record_lost_event(:ratelimit_backoff, item.data_category)
         | 
| 213 205 |  | 
| 214 206 | 
             
                      true
         | 
| 215 207 | 
             
                    else
         | 
| @@ -15,5 +15,11 @@ module Sentry | |
| 15 15 | 
             
                    raise ArgumentError, "expect the argument to be one of #{values.map(&:inspect).join(' or ')}, got #{argument.inspect}"
         | 
| 16 16 | 
             
                  end
         | 
| 17 17 | 
             
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def check_callable!(name, value)
         | 
| 20 | 
            +
                  unless value == nil || value.respond_to?(:call)
         | 
| 21 | 
            +
                    raise ArgumentError, "#{name} must be callable (or nil to disable)"
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 18 24 | 
             
              end
         | 
| 19 25 | 
             
            end
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Sentry
         | 
| 4 | 
            +
              module Utils
         | 
| 5 | 
            +
                module HttpTracing
         | 
| 6 | 
            +
                  def set_span_info(sentry_span, request_info, response_status)
         | 
| 7 | 
            +
                    sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
         | 
| 8 | 
            +
                    sentry_span.set_data(Span::DataConventions::URL, request_info[:url])
         | 
| 9 | 
            +
                    sentry_span.set_data(Span::DataConventions::HTTP_METHOD, request_info[:method])
         | 
| 10 | 
            +
                    sentry_span.set_data(Span::DataConventions::HTTP_QUERY, request_info[:query]) if request_info[:query]
         | 
| 11 | 
            +
                    sentry_span.set_data(Span::DataConventions::HTTP_STATUS_CODE, response_status)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def set_propagation_headers(req)
         | 
| 15 | 
            +
                    Sentry.get_trace_propagation_headers&.each { |k, v| req[k] = v }
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def record_sentry_breadcrumb(request_info, response_status)
         | 
| 19 | 
            +
                    crumb = Sentry::Breadcrumb.new(
         | 
| 20 | 
            +
                      level: :info,
         | 
| 21 | 
            +
                      category: self.class::BREADCRUMB_CATEGORY,
         | 
| 22 | 
            +
                      type: :info,
         | 
| 23 | 
            +
                      data: { status: response_status, **request_info }
         | 
| 24 | 
            +
                    )
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    Sentry.add_breadcrumb(crumb)
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def record_sentry_breadcrumb?
         | 
| 30 | 
            +
                    Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def propagate_trace?(url)
         | 
| 34 | 
            +
                    url &&
         | 
| 35 | 
            +
                      Sentry.initialized? &&
         | 
| 36 | 
            +
                      Sentry.configuration.propagate_traces &&
         | 
| 37 | 
            +
                      Sentry.configuration.trace_propagation_targets.any? { |target| url.match?(target) }
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
    
        data/lib/sentry/utils/real_ip.rb
    CHANGED
    
    | @@ -15,7 +15,7 @@ module Sentry | |
| 15 15 | 
             
                    "fc00::/7",       # private IPv6 range fc00::/7
         | 
| 16 16 | 
             
                    "10.0.0.0/8",     # private IPv4 range 10.x.x.x
         | 
| 17 17 | 
             
                    "172.16.0.0/12",  # private IPv4 range 172.16.0.0 .. 172.31.255.255
         | 
| 18 | 
            -
                    "192.168.0.0/16" | 
| 18 | 
            +
                    "192.168.0.0/16" # private IPv4 range 192.168.x.x
         | 
| 19 19 | 
             
                  ]
         | 
| 20 20 |  | 
| 21 21 | 
             
                  attr_reader :ip
         | 
| @@ -3,7 +3,7 @@ | |
| 3 3 | 
             
            module Sentry
         | 
| 4 4 | 
             
              module Utils
         | 
| 5 5 | 
             
                module RequestId
         | 
| 6 | 
            -
                  REQUEST_ID_HEADERS = %w | 
| 6 | 
            +
                  REQUEST_ID_HEADERS = %w[action_dispatch.request_id HTTP_X_REQUEST_ID].freeze
         | 
| 7 7 |  | 
| 8 8 | 
             
                  # Request ID based on ActionDispatch::RequestId
         | 
| 9 9 | 
             
                  def self.read_from(env)
         | 
    
        data/lib/sentry/version.rb
    CHANGED
    
    
    
        data/lib/sentry-ruby.rb
    CHANGED
    
    | @@ -20,13 +20,15 @@ require "sentry/span" | |
| 20 20 | 
             
            require "sentry/transaction"
         | 
| 21 21 | 
             
            require "sentry/hub"
         | 
| 22 22 | 
             
            require "sentry/background_worker"
         | 
| 23 | 
            +
            require "sentry/threaded_periodic_worker"
         | 
| 23 24 | 
             
            require "sentry/session_flusher"
         | 
| 24 25 | 
             
            require "sentry/backpressure_monitor"
         | 
| 25 26 | 
             
            require "sentry/cron/monitor_check_ins"
         | 
| 27 | 
            +
            require "sentry/metrics"
         | 
| 26 28 |  | 
| 27 29 | 
             
            [
         | 
| 28 30 | 
             
              "sentry/rake",
         | 
| 29 | 
            -
              "sentry/rack" | 
| 31 | 
            +
              "sentry/rack"
         | 
| 30 32 | 
             
            ].each do |lib|
         | 
| 31 33 | 
             
              begin
         | 
| 32 34 | 
             
                require lib
         | 
| @@ -77,6 +79,10 @@ module Sentry | |
| 77 79 | 
             
                #   @return [BackpressureMonitor, nil]
         | 
| 78 80 | 
             
                attr_reader :backpressure_monitor
         | 
| 79 81 |  | 
| 82 | 
            +
                # @!attribute [r] metrics_aggregator
         | 
| 83 | 
            +
                #   @return [Metrics::Aggregator, nil]
         | 
| 84 | 
            +
                attr_reader :metrics_aggregator
         | 
| 85 | 
            +
             | 
| 80 86 | 
             
                ##### Patch Registration #####
         | 
| 81 87 |  | 
| 82 88 | 
             
                # @!visibility private
         | 
| @@ -205,6 +211,13 @@ module Sentry | |
| 205 211 | 
             
                  get_current_scope.set_context(*args)
         | 
| 206 212 | 
             
                end
         | 
| 207 213 |  | 
| 214 | 
            +
                # @!method add_attachment
         | 
| 215 | 
            +
                #   @!macro add_attachment
         | 
| 216 | 
            +
                def add_attachment(**opts)
         | 
| 217 | 
            +
                  return unless initialized?
         | 
| 218 | 
            +
                  get_current_scope.add_attachment(**opts)
         | 
| 219 | 
            +
                end
         | 
| 220 | 
            +
             | 
| 208 221 | 
             
                ##### Main APIs #####
         | 
| 209 222 |  | 
| 210 223 | 
             
                # Initializes the SDK with given configuration.
         | 
| @@ -222,8 +235,9 @@ module Sentry | |
| 222 235 | 
             
                  Thread.current.thread_variable_set(THREAD_LOCAL, hub)
         | 
| 223 236 | 
             
                  @main_hub = hub
         | 
| 224 237 | 
             
                  @background_worker = Sentry::BackgroundWorker.new(config)
         | 
| 225 | 
            -
                  @session_flusher = config. | 
| 238 | 
            +
                  @session_flusher = config.session_tracking? ? Sentry::SessionFlusher.new(config, client) : nil
         | 
| 226 239 | 
             
                  @backpressure_monitor = config.enable_backpressure_handling ? Sentry::BackpressureMonitor.new(config, client) : nil
         | 
| 240 | 
            +
                  @metrics_aggregator = config.metrics.enabled ? Sentry::Metrics::Aggregator.new(config, client) : nil
         | 
| 227 241 | 
             
                  exception_locals_tp.enable if config.include_local_variables
         | 
| 228 242 | 
             
                  at_exit { close }
         | 
| 229 243 | 
             
                end
         | 
| @@ -244,8 +258,14 @@ module Sentry | |
| 244 258 | 
             
                    @backpressure_monitor = nil
         | 
| 245 259 | 
             
                  end
         | 
| 246 260 |  | 
| 261 | 
            +
                  if @metrics_aggregator
         | 
| 262 | 
            +
                    @metrics_aggregator.flush(force: true)
         | 
| 263 | 
            +
                    @metrics_aggregator.kill
         | 
| 264 | 
            +
                    @metrics_aggregator = nil
         | 
| 265 | 
            +
                  end
         | 
| 266 | 
            +
             | 
| 247 267 | 
             
                  if client = get_current_client
         | 
| 248 | 
            -
                    client. | 
| 268 | 
            +
                    client.flush
         | 
| 249 269 |  | 
| 250 270 | 
             
                    if client.configuration.include_local_variables
         | 
| 251 271 | 
             
                      exception_locals_tp.disable
         | 
| @@ -538,6 +558,15 @@ module Sentry | |
| 538 558 | 
             
                  get_current_hub.get_trace_propagation_headers
         | 
| 539 559 | 
             
                end
         | 
| 540 560 |  | 
| 561 | 
            +
                # Returns the a Hash containing sentry-trace and baggage.
         | 
| 562 | 
            +
                # Can be either from the currently active span or the propagation context.
         | 
| 563 | 
            +
                #
         | 
| 564 | 
            +
                # @return [String]
         | 
| 565 | 
            +
                def get_trace_propagation_meta
         | 
| 566 | 
            +
                  return '' unless initialized?
         | 
| 567 | 
            +
                  get_current_hub.get_trace_propagation_meta
         | 
| 568 | 
            +
                end
         | 
| 569 | 
            +
             | 
| 541 570 | 
             
                # Continue an incoming trace from a rack env like hash.
         | 
| 542 571 | 
             
                #
         | 
| 543 572 | 
             
                # @param env [Hash]
         | 
| @@ -578,3 +607,5 @@ end | |
| 578 607 | 
             
            require "sentry/net/http"
         | 
| 579 608 | 
             
            require "sentry/redis"
         | 
| 580 609 | 
             
            require "sentry/puma"
         | 
| 610 | 
            +
            require "sentry/graphql"
         | 
| 611 | 
            +
            require "sentry/faraday"
         | 
    
        data/sentry-ruby.gemspec
    CHANGED
    
    | @@ -7,18 +7,25 @@ Gem::Specification.new do |spec| | |
| 7 7 | 
             
              spec.description = spec.summary = "A gem that provides a client interface for the Sentry error logger"
         | 
| 8 8 | 
             
              spec.email = "accounts@sentry.io"
         | 
| 9 9 | 
             
              spec.license = 'MIT'
         | 
| 10 | 
            -
              spec.homepage = "https://github.com/getsentry/sentry-ruby"
         | 
| 11 10 |  | 
| 12 11 | 
             
              spec.platform = Gem::Platform::RUBY
         | 
| 13 12 | 
             
              spec.required_ruby_version = '>= 2.4'
         | 
| 14 13 | 
             
              spec.extra_rdoc_files = ["README.md", "LICENSE.txt"]
         | 
| 15 14 | 
             
              spec.files = `git ls-files | grep -Ev '^(spec|benchmarks|examples)'`.split("\n")
         | 
| 16 15 |  | 
| 17 | 
            -
               | 
| 18 | 
            -
              spec. | 
| 19 | 
            -
             | 
| 16 | 
            +
              github_root_uri = 'https://github.com/getsentry/sentry-ruby'
         | 
| 17 | 
            +
              spec.homepage = "#{github_root_uri}/tree/#{spec.version}/#{spec.name}"
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              spec.metadata = {
         | 
| 20 | 
            +
                "homepage_uri" => spec.homepage,
         | 
| 21 | 
            +
                "source_code_uri" => spec.homepage,
         | 
| 22 | 
            +
                "changelog_uri" => "#{github_root_uri}/blob/#{spec.version}/CHANGELOG.md",
         | 
| 23 | 
            +
                "bug_tracker_uri" => "#{github_root_uri}/issues",
         | 
| 24 | 
            +
                "documentation_uri" => "http://www.rubydoc.info/gems/#{spec.name}/#{spec.version}"
         | 
| 25 | 
            +
              }
         | 
| 20 26 |  | 
| 21 27 | 
             
              spec.require_paths = ["lib"]
         | 
| 22 28 |  | 
| 23 | 
            -
              spec.add_dependency "concurrent-ruby",  | 
| 29 | 
            +
              spec.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2"
         | 
| 30 | 
            +
              spec.add_dependency "bigdecimal"
         | 
| 24 31 | 
             
            end
         |