sentry-ruby 5.19.0 → 5.21.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/Rakefile +2 -0
- data/bin/console +1 -0
- data/lib/sentry/attachment.rb +3 -5
- data/lib/sentry/backtrace.rb +3 -5
- data/lib/sentry/baggage.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
- data/lib/sentry/check_in_event.rb +4 -4
- data/lib/sentry/client.rb +9 -9
- data/lib/sentry/configuration.rb +52 -19
- data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
- data/lib/sentry/cron/monitor_check_ins.rb +3 -1
- data/lib/sentry/cron/monitor_config.rb +1 -1
- data/lib/sentry/dsn.rb +3 -3
- data/lib/sentry/envelope/item.rb +88 -0
- data/lib/sentry/envelope.rb +2 -85
- data/lib/sentry/event.rb +7 -7
- data/lib/sentry/graphql.rb +1 -1
- data/lib/sentry/hub.rb +8 -1
- data/lib/sentry/interfaces/mechanism.rb +1 -1
- data/lib/sentry/interfaces/request.rb +5 -5
- data/lib/sentry/interfaces/single_exception.rb +3 -3
- data/lib/sentry/interfaces/stacktrace.rb +3 -1
- data/lib/sentry/interfaces/stacktrace_builder.rb +15 -2
- data/lib/sentry/logger.rb +1 -1
- data/lib/sentry/metrics/aggregator.rb +12 -12
- data/lib/sentry/metrics/set_metric.rb +2 -2
- data/lib/sentry/metrics.rb +15 -15
- data/lib/sentry/net/http.rb +1 -1
- data/lib/sentry/profiler/helpers.rb +46 -0
- data/lib/sentry/profiler.rb +25 -56
- data/lib/sentry/propagation_context.rb +1 -1
- data/lib/sentry/rack/capture_exceptions.rb +2 -2
- data/lib/sentry/rack.rb +2 -2
- data/lib/sentry/rake.rb +2 -2
- data/lib/sentry/release_detector.rb +4 -4
- data/lib/sentry/scope.rb +1 -0
- data/lib/sentry/session_flusher.rb +1 -1
- data/lib/sentry/span.rb +6 -0
- data/lib/sentry/test_helper.rb +3 -1
- data/lib/sentry/transaction.rb +4 -4
- data/lib/sentry/transaction_event.rb +1 -2
- data/lib/sentry/transport/http_transport.rb +12 -12
- data/lib/sentry/transport.rb +4 -4
- data/lib/sentry/utils/env_helper.rb +21 -0
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/vernier/output.rb +89 -0
- data/lib/sentry/vernier/profiler.rb +125 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +5 -4
- data/sentry-ruby-core.gemspec +3 -1
- data/sentry-ruby.gemspec +3 -1
- metadata +13 -8
| @@ -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[ | 
| 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,  | 
| 21 | 
            -
                    revision_log = File.join(project_root,  | 
| 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[ | 
| 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
         | 
    
        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 = {
         | 
    
        data/lib/sentry/test_helper.rb
    CHANGED
    
    | @@ -1,6 +1,8 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Sentry
         | 
| 2 4 | 
             
              module TestHelper
         | 
| 3 | 
            -
                DUMMY_DSN =  | 
| 5 | 
            +
                DUMMY_DSN = "http://12345:67890@sentry.localdomain/sentry/42"
         | 
| 4 6 |  | 
| 5 7 | 
             
                # Alters the existing SDK configuration with test-suitable options. Mainly:
         | 
| 6 8 | 
             
                # - Sets a dummy DSN instead of `nil` or an actual DSN.
         | 
    
        data/lib/sentry/transaction.rb
    CHANGED
    
    | @@ -9,7 +9,7 @@ module Sentry | |
| 9 9 | 
             
                # @deprecated Use Sentry::PropagationContext::SENTRY_TRACE_REGEXP instead.
         | 
| 10 10 | 
             
                SENTRY_TRACE_REGEXP = PropagationContext::SENTRY_TRACE_REGEXP
         | 
| 11 11 |  | 
| 12 | 
            -
                UNLABELD_NAME = "<unlabeled transaction>" | 
| 12 | 
            +
                UNLABELD_NAME = "<unlabeled transaction>"
         | 
| 13 13 | 
             
                MESSAGE_PREFIX = "[Tracing]"
         | 
| 14 14 |  | 
| 15 15 | 
             
                # https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations
         | 
| @@ -85,7 +85,7 @@ module Sentry | |
| 85 85 | 
             
                  @effective_sample_rate = nil
         | 
| 86 86 | 
             
                  @contexts = {}
         | 
| 87 87 | 
             
                  @measurements = {}
         | 
| 88 | 
            -
                  @profiler =  | 
| 88 | 
            +
                  @profiler = @configuration.profiler_class.new(@configuration)
         | 
| 89 89 | 
             
                  init_span_recorder
         | 
| 90 90 | 
             
                end
         | 
| 91 91 |  | 
| @@ -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,  | 
| 269 | 
            -
                    hub.current_client.transport.record_lost_event(reason,  | 
| 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 |  | 
| @@ -74,8 +74,7 @@ module Sentry | |
| 74 74 | 
             
                      id: event_id,
         | 
| 75 75 | 
             
                      name: transaction.name,
         | 
| 76 76 | 
             
                      trace_id: transaction.trace_id,
         | 
| 77 | 
            -
                       | 
| 78 | 
            -
                      active_thead_id: '0'
         | 
| 77 | 
            +
                      active_thread_id: transaction.profiler.active_thread_id.to_s
         | 
| 79 78 | 
             
                    }
         | 
| 80 79 | 
             
                  )
         | 
| 81 80 |  | 
| @@ -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 =  | 
| 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 | 
            -
                     | 
| 42 | 
            -
                     | 
| 43 | 
            -
                     | 
| 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[ | 
| 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[ | 
| 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 | 
            -
                     | 
| 82 | 
            -
                     | 
| 83 | 
            -
                     | 
| 84 | 
            -
                     | 
| 81 | 
            +
                    "sentry_version" => PROTOCOL_VERSION,
         | 
| 82 | 
            +
                    "sentry_client" => USER_AGENT,
         | 
| 83 | 
            +
                    "sentry_timestamp" => now,
         | 
| 84 | 
            +
                    "sentry_key" => @dsn.public_key
         | 
| 85 85 | 
             
                  }
         | 
| 86 | 
            -
                  fields[ | 
| 87 | 
            -
                   | 
| 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
         | 
    
        data/lib/sentry/transport.rb
    CHANGED
    
    | @@ -5,7 +5,7 @@ require "sentry/envelope" | |
| 5 5 |  | 
| 6 6 | 
             
            module Sentry
         | 
| 7 7 | 
             
              class Transport
         | 
| 8 | 
            -
                PROTOCOL_VERSION =  | 
| 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:  | 
| 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:  | 
| 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:  | 
| 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
         | 
    
        data/lib/sentry/utils/real_ip.rb
    CHANGED
    
    
| @@ -0,0 +1,89 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "json"
         | 
| 4 | 
            +
            require "rbconfig"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Sentry
         | 
| 7 | 
            +
              module Vernier
         | 
| 8 | 
            +
                class Output
         | 
| 9 | 
            +
                  include Profiler::Helpers
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  attr_reader :profile
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize(profile, project_root:, in_app_pattern:, app_dirs_pattern:)
         | 
| 14 | 
            +
                    @profile = profile
         | 
| 15 | 
            +
                    @project_root = project_root
         | 
| 16 | 
            +
                    @in_app_pattern = in_app_pattern
         | 
| 17 | 
            +
                    @app_dirs_pattern = app_dirs_pattern
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def to_h
         | 
| 21 | 
            +
                    @to_h ||= {
         | 
| 22 | 
            +
                      frames: frames,
         | 
| 23 | 
            +
                      stacks: stacks,
         | 
| 24 | 
            +
                      samples: samples,
         | 
| 25 | 
            +
                      thread_metadata: thread_metadata
         | 
| 26 | 
            +
                    }
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  private
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def thread_metadata
         | 
| 32 | 
            +
                    profile.threads.map { |thread_id, thread_info|
         | 
| 33 | 
            +
                      [thread_id, { name: thread_info[:name] }]
         | 
| 34 | 
            +
                    }.to_h
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def samples
         | 
| 38 | 
            +
                    profile.threads.flat_map { |thread_id, thread_info|
         | 
| 39 | 
            +
                      started_at = thread_info[:started_at]
         | 
| 40 | 
            +
                      samples, timestamps = thread_info.values_at(:samples, :timestamps)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                      samples.zip(timestamps).map { |stack_id, timestamp|
         | 
| 43 | 
            +
                        elapsed_since_start_ns = timestamp - started_at
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                        next if elapsed_since_start_ns < 0
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                        {
         | 
| 48 | 
            +
                          thread_id: thread_id.to_s,
         | 
| 49 | 
            +
                          stack_id: stack_id,
         | 
| 50 | 
            +
                          elapsed_since_start_ns: elapsed_since_start_ns.to_s
         | 
| 51 | 
            +
                        }
         | 
| 52 | 
            +
                      }.compact
         | 
| 53 | 
            +
                    }
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  def frames
         | 
| 57 | 
            +
                    funcs = stack_table_hash[:frame_table].fetch(:func)
         | 
| 58 | 
            +
                    lines = stack_table_hash[:func_table].fetch(:first_line)
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                    funcs.map do |idx|
         | 
| 61 | 
            +
                      function, mod = split_module(stack_table_hash[:func_table][:name][idx])
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                      abs_path = stack_table_hash[:func_table][:filename][idx]
         | 
| 64 | 
            +
                      in_app = in_app?(abs_path)
         | 
| 65 | 
            +
                      filename = compute_filename(abs_path, in_app)
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                      {
         | 
| 68 | 
            +
                        function: function,
         | 
| 69 | 
            +
                        module: mod,
         | 
| 70 | 
            +
                        filename: filename,
         | 
| 71 | 
            +
                        abs_path: abs_path,
         | 
| 72 | 
            +
                        lineno: (lineno = lines[idx]) > 0 ? lineno : nil,
         | 
| 73 | 
            +
                        in_app: in_app
         | 
| 74 | 
            +
                      }.compact
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  def stacks
         | 
| 79 | 
            +
                    profile._stack_table.stack_count.times.map do |stack_id|
         | 
| 80 | 
            +
                      profile.stack(stack_id).frames.map(&:idx)
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  def stack_table_hash
         | 
| 85 | 
            +
                    @stack_table_hash ||= profile._stack_table.to_h
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
              end
         | 
| 89 | 
            +
            end
         | 
| @@ -0,0 +1,125 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "securerandom"
         | 
| 4 | 
            +
            require_relative "../profiler/helpers"
         | 
| 5 | 
            +
            require_relative "output"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Sentry
         | 
| 8 | 
            +
              module Vernier
         | 
| 9 | 
            +
                class Profiler
         | 
| 10 | 
            +
                  EMPTY_RESULT = {}.freeze
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  attr_reader :started, :event_id, :result
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def initialize(configuration)
         | 
| 15 | 
            +
                    @event_id = SecureRandom.uuid.delete("-")
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    @started = false
         | 
| 18 | 
            +
                    @sampled = nil
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    @profiling_enabled = defined?(Vernier) && configuration.profiling_enabled?
         | 
| 21 | 
            +
                    @profiles_sample_rate = configuration.profiles_sample_rate
         | 
| 22 | 
            +
                    @project_root = configuration.project_root
         | 
| 23 | 
            +
                    @app_dirs_pattern = configuration.app_dirs_pattern
         | 
| 24 | 
            +
                    @in_app_pattern = Regexp.new("^(#{@project_root}/)?#{@app_dirs_pattern}")
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def set_initial_sample_decision(transaction_sampled)
         | 
| 28 | 
            +
                    unless @profiling_enabled
         | 
| 29 | 
            +
                      @sampled = false
         | 
| 30 | 
            +
                      return
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    unless transaction_sampled
         | 
| 34 | 
            +
                      @sampled = false
         | 
| 35 | 
            +
                      log("Discarding profile because transaction not sampled")
         | 
| 36 | 
            +
                      return
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    case @profiles_sample_rate
         | 
| 40 | 
            +
                    when 0.0
         | 
| 41 | 
            +
                      @sampled = false
         | 
| 42 | 
            +
                      log("Discarding profile because sample_rate is 0")
         | 
| 43 | 
            +
                      return
         | 
| 44 | 
            +
                    when 1.0
         | 
| 45 | 
            +
                      @sampled = true
         | 
| 46 | 
            +
                      return
         | 
| 47 | 
            +
                    else
         | 
| 48 | 
            +
                      @sampled = Random.rand < @profiles_sample_rate
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    log("Discarding profile due to sampling decision") unless @sampled
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  def start
         | 
| 55 | 
            +
                    return unless @sampled
         | 
| 56 | 
            +
                    return if @started
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    ::Vernier.start_profile
         | 
| 59 | 
            +
                    @started = true
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    log("Started")
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    @started
         | 
| 64 | 
            +
                  rescue RuntimeError => e
         | 
| 65 | 
            +
                    # TODO: once Vernier raises something more dedicated, we should catch that instead
         | 
| 66 | 
            +
                    if e.message.include?("Profile already started")
         | 
| 67 | 
            +
                      log("Not started since running elsewhere")
         | 
| 68 | 
            +
                    else
         | 
| 69 | 
            +
                      log("Failed to start: #{e.message}")
         | 
| 70 | 
            +
                    end
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  def stop
         | 
| 74 | 
            +
                    return unless @sampled
         | 
| 75 | 
            +
                    return unless @started
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    @result = ::Vernier.stop_profile
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    log("Stopped")
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  def active_thread_id
         | 
| 83 | 
            +
                    Thread.current.object_id
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  def to_hash
         | 
| 87 | 
            +
                    return EMPTY_RESULT unless @started
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    unless @sampled
         | 
| 90 | 
            +
                      record_lost_event(:sample_rate)
         | 
| 91 | 
            +
                      return EMPTY_RESULT
         | 
| 92 | 
            +
                    end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                    { **profile_meta, profile: output.to_h }
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  private
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  def log(message)
         | 
| 100 | 
            +
                    Sentry.logger.debug(LOGGER_PROGNAME) { "[Profiler::Vernier] #{message}" }
         | 
| 101 | 
            +
                  end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  def record_lost_event(reason)
         | 
| 104 | 
            +
                    Sentry.get_current_client&.transport&.record_lost_event(reason, "profile")
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  def profile_meta
         | 
| 108 | 
            +
                    {
         | 
| 109 | 
            +
                      event_id: @event_id,
         | 
| 110 | 
            +
                      version: "1",
         | 
| 111 | 
            +
                      platform: "ruby"
         | 
| 112 | 
            +
                    }
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  def output
         | 
| 116 | 
            +
                    @output ||= Output.new(
         | 
| 117 | 
            +
                      result,
         | 
| 118 | 
            +
                      project_root: @project_root,
         | 
| 119 | 
            +
                      app_dirs_pattern: @app_dirs_pattern,
         | 
| 120 | 
            +
                      in_app_pattern: @in_app_pattern
         | 
| 121 | 
            +
                    )
         | 
| 122 | 
            +
                  end
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
              end
         | 
| 125 | 
            +
            end
         | 
    
        data/lib/sentry/version.rb
    CHANGED
    
    
    
        data/lib/sentry-ruby.rb
    CHANGED
    
    | @@ -25,6 +25,7 @@ require "sentry/session_flusher" | |
| 25 25 | 
             
            require "sentry/backpressure_monitor"
         | 
| 26 26 | 
             
            require "sentry/cron/monitor_check_ins"
         | 
| 27 27 | 
             
            require "sentry/metrics"
         | 
| 28 | 
            +
            require "sentry/vernier/profiler"
         | 
| 28 29 |  | 
| 29 30 | 
             
            [
         | 
| 30 31 | 
             
              "sentry/rake",
         | 
| @@ -41,11 +42,11 @@ module Sentry | |
| 41 42 |  | 
| 42 43 | 
             
              CAPTURED_SIGNATURE = :@__sentry_captured
         | 
| 43 44 |  | 
| 44 | 
            -
              LOGGER_PROGNAME = "sentry" | 
| 45 | 
            +
              LOGGER_PROGNAME = "sentry"
         | 
| 45 46 |  | 
| 46 | 
            -
              SENTRY_TRACE_HEADER_NAME = "sentry-trace" | 
| 47 | 
            +
              SENTRY_TRACE_HEADER_NAME = "sentry-trace"
         | 
| 47 48 |  | 
| 48 | 
            -
              BAGGAGE_HEADER_NAME = "baggage" | 
| 49 | 
            +
              BAGGAGE_HEADER_NAME = "baggage"
         | 
| 49 50 |  | 
| 50 51 | 
             
              THREAD_LOCAL = :sentry_hub
         | 
| 51 52 |  | 
| @@ -563,7 +564,7 @@ module Sentry | |
| 563 564 | 
             
                #
         | 
| 564 565 | 
             
                # @return [String]
         | 
| 565 566 | 
             
                def get_trace_propagation_meta
         | 
| 566 | 
            -
                  return  | 
| 567 | 
            +
                  return "" unless initialized?
         | 
| 567 568 | 
             
                  get_current_hub.get_trace_propagation_meta
         | 
| 568 569 | 
             
                end
         | 
| 569 570 |  | 
    
        data/sentry-ruby-core.gemspec
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require_relative "lib/sentry/version"
         | 
| 2 4 |  | 
| 3 5 | 
             
            Gem::Specification.new do |spec|
         | 
| @@ -12,7 +14,7 @@ Gem::Specification.new do |spec| | |
| 12 14 | 
             
              spec.platform = Gem::Platform::RUBY
         | 
| 13 15 | 
             
              spec.required_ruby_version = '>= 2.4'
         | 
| 14 16 | 
             
              spec.extra_rdoc_files = ["README.md", "LICENSE.txt"]
         | 
| 15 | 
            -
              spec.files = `git ls-files | grep -Ev '^(spec|benchmarks|examples)'`.split("\n")
         | 
| 17 | 
            +
              spec.files = `git ls-files | grep -Ev '^(spec|benchmarks|examples|\.rubocop\.yml)'`.split("\n")
         | 
| 16 18 |  | 
| 17 19 | 
             
              spec.metadata["homepage_uri"] = spec.homepage
         | 
| 18 20 | 
             
              spec.metadata["source_code_uri"] = spec.homepage
         | 
    
        data/sentry-ruby.gemspec
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require_relative "lib/sentry/version"
         | 
| 2 4 |  | 
| 3 5 | 
             
            Gem::Specification.new do |spec|
         | 
| @@ -11,7 +13,7 @@ Gem::Specification.new do |spec| | |
| 11 13 | 
             
              spec.platform = Gem::Platform::RUBY
         | 
| 12 14 | 
             
              spec.required_ruby_version = '>= 2.4'
         | 
| 13 15 | 
             
              spec.extra_rdoc_files = ["README.md", "LICENSE.txt"]
         | 
| 14 | 
            -
              spec.files = `git ls-files | grep -Ev '^(spec|benchmarks|examples)'`.split("\n")
         | 
| 16 | 
            +
              spec.files = `git ls-files | grep -Ev '^(spec|benchmarks|examples|\.rubocop\.yml)'`.split("\n")
         | 
| 15 17 |  | 
| 16 18 | 
             
              github_root_uri = 'https://github.com/getsentry/sentry-ruby'
         | 
| 17 19 | 
             
              spec.homepage = "#{github_root_uri}/tree/#{spec.version}/#{spec.name}"
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: sentry-ruby
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 5. | 
| 4 | 
            +
              version: 5.21.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- | 
| 11 | 
            +
            date: 2024-10-07 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: concurrent-ruby
         | 
| @@ -83,6 +83,7 @@ files: | |
| 83 83 | 
             
            - lib/sentry/cron/monitor_schedule.rb
         | 
| 84 84 | 
             
            - lib/sentry/dsn.rb
         | 
| 85 85 | 
             
            - lib/sentry/envelope.rb
         | 
| 86 | 
            +
            - lib/sentry/envelope/item.rb
         | 
| 86 87 | 
             
            - lib/sentry/error_event.rb
         | 
| 87 88 | 
             
            - lib/sentry/event.rb
         | 
| 88 89 | 
             
            - lib/sentry/exceptions.rb
         | 
| @@ -112,6 +113,7 @@ files: | |
| 112 113 | 
             
            - lib/sentry/metrics/timing.rb
         | 
| 113 114 | 
             
            - lib/sentry/net/http.rb
         | 
| 114 115 | 
             
            - lib/sentry/profiler.rb
         | 
| 116 | 
            +
            - lib/sentry/profiler/helpers.rb
         | 
| 115 117 | 
             
            - lib/sentry/propagation_context.rb
         | 
| 116 118 | 
             
            - lib/sentry/puma.rb
         | 
| 117 119 | 
             
            - lib/sentry/rack.rb
         | 
| @@ -135,23 +137,26 @@ files: | |
| 135 137 | 
             
            - lib/sentry/utils/argument_checking_helper.rb
         | 
| 136 138 | 
             
            - lib/sentry/utils/custom_inspection.rb
         | 
| 137 139 | 
             
            - lib/sentry/utils/encoding_helper.rb
         | 
| 140 | 
            +
            - lib/sentry/utils/env_helper.rb
         | 
| 138 141 | 
             
            - lib/sentry/utils/exception_cause_chain.rb
         | 
| 139 142 | 
             
            - lib/sentry/utils/http_tracing.rb
         | 
| 140 143 | 
             
            - lib/sentry/utils/logging_helper.rb
         | 
| 141 144 | 
             
            - lib/sentry/utils/real_ip.rb
         | 
| 142 145 | 
             
            - lib/sentry/utils/request_id.rb
         | 
| 146 | 
            +
            - lib/sentry/vernier/output.rb
         | 
| 147 | 
            +
            - lib/sentry/vernier/profiler.rb
         | 
| 143 148 | 
             
            - lib/sentry/version.rb
         | 
| 144 149 | 
             
            - sentry-ruby-core.gemspec
         | 
| 145 150 | 
             
            - sentry-ruby.gemspec
         | 
| 146 | 
            -
            homepage: https://github.com/getsentry/sentry-ruby/tree/5. | 
| 151 | 
            +
            homepage: https://github.com/getsentry/sentry-ruby/tree/5.21.0/sentry-ruby
         | 
| 147 152 | 
             
            licenses:
         | 
| 148 153 | 
             
            - MIT
         | 
| 149 154 | 
             
            metadata:
         | 
| 150 | 
            -
              homepage_uri: https://github.com/getsentry/sentry-ruby/tree/5. | 
| 151 | 
            -
              source_code_uri: https://github.com/getsentry/sentry-ruby/tree/5. | 
| 152 | 
            -
              changelog_uri: https://github.com/getsentry/sentry-ruby/blob/5. | 
| 155 | 
            +
              homepage_uri: https://github.com/getsentry/sentry-ruby/tree/5.21.0/sentry-ruby
         | 
| 156 | 
            +
              source_code_uri: https://github.com/getsentry/sentry-ruby/tree/5.21.0/sentry-ruby
         | 
| 157 | 
            +
              changelog_uri: https://github.com/getsentry/sentry-ruby/blob/5.21.0/CHANGELOG.md
         | 
| 153 158 | 
             
              bug_tracker_uri: https://github.com/getsentry/sentry-ruby/issues
         | 
| 154 | 
            -
              documentation_uri: http://www.rubydoc.info/gems/sentry-ruby/5. | 
| 159 | 
            +
              documentation_uri: http://www.rubydoc.info/gems/sentry-ruby/5.21.0
         | 
| 155 160 | 
             
            post_install_message: 
         | 
| 156 161 | 
             
            rdoc_options: []
         | 
| 157 162 | 
             
            require_paths:
         | 
| @@ -167,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 167 172 | 
             
                - !ruby/object:Gem::Version
         | 
| 168 173 | 
             
                  version: '0'
         | 
| 169 174 | 
             
            requirements: []
         | 
| 170 | 
            -
            rubygems_version: 3.5. | 
| 175 | 
            +
            rubygems_version: 3.5.16
         | 
| 171 176 | 
             
            signing_key: 
         | 
| 172 177 | 
             
            specification_version: 4
         | 
| 173 178 | 
             
            summary: A gem that provides a client interface for the Sentry error logger
         |