sentry-ruby 5.4.2 → 5.16.1
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/.rspec +0 -1
- data/Gemfile +13 -14
- data/README.md +11 -8
- data/Rakefile +8 -1
- data/lib/sentry/background_worker.rb +8 -1
- data/lib/sentry/backpressure_monitor.rb +75 -0
- data/lib/sentry/backtrace.rb +1 -1
- data/lib/sentry/baggage.rb +70 -0
- data/lib/sentry/breadcrumb.rb +8 -2
- data/lib/sentry/check_in_event.rb +60 -0
- data/lib/sentry/client.rb +77 -19
- data/lib/sentry/configuration.rb +177 -29
- data/lib/sentry/cron/configuration.rb +23 -0
- data/lib/sentry/cron/monitor_check_ins.rb +75 -0
- data/lib/sentry/cron/monitor_config.rb +53 -0
- data/lib/sentry/cron/monitor_schedule.rb +42 -0
- data/lib/sentry/envelope.rb +2 -5
- data/lib/sentry/event.rb +7 -29
- data/lib/sentry/hub.rb +100 -4
- data/lib/sentry/integrable.rb +6 -0
- data/lib/sentry/interfaces/request.rb +6 -16
- data/lib/sentry/interfaces/single_exception.rb +13 -3
- data/lib/sentry/net/http.rb +37 -46
- data/lib/sentry/profiler.rb +233 -0
- data/lib/sentry/propagation_context.rb +134 -0
- data/lib/sentry/puma.rb +32 -0
- data/lib/sentry/rack/capture_exceptions.rb +4 -5
- data/lib/sentry/rake.rb +1 -14
- data/lib/sentry/redis.rb +41 -23
- data/lib/sentry/release_detector.rb +1 -1
- data/lib/sentry/scope.rb +81 -16
- data/lib/sentry/session.rb +5 -7
- data/lib/sentry/span.rb +57 -10
- data/lib/sentry/test_helper.rb +19 -11
- data/lib/sentry/transaction.rb +183 -30
- data/lib/sentry/transaction_event.rb +51 -0
- data/lib/sentry/transport/configuration.rb +74 -1
- data/lib/sentry/transport/http_transport.rb +68 -37
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +39 -24
- data/lib/sentry/utils/argument_checking_helper.rb +9 -3
- data/lib/sentry/utils/encoding_helper.rb +22 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +116 -41
- metadata +14 -3
- data/CODE_OF_CONDUCT.md +0 -74
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 565289974a80625ef7ecac6926cfb7292569dfafd84f12584a8214619bdd5ed5
         | 
| 4 | 
            +
              data.tar.gz: 005b3e5c27b7188058c412d36981779eb759f7be1032429eea17a2e4a7ffcb9f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d0e68db7961263d6aa070feaa131fae4c2039884e565cd248795298a99f08d66e7c921df1a6f6175e68ac0ed554185b4b94769f8b0fcba12d76e6aa042fc3359
         | 
| 7 | 
            +
              data.tar.gz: 5e10f1406d7a7809aed02cef80e1d4355e61af54ed42ffd9a1b3a54a730229abfef4f0a690980c646757b93fffa6219d6500c5700b08a6eef61b6eb682d63620
         | 
    
        data/.rspec
    CHANGED
    
    
    
        data/Gemfile
    CHANGED
    
    | @@ -3,25 +3,24 @@ git_source(:github) { |name| "https://github.com/#{name}.git" } | |
| 3 3 |  | 
| 4 4 | 
             
            gem "sentry-ruby", path: "./"
         | 
| 5 5 |  | 
| 6 | 
            -
             | 
| 6 | 
            +
            rack_version = ENV["RACK_VERSION"]
         | 
| 7 | 
            +
            rack_version = "3.0.0" if rack_version.nil?
         | 
| 8 | 
            +
            gem "rack", "~> #{Gem::Version.new(rack_version)}" unless rack_version == "0"
         | 
| 7 9 |  | 
| 8 | 
            -
             | 
| 9 | 
            -
            gem " | 
| 10 | 
            -
             | 
| 11 | 
            -
            gem " | 
| 12 | 
            -
            gem "fakeredis"
         | 
| 13 | 
            -
            gem "timecop"
         | 
| 14 | 
            -
            gem 'simplecov'
         | 
| 15 | 
            -
            gem "simplecov-cobertura", "~> 1.4"
         | 
| 16 | 
            -
            gem "rexml"
         | 
| 10 | 
            +
            redis_rb_version = ENV.fetch("REDIS_RB_VERSION", "5.0")
         | 
| 11 | 
            +
            gem "redis", "~> #{redis_rb_version}"
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            gem "puma"
         | 
| 17 14 |  | 
| 18 | 
            -
            gem " | 
| 19 | 
            -
            gem " | 
| 20 | 
            -
            gem "pry"
         | 
| 15 | 
            +
            gem "timecop"
         | 
| 16 | 
            +
            gem "stackprof" unless RUBY_PLATFORM == "java"
         | 
| 21 17 |  | 
| 22 18 | 
             
            gem "benchmark-ips"
         | 
| 23 19 | 
             
            gem "benchmark_driver"
         | 
| 24 20 | 
             
            gem "benchmark-ipsa"
         | 
| 25 21 | 
             
            gem "benchmark-memory"
         | 
| 26 22 |  | 
| 27 | 
            -
            gem "yard",  | 
| 23 | 
            +
            gem "yard", github: "lsegal/yard"
         | 
| 24 | 
            +
            gem "webrick"
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            eval_gemfile File.expand_path("../Gemfile", __dir__)
         | 
    
        data/README.md
    CHANGED
    
    | @@ -13,13 +13,14 @@ _Bad software is everywhere, and we're tired of it. Sentry is on a mission to he | |
| 13 13 | 
             
            Sentry SDK for Ruby
         | 
| 14 14 | 
             
            ===========
         | 
| 15 15 |  | 
| 16 | 
            -
            | current version | 
| 17 | 
            -
            | --- | 
| 18 | 
            -
            | [](https://rubygems.org/gems/sentry-ruby) | 
| 19 | 
            -
            | [](https://rubygems.org/gems/sentry-rails) | 
| 20 | 
            -
            | [](https://rubygems.org/gems/sentry-sidekiq) | 
| 21 | 
            -
            | [](https://rubygems.org/gems/sentry-delayed_job) | 
| 22 | 
            -
            | [](https://rubygems.org/gems/sentry-resque) | 
| 16 | 
            +
            | current version                                                                                                                                | build                                                                                                                                                                                                           | coverage                                                                                                                                                           | downloads                                                                                                               |
         | 
| 17 | 
            +
            | ---                                                                                                                                            | -----                                                                                                                                                                                                           | --------                                                                                                                                                           | ---------                                                                                                               |
         | 
| 18 | 
            +
            | [](https://rubygems.org/gems/sentry-ruby)                            | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml)                   | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-ruby/)                   |
         | 
| 19 | 
            +
            | [](https://rubygems.org/gems/sentry-rails)                         | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml)                 | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-rails/)                 |
         | 
| 20 | 
            +
            | [](https://rubygems.org/gems/sentry-sidekiq)                   | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml)             | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-sidekiq/)             |
         | 
| 21 | 
            +
            | [](https://rubygems.org/gems/sentry-delayed_job)       | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml)     | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-delayed_job/)     |
         | 
| 22 | 
            +
            | [](https://rubygems.org/gems/sentry-resque)                      | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml)               | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-resque/)               |
         | 
| 23 | 
            +
            | [](https://rubygems.org/gems/sentry-opentelemetry) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_opentelemetry_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-opentelemetry/) |
         | 
| 23 24 |  | 
| 24 25 |  | 
| 25 26 |  | 
| @@ -32,7 +33,7 @@ If you're using `sentry-raven`, we recommend you to migrate to this new SDK. You | |
| 32 33 |  | 
| 33 34 | 
             
            ## Requirements
         | 
| 34 35 |  | 
| 35 | 
            -
            We test  | 
| 36 | 
            +
            We test from Ruby 2.4 to Ruby 3.2 at the latest patchlevel/teeny version. We also support JRuby 9.0.
         | 
| 36 37 |  | 
| 37 38 | 
             
            If you use self-hosted Sentry, please also make sure its version is above `20.6.0`.
         | 
| 38 39 |  | 
| @@ -51,6 +52,7 @@ gem "sentry-rails" | |
| 51 52 | 
             
            gem "sentry-sidekiq"
         | 
| 52 53 | 
             
            gem "sentry-delayed_job"
         | 
| 53 54 | 
             
            gem "sentry-resque"
         | 
| 55 | 
            +
            gem "sentry-opentelemetry"
         | 
| 54 56 | 
             
            ```
         | 
| 55 57 |  | 
| 56 58 | 
             
            ### Configuration
         | 
| @@ -88,6 +90,7 @@ To learn more about sampling transactions, please visit the [official documentat | |
| 88 90 | 
             
            - [Sidekiq](https://docs.sentry.io/platforms/ruby/guides/sidekiq/)
         | 
| 89 91 | 
             
            - [DelayedJob](https://docs.sentry.io/platforms/ruby/guides/delayed_job/)
         | 
| 90 92 | 
             
            - [Resque](https://docs.sentry.io/platforms/ruby/guides/resque/)
         | 
| 93 | 
            +
            - [OpenTemeletry](https://docs.sentry.io/platforms/ruby/performance/instrumentation/opentelemetry/)
         | 
| 91 94 |  | 
| 92 95 | 
             
            ### Enriching Events
         | 
| 93 96 |  | 
    
        data/Rakefile
    CHANGED
    
    | @@ -8,6 +8,13 @@ require "rspec/core/rake_task" | |
| 8 8 |  | 
| 9 9 | 
             
            RSpec::Core::RakeTask.new(:spec).tap do |task|
         | 
| 10 10 | 
             
              task.rspec_opts = "--order rand"
         | 
| 11 | 
            +
              task.exclude_pattern = "spec/isolated/**/*_spec.rb"
         | 
| 11 12 | 
             
            end
         | 
| 12 13 |  | 
| 13 | 
            -
            task : | 
| 14 | 
            +
            task :isolated_specs do
         | 
| 15 | 
            +
              Dir["spec/isolated/*"].each do |file|
         | 
| 16 | 
            +
                sh "bundle exec rspec #{file}"
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            task :default => [:spec, :isolated_specs]
         | 
| @@ -13,10 +13,12 @@ module Sentry | |
| 13 13 | 
             
                attr_reader :logger
         | 
| 14 14 | 
             
                attr_accessor :shutdown_timeout
         | 
| 15 15 |  | 
| 16 | 
            +
                DEFAULT_MAX_QUEUE = 30
         | 
| 17 | 
            +
             | 
| 16 18 | 
             
                def initialize(configuration)
         | 
| 17 | 
            -
                  @max_queue = 30
         | 
| 18 19 | 
             
                  @shutdown_timeout = 1
         | 
| 19 20 | 
             
                  @number_of_threads = configuration.background_worker_threads
         | 
| 21 | 
            +
                  @max_queue = configuration.background_worker_max_queue
         | 
| 20 22 | 
             
                  @logger = configuration.logger
         | 
| 21 23 | 
             
                  @debug = configuration.debug
         | 
| 22 24 | 
             
                  @shutdown_callback = nil
         | 
| @@ -63,6 +65,11 @@ module Sentry | |
| 63 65 | 
             
                  @shutdown_callback&.call
         | 
| 64 66 | 
             
                end
         | 
| 65 67 |  | 
| 68 | 
            +
                def full?
         | 
| 69 | 
            +
                  @executor.is_a?(Concurrent::ThreadPoolExecutor) &&
         | 
| 70 | 
            +
                    @executor.remaining_capacity == 0
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 66 73 | 
             
                private
         | 
| 67 74 |  | 
| 68 75 | 
             
                def _perform(&block)
         | 
| @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Sentry
         | 
| 4 | 
            +
              class BackpressureMonitor
         | 
| 5 | 
            +
                include LoggingHelper
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                DEFAULT_INTERVAL = 10
         | 
| 8 | 
            +
                MAX_DOWNSAMPLE_FACTOR = 10
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def initialize(configuration, client, interval: DEFAULT_INTERVAL)
         | 
| 11 | 
            +
                  @interval = interval
         | 
| 12 | 
            +
                  @client = client
         | 
| 13 | 
            +
                  @logger = configuration.logger
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  @thread = nil
         | 
| 16 | 
            +
                  @exited = false
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  @healthy = true
         | 
| 19 | 
            +
                  @downsample_factor = 0
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def healthy?
         | 
| 23 | 
            +
                  ensure_thread
         | 
| 24 | 
            +
                  @healthy
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def downsample_factor
         | 
| 28 | 
            +
                  ensure_thread
         | 
| 29 | 
            +
                  @downsample_factor
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def run
         | 
| 33 | 
            +
                  check_health
         | 
| 34 | 
            +
                  set_downsample_factor
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def check_health
         | 
| 38 | 
            +
                  @healthy = !(@client.transport.any_rate_limited? || Sentry.background_worker&.full?)
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def set_downsample_factor
         | 
| 42 | 
            +
                  if @healthy
         | 
| 43 | 
            +
                    log_debug("[BackpressureMonitor] health check positive, reverting to normal sampling") if @downsample_factor.positive?
         | 
| 44 | 
            +
                    @downsample_factor = 0
         | 
| 45 | 
            +
                  else
         | 
| 46 | 
            +
                    @downsample_factor += 1 if @downsample_factor < MAX_DOWNSAMPLE_FACTOR
         | 
| 47 | 
            +
                    log_debug("[BackpressureMonitor] health check negative, downsampling with a factor of #{@downsample_factor}")
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def kill
         | 
| 52 | 
            +
                  log_debug("[BackpressureMonitor] killing monitor")
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  @exited = true
         | 
| 55 | 
            +
                  @thread&.kill
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                private
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def ensure_thread
         | 
| 61 | 
            +
                  return if @exited
         | 
| 62 | 
            +
                  return if @thread&.alive?
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  @thread = Thread.new do
         | 
| 65 | 
            +
                    loop do
         | 
| 66 | 
            +
                      sleep(@interval)
         | 
| 67 | 
            +
                      run
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                rescue ThreadError
         | 
| 71 | 
            +
                  log_debug("[BackpressureMonitor] Thread creation failed")
         | 
| 72 | 
            +
                  @exited = true
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
            end
         | 
    
        data/lib/sentry/backtrace.rb
    CHANGED
    
    
| @@ -0,0 +1,70 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'cgi'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Sentry
         | 
| 6 | 
            +
              # A {https://www.w3.org/TR/baggage W3C Baggage Header} implementation.
         | 
| 7 | 
            +
              class Baggage
         | 
| 8 | 
            +
                SENTRY_PREFIX = 'sentry-'
         | 
| 9 | 
            +
                SENTRY_PREFIX_REGEX = /^sentry-/.freeze
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                # @return [Hash]
         | 
| 12 | 
            +
                attr_reader :items
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                # @return [Boolean]
         | 
| 15 | 
            +
                attr_reader :mutable
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def initialize(items, mutable: true)
         | 
| 18 | 
            +
                  @items = items
         | 
| 19 | 
            +
                  @mutable = mutable
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                # Creates a Baggage object from an incoming W3C Baggage header string.
         | 
| 23 | 
            +
                #
         | 
| 24 | 
            +
                # Sentry items are identified with the 'sentry-' prefix and stored in a hash.
         | 
| 25 | 
            +
                # The presence of a Sentry item makes the baggage object immutable.
         | 
| 26 | 
            +
                #
         | 
| 27 | 
            +
                # @param header [String] The incoming Baggage header string.
         | 
| 28 | 
            +
                # @return [Baggage, nil]
         | 
| 29 | 
            +
                def self.from_incoming_header(header)
         | 
| 30 | 
            +
                  items = {}
         | 
| 31 | 
            +
                  mutable = true
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  header.split(',').each do |item|
         | 
| 34 | 
            +
                    item = item.strip
         | 
| 35 | 
            +
                    key, val = item.split('=')
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    next unless key && val
         | 
| 38 | 
            +
                    next unless key =~ SENTRY_PREFIX_REGEX
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    baggage_key = key.split('-')[1]
         | 
| 41 | 
            +
                    next unless baggage_key
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    items[CGI.unescape(baggage_key)] = CGI.unescape(val)
         | 
| 44 | 
            +
                    mutable = false
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  new(items, mutable: mutable)
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                # Make the Baggage immutable.
         | 
| 51 | 
            +
                # @return [void]
         | 
| 52 | 
            +
                def freeze!
         | 
| 53 | 
            +
                  @mutable = false
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                # A {https://develop.sentry.dev/sdk/performance/dynamic-sampling-context/#envelope-header Dynamic Sampling Context}
         | 
| 57 | 
            +
                # hash to be used in the trace envelope header.
         | 
| 58 | 
            +
                # @return [Hash]
         | 
| 59 | 
            +
                def dynamic_sampling_context
         | 
| 60 | 
            +
                  @items
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                # Serialize the Baggage object back to a string.
         | 
| 64 | 
            +
                # @return [String]
         | 
| 65 | 
            +
                def serialize
         | 
| 66 | 
            +
                  items = @items.map { |k, v| "#{SENTRY_PREFIX}#{CGI.escape(k)}=#{CGI.escape(v)}" }
         | 
| 67 | 
            +
                  items.join(',')
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
            end
         | 
    
        data/lib/sentry/breadcrumb.rb
    CHANGED
    
    | @@ -9,7 +9,7 @@ module Sentry | |
| 9 9 | 
             
                # @return [Hash, nil]
         | 
| 10 10 | 
             
                attr_accessor :data
         | 
| 11 11 | 
             
                # @return [String, nil]
         | 
| 12 | 
            -
                 | 
| 12 | 
            +
                attr_reader :level
         | 
| 13 13 | 
             
                # @return [Time, Integer, nil]
         | 
| 14 14 | 
             
                attr_accessor :timestamp
         | 
| 15 15 | 
             
                # @return [String, nil]
         | 
| @@ -26,10 +26,10 @@ module Sentry | |
| 26 26 | 
             
                def initialize(category: nil, data: nil, message: nil, timestamp: nil, level: nil, type: nil)
         | 
| 27 27 | 
             
                  @category = category
         | 
| 28 28 | 
             
                  @data = data || {}
         | 
| 29 | 
            -
                  @level = level
         | 
| 30 29 | 
             
                  @timestamp = timestamp || Sentry.utc_now.to_i
         | 
| 31 30 | 
             
                  @type = type
         | 
| 32 31 | 
             
                  self.message = message
         | 
| 32 | 
            +
                  self.level = level
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
| 35 35 | 
             
                # @return [Hash]
         | 
| @@ -50,6 +50,12 @@ module Sentry | |
| 50 50 | 
             
                  @message = (message || "").byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES)
         | 
| 51 51 | 
             
                end
         | 
| 52 52 |  | 
| 53 | 
            +
                # @param level [String]
         | 
| 54 | 
            +
                # @return [void]
         | 
| 55 | 
            +
                def level=(level) # needed to meet the Sentry spec
         | 
| 56 | 
            +
                  @level = level == "warn" ? "warning" : level
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 53 59 | 
             
                private
         | 
| 54 60 |  | 
| 55 61 | 
             
                def serialized_data
         | 
| @@ -0,0 +1,60 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'securerandom'
         | 
| 4 | 
            +
            require 'sentry/cron/monitor_config'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Sentry
         | 
| 7 | 
            +
              class CheckInEvent < Event
         | 
| 8 | 
            +
                TYPE = 'check_in'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # uuid to identify this check-in.
         | 
| 11 | 
            +
                # @return [String]
         | 
| 12 | 
            +
                attr_accessor :check_in_id
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                # Identifier of the monitor for this check-in.
         | 
| 15 | 
            +
                # @return [String]
         | 
| 16 | 
            +
                attr_accessor :monitor_slug
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                # Duration of this check since it has started in seconds.
         | 
| 19 | 
            +
                # @return [Integer, nil]
         | 
| 20 | 
            +
                attr_accessor :duration
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                # Monitor configuration to support upserts.
         | 
| 23 | 
            +
                # @return [Cron::MonitorConfig, nil]
         | 
| 24 | 
            +
                attr_accessor :monitor_config
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                # Status of this check-in.
         | 
| 27 | 
            +
                # @return [Symbol]
         | 
| 28 | 
            +
                attr_accessor :status
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                VALID_STATUSES = %i(ok in_progress error)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def initialize(
         | 
| 33 | 
            +
                  slug:,
         | 
| 34 | 
            +
                  status:,
         | 
| 35 | 
            +
                  duration: nil,
         | 
| 36 | 
            +
                  monitor_config: nil,
         | 
| 37 | 
            +
                  check_in_id: nil,
         | 
| 38 | 
            +
                  **options
         | 
| 39 | 
            +
                )
         | 
| 40 | 
            +
                  super(**options)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  self.monitor_slug = slug
         | 
| 43 | 
            +
                  self.status = status
         | 
| 44 | 
            +
                  self.duration = duration
         | 
| 45 | 
            +
                  self.monitor_config = monitor_config
         | 
| 46 | 
            +
                  self.check_in_id = check_in_id || SecureRandom.uuid.delete('-')
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                # @return [Hash]
         | 
| 50 | 
            +
                def to_hash
         | 
| 51 | 
            +
                  data = super
         | 
| 52 | 
            +
                  data[:check_in_id] = check_in_id
         | 
| 53 | 
            +
                  data[:monitor_slug] = monitor_slug
         | 
| 54 | 
            +
                  data[:status] = status
         | 
| 55 | 
            +
                  data[:duration] = duration if duration
         | 
| 56 | 
            +
                  data[:monitor_config] = monitor_config.to_hash if monitor_config
         | 
| 57 | 
            +
                  data
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
            end
         | 
    
        data/lib/sentry/client.rb
    CHANGED
    
    | @@ -10,6 +10,10 @@ module Sentry | |
| 10 10 | 
             
                # @return [Transport]
         | 
| 11 11 | 
             
                attr_reader :transport
         | 
| 12 12 |  | 
| 13 | 
            +
                # The Transport object that'll send events for the client.
         | 
| 14 | 
            +
                # @return [SpotlightTransport, nil]
         | 
| 15 | 
            +
                attr_reader :spotlight_transport
         | 
| 16 | 
            +
             | 
| 13 17 | 
             
                # @!macro configuration
         | 
| 14 18 | 
             
                attr_reader :configuration
         | 
| 15 19 |  | 
| @@ -32,6 +36,8 @@ module Sentry | |
| 32 36 | 
             
                        DummyTransport.new(configuration)
         | 
| 33 37 | 
             
                      end
         | 
| 34 38 | 
             
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  @spotlight_transport = SpotlightTransport.new(configuration) if configuration.spotlight
         | 
| 35 41 | 
             
                end
         | 
| 36 42 |  | 
| 37 43 | 
             
                # Applies the given scope's data to the event and sends it to Sentry.
         | 
| @@ -42,7 +48,7 @@ module Sentry | |
| 42 48 | 
             
                def capture_event(event, scope, hint = {})
         | 
| 43 49 | 
             
                  return unless configuration.sending_allowed?
         | 
| 44 50 |  | 
| 45 | 
            -
                   | 
| 51 | 
            +
                  if event.is_a?(ErrorEvent) && !configuration.sample_allowed?
         | 
| 46 52 | 
             
                    transport.record_lost_event(:sample_rate, 'event')
         | 
| 47 53 | 
             
                    return
         | 
| 48 54 | 
             
                  end
         | 
| @@ -51,7 +57,7 @@ module Sentry | |
| 51 57 | 
             
                  event = scope.apply_to_event(event, hint)
         | 
| 52 58 |  | 
| 53 59 | 
             
                  if event.nil?
         | 
| 54 | 
            -
                     | 
| 60 | 
            +
                    log_debug("Discarded event because one of the event processors returned nil")
         | 
| 55 61 | 
             
                    transport.record_lost_event(:event_processor, event_type)
         | 
| 56 62 | 
             
                    return
         | 
| 57 63 | 
             
                  end
         | 
| @@ -76,7 +82,10 @@ module Sentry | |
| 76 82 | 
             
                # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
         | 
| 77 83 | 
             
                # @return [Event, nil]
         | 
| 78 84 | 
             
                def event_from_exception(exception, hint = {})
         | 
| 79 | 
            -
                  return unless @configuration.sending_allowed? | 
| 85 | 
            +
                  return unless @configuration.sending_allowed?
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  ignore_exclusions = hint.delete(:ignore_exclusions) { false }
         | 
| 88 | 
            +
                  return if !ignore_exclusions && !@configuration.exception_class_allowed?(exception)
         | 
| 80 89 |  | 
| 81 90 | 
             
                  integration_meta = Sentry.integrations[hint[:integration]]
         | 
| 82 91 |  | 
| @@ -101,20 +110,42 @@ module Sentry | |
| 101 110 | 
             
                  event
         | 
| 102 111 | 
             
                end
         | 
| 103 112 |  | 
| 113 | 
            +
                # Initializes a CheckInEvent object with the given options.
         | 
| 114 | 
            +
                #
         | 
| 115 | 
            +
                # @param slug [String] identifier of this monitor
         | 
| 116 | 
            +
                # @param status [Symbol] status of this check-in, one of {CheckInEvent::VALID_STATUSES}
         | 
| 117 | 
            +
                # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
         | 
| 118 | 
            +
                # @param duration [Integer, nil] seconds elapsed since this monitor started
         | 
| 119 | 
            +
                # @param monitor_config [Cron::MonitorConfig, nil] configuration for this monitor
         | 
| 120 | 
            +
                # @param check_in_id [String, nil] for updating the status of an existing monitor
         | 
| 121 | 
            +
                #
         | 
| 122 | 
            +
                # @return [Event]
         | 
| 123 | 
            +
                def event_from_check_in(
         | 
| 124 | 
            +
                  slug,
         | 
| 125 | 
            +
                  status,
         | 
| 126 | 
            +
                  hint = {},
         | 
| 127 | 
            +
                  duration: nil,
         | 
| 128 | 
            +
                  monitor_config: nil,
         | 
| 129 | 
            +
                  check_in_id: nil
         | 
| 130 | 
            +
                )
         | 
| 131 | 
            +
                  return unless configuration.sending_allowed?
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  CheckInEvent.new(
         | 
| 134 | 
            +
                    configuration: configuration,
         | 
| 135 | 
            +
                    integration_meta: Sentry.integrations[hint[:integration]],
         | 
| 136 | 
            +
                    slug: slug,
         | 
| 137 | 
            +
                    status: status,
         | 
| 138 | 
            +
                    duration: duration,
         | 
| 139 | 
            +
                    monitor_config: monitor_config,
         | 
| 140 | 
            +
                    check_in_id: check_in_id
         | 
| 141 | 
            +
                  )
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 104 144 | 
             
                # Initializes an Event object with the given Transaction object.
         | 
| 105 145 | 
             
                # @param transaction [Transaction] the transaction to be recorded.
         | 
| 106 146 | 
             
                # @return [TransactionEvent]
         | 
| 107 147 | 
             
                def event_from_transaction(transaction)
         | 
| 108 | 
            -
                  TransactionEvent.new(configuration: configuration | 
| 109 | 
            -
                    event.transaction = transaction.name
         | 
| 110 | 
            -
                    event.contexts.merge!(trace: transaction.get_trace_context)
         | 
| 111 | 
            -
                    event.timestamp = transaction.timestamp
         | 
| 112 | 
            -
                    event.start_timestamp = transaction.start_timestamp
         | 
| 113 | 
            -
                    event.tags = transaction.tags
         | 
| 114 | 
            -
             | 
| 115 | 
            -
                    finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
         | 
| 116 | 
            -
                    event.spans = finished_spans.map(&:to_hash)
         | 
| 117 | 
            -
                  end
         | 
| 148 | 
            +
                  TransactionEvent.new(configuration: configuration, transaction: transaction)
         | 
| 118 149 | 
             
                end
         | 
| 119 150 |  | 
| 120 151 | 
             
                # @!macro send_event
         | 
| @@ -125,25 +156,34 @@ module Sentry | |
| 125 156 | 
             
                    event = configuration.before_send.call(event, hint)
         | 
| 126 157 |  | 
| 127 158 | 
             
                    if event.nil?
         | 
| 128 | 
            -
                       | 
| 159 | 
            +
                      log_debug("Discarded event because before_send returned nil")
         | 
| 129 160 | 
             
                      transport.record_lost_event(:before_send, 'event')
         | 
| 130 161 | 
             
                      return
         | 
| 131 162 | 
             
                    end
         | 
| 132 163 | 
             
                  end
         | 
| 133 164 |  | 
| 165 | 
            +
                  if event_type == TransactionEvent::TYPE && configuration.before_send_transaction
         | 
| 166 | 
            +
                    event = configuration.before_send_transaction.call(event, hint)
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                    if event.nil?
         | 
| 169 | 
            +
                      log_debug("Discarded event because before_send_transaction returned nil")
         | 
| 170 | 
            +
                      transport.record_lost_event(:before_send, 'transaction')
         | 
| 171 | 
            +
                      return
         | 
| 172 | 
            +
                    end
         | 
| 173 | 
            +
                  end
         | 
| 174 | 
            +
             | 
| 134 175 | 
             
                  transport.send_event(event)
         | 
| 176 | 
            +
                  spotlight_transport&.send_event(event)
         | 
| 135 177 |  | 
| 136 178 | 
             
                  event
         | 
| 137 179 | 
             
                rescue => e
         | 
| 138 | 
            -
                   | 
| 139 | 
            -
                  log_error("#{loggable_event_type} sending failed", e, debug: configuration.debug)
         | 
| 140 | 
            -
             | 
| 141 | 
            -
                  event_info = Event.get_log_message(event.to_hash)
         | 
| 142 | 
            -
                  log_info("Unreported #{loggable_event_type}: #{event_info}")
         | 
| 180 | 
            +
                  log_error("Event sending failed", e, debug: configuration.debug)
         | 
| 143 181 | 
             
                  transport.record_lost_event(:network_error, event_type)
         | 
| 144 182 | 
             
                  raise
         | 
| 145 183 | 
             
                end
         | 
| 146 184 |  | 
| 185 | 
            +
                # @deprecated use Sentry.get_traceparent instead.
         | 
| 186 | 
            +
                #
         | 
| 147 187 | 
             
                # Generates a Sentry trace for distribted tracing from the given Span.
         | 
| 148 188 | 
             
                # Returns `nil` if `config.propagate_traces` is `false`.
         | 
| 149 189 | 
             
                # @param span [Span] the span to generate trace from.
         | 
| @@ -156,6 +196,24 @@ module Sentry | |
| 156 196 | 
             
                  trace
         | 
| 157 197 | 
             
                end
         | 
| 158 198 |  | 
| 199 | 
            +
                # @deprecated Use Sentry.get_baggage instead.
         | 
| 200 | 
            +
                #
         | 
| 201 | 
            +
                # Generates a W3C Baggage header for distributed tracing from the given Span.
         | 
| 202 | 
            +
                # Returns `nil` if `config.propagate_traces` is `false`.
         | 
| 203 | 
            +
                # @param span [Span] the span to generate trace from.
         | 
| 204 | 
            +
                # @return [String, nil]
         | 
| 205 | 
            +
                def generate_baggage(span)
         | 
| 206 | 
            +
                  return unless configuration.propagate_traces
         | 
| 207 | 
            +
             | 
| 208 | 
            +
                  baggage = span.to_baggage
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                  if baggage && !baggage.empty?
         | 
| 211 | 
            +
                    log_debug("[Tracing] Adding #{BAGGAGE_HEADER_NAME} header to outgoing request: #{baggage}")
         | 
| 212 | 
            +
                  end
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                  baggage
         | 
| 215 | 
            +
                end
         | 
| 216 | 
            +
             | 
| 159 217 | 
             
                private
         | 
| 160 218 |  | 
| 161 219 | 
             
                def dispatch_background_event(event, hint)
         |