airbrake-ruby 5.1.0 → 6.0.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/lib/airbrake-ruby/async_sender.rb +3 -1
- data/lib/airbrake-ruby/config/processor.rb +2 -1
- data/lib/airbrake-ruby/config.rb +15 -6
- data/lib/airbrake-ruby/context.rb +51 -0
- data/lib/airbrake-ruby/file_cache.rb +1 -1
- data/lib/airbrake-ruby/filter_chain.rb +2 -0
- data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
- data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/git_repository_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/git_revision_filter.rb +1 -1
- data/lib/airbrake-ruby/filters/keys_filter.rb +2 -2
- data/lib/airbrake-ruby/filters/sql_filter.rb +2 -2
- data/lib/airbrake-ruby/filters/thread_filter.rb +2 -3
- data/lib/airbrake-ruby/grouppable.rb +1 -1
- data/lib/airbrake-ruby/ignorable.rb +0 -2
- data/lib/airbrake-ruby/mergeable.rb +1 -1
- data/lib/airbrake-ruby/monotonic_time.rb +1 -1
- data/lib/airbrake-ruby/notice_notifier.rb +3 -4
- data/lib/airbrake-ruby/performance_notifier.rb +1 -2
- data/lib/airbrake-ruby/remote_settings/callback.rb +1 -1
- data/lib/airbrake-ruby/remote_settings/settings_data.rb +2 -2
- data/lib/airbrake-ruby/remote_settings.rb +8 -7
- data/lib/airbrake-ruby/tdigest.rb +10 -9
- data/lib/airbrake-ruby/thread_pool.rb +5 -3
- data/lib/airbrake-ruby/timed_trace.rb +1 -3
- data/lib/airbrake-ruby/version.rb +2 -2
- data/lib/airbrake-ruby.rb +3 -2
- data/spec/airbrake_spec.rb +139 -76
- data/spec/async_sender_spec.rb +10 -8
- data/spec/backtrace_spec.rb +13 -10
- data/spec/benchmark_spec.rb +5 -3
- data/spec/code_hunk_spec.rb +24 -15
- data/spec/config/processor_spec.rb +20 -3
- data/spec/config/validator_spec.rb +5 -2
- data/spec/config_spec.rb +26 -17
- data/spec/context_spec.rb +54 -0
- data/spec/deploy_notifier_spec.rb +6 -4
- data/spec/file_cache_spec.rb +1 -0
- data/spec/filter_chain_spec.rb +29 -24
- data/spec/filters/context_filter_spec.rb +14 -5
- data/spec/filters/dependency_filter_spec.rb +3 -1
- data/spec/filters/exception_attributes_filter_spec.rb +5 -3
- data/spec/filters/gem_root_filter_spec.rb +5 -2
- data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
- data/spec/filters/git_repository_filter.rb +9 -9
- data/spec/filters/git_revision_filter_spec.rb +19 -19
- data/spec/filters/keys_allowlist_spec.rb +25 -16
- data/spec/filters/keys_blocklist_spec.rb +25 -18
- data/spec/filters/root_directory_filter_spec.rb +3 -3
- data/spec/filters/sql_filter_spec.rb +26 -26
- data/spec/filters/system_exit_filter_spec.rb +4 -2
- data/spec/filters/thread_filter_spec.rb +16 -14
- data/spec/loggable_spec.rb +2 -2
- data/spec/monotonic_time_spec.rb +8 -6
- data/spec/nested_exception_spec.rb +46 -46
- data/spec/notice_notifier/options_spec.rb +23 -13
- data/spec/notice_notifier_spec.rb +52 -47
- data/spec/notice_spec.rb +6 -2
- data/spec/performance_notifier_spec.rb +67 -60
- data/spec/promise_spec.rb +38 -32
- data/spec/remote_settings/callback_spec.rb +27 -8
- data/spec/remote_settings/settings_data_spec.rb +4 -4
- data/spec/remote_settings_spec.rb +40 -7
- data/spec/response_spec.rb +34 -12
- data/spec/stashable_spec.rb +5 -5
- data/spec/stat_spec.rb +7 -5
- data/spec/sync_sender_spec.rb +49 -16
- data/spec/tdigest_spec.rb +61 -56
- data/spec/thread_pool_spec.rb +65 -55
- data/spec/time_truncate_spec.rb +4 -2
- data/spec/timed_trace_spec.rb +32 -30
- data/spec/truncator_spec.rb +72 -43
- metadata +52 -49
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: f8371a959c69ffddca0dd25b6e8096450ecea66e13ddd6f6ace583eb37976516
         | 
| 4 | 
            +
              data.tar.gz: f769f0604e3dd7118df53cb6de2e3115beed43a898e9eefb5828174c29f16f67
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: ef094ddf119abfe8fd552980dbbc05ce907ed7608c12f7012fbcde1ee7861a33da67a435c8ef6fc378ef2490274050b7ccde598ac2a1f0f1098cd587c36b1222
         | 
| 7 | 
            +
              data.tar.gz: 737a3900b60024d24303d10277d89ab782f60c58cadeb8e7fef3b7da17e983c8dd0033724e3640fe07d3428f1f86952f65ef378f81547213c2a8b11a9271eaa7
         | 
| @@ -7,9 +7,10 @@ module Airbrake | |
| 7 7 | 
             
              class AsyncSender
         | 
| 8 8 | 
             
                include Loggable
         | 
| 9 9 |  | 
| 10 | 
            -
                def initialize(method = :post)
         | 
| 10 | 
            +
                def initialize(method = :post, name = 'async-sender')
         | 
| 11 11 | 
             
                  @config = Airbrake::Config.instance
         | 
| 12 12 | 
             
                  @method = method
         | 
| 13 | 
            +
                  @name = name
         | 
| 13 14 | 
             
                end
         | 
| 14 15 |  | 
| 15 16 | 
             
                # Asynchronously sends a notice to Airbrake.
         | 
| @@ -47,6 +48,7 @@ module Airbrake | |
| 47 48 | 
             
                  @thread_pool ||= begin
         | 
| 48 49 | 
             
                    sender = SyncSender.new(@method)
         | 
| 49 50 | 
             
                    ThreadPool.new(
         | 
| 51 | 
            +
                      name: @name,
         | 
| 50 52 | 
             
                      worker_size: @config.workers,
         | 
| 51 53 | 
             
                      queue_size: @config.queue_size,
         | 
| 52 54 | 
             
                      block: proc { |args| sender.send(*args) },
         | 
| @@ -3,7 +3,7 @@ module Airbrake | |
| 3 3 | 
             
                # Processor is a helper class, which is responsible for setting default
         | 
| 4 4 | 
             
                # config values, default notifier filters and remote configuration changes.
         | 
| 5 5 | 
             
                #
         | 
| 6 | 
            -
                # @since  | 
| 6 | 
            +
                # @since v5.0.0
         | 
| 7 7 | 
             
                # @api private
         | 
| 8 8 | 
             
                class Processor
         | 
| 9 9 | 
             
                  # @param [Airbrake::Config] config
         | 
| @@ -41,6 +41,7 @@ module Airbrake | |
| 41 41 |  | 
| 42 42 | 
             
                  # @return [Airbrake::RemoteSettings]
         | 
| 43 43 | 
             
                  def process_remote_configuration
         | 
| 44 | 
            +
                    return unless @config.remote_config
         | 
| 44 45 | 
             
                    return unless @project_id
         | 
| 45 46 | 
             
                    return if @config.environment == 'test'
         | 
| 46 47 |  | 
    
        data/lib/airbrake-ruby/config.rb
    CHANGED
    
    | @@ -121,13 +121,21 @@ module Airbrake | |
| 121 121 | 
             
                # @return [Boolean] true if the library should send error reports to
         | 
| 122 122 | 
             
                #   Airbrake, false otherwise
         | 
| 123 123 | 
             
                # @api public
         | 
| 124 | 
            -
                # @since  | 
| 124 | 
            +
                # @since v5.0.0
         | 
| 125 125 | 
             
                attr_accessor :error_notifications
         | 
| 126 126 |  | 
| 127 | 
            -
                # @return [String] the host  | 
| 128 | 
            -
                #   configuration options | 
| 127 | 
            +
                # @return [String] the host which should be used for fetching remote
         | 
| 128 | 
            +
                #   configuration options
         | 
| 129 | 
            +
                # @api public
         | 
| 130 | 
            +
                # @since v5.0.0
         | 
| 129 131 | 
             
                attr_accessor :remote_config_host
         | 
| 130 132 |  | 
| 133 | 
            +
                # @return [String] true if notifier should periodically fetch remote
         | 
| 134 | 
            +
                #   configuration, false otherwise
         | 
| 135 | 
            +
                # @api public
         | 
| 136 | 
            +
                # @since v5.2.0
         | 
| 137 | 
            +
                attr_accessor :remote_config
         | 
| 138 | 
            +
             | 
| 131 139 | 
             
                class << self
         | 
| 132 140 | 
             
                  # @return [Config]
         | 
| 133 141 | 
             
                  attr_writer :instance
         | 
| @@ -140,7 +148,7 @@ module Airbrake | |
| 140 148 |  | 
| 141 149 | 
             
                # @param [Hash{Symbol=>Object}] user_config the hash to be used to build the
         | 
| 142 150 | 
             
                #   config
         | 
| 143 | 
            -
                # rubocop:disable Metrics/AbcSize
         | 
| 151 | 
            +
                # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
         | 
| 144 152 | 
             
                def initialize(user_config = {})
         | 
| 145 153 | 
             
                  self.proxy = {}
         | 
| 146 154 | 
             
                  self.queue_size = 100
         | 
| @@ -151,7 +159,7 @@ module Airbrake | |
| 151 159 | 
             
                  self.project_key = user_config[:project_key]
         | 
| 152 160 | 
             
                  self.error_host = 'https://api.airbrake.io'
         | 
| 153 161 | 
             
                  self.apm_host = 'https://api.airbrake.io'
         | 
| 154 | 
            -
                  self.remote_config_host = 'https:// | 
| 162 | 
            +
                  self.remote_config_host = 'https://notifier-configs.airbrake.io'
         | 
| 155 163 |  | 
| 156 164 | 
             
                  self.ignore_environments = []
         | 
| 157 165 |  | 
| @@ -171,10 +179,11 @@ module Airbrake | |
| 171 179 | 
             
                  self.query_stats = true
         | 
| 172 180 | 
             
                  self.job_stats = true
         | 
| 173 181 | 
             
                  self.error_notifications = true
         | 
| 182 | 
            +
                  self.remote_config = true
         | 
| 174 183 |  | 
| 175 184 | 
             
                  merge(user_config)
         | 
| 176 185 | 
             
                end
         | 
| 177 | 
            -
                # rubocop:enable Metrics/AbcSize
         | 
| 186 | 
            +
                # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
         | 
| 178 187 |  | 
| 179 188 | 
             
                # The full URL to the Airbrake Notice API. Based on the +:error_host+ option.
         | 
| 180 189 | 
             
                # @return [URI] the endpoint address
         | 
| @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            module Airbrake
         | 
| 2 | 
            +
              # Represents a thread-safe Airbrake context object, which carries arbitrary
         | 
| 3 | 
            +
              # information added via {Airbrake.merge_context} calls.
         | 
| 4 | 
            +
              #
         | 
| 5 | 
            +
              # @example
         | 
| 6 | 
            +
              #   Airbrake::Context.current.merge!(foo: 'bar')
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              # @api private
         | 
| 9 | 
            +
              # @since v5.2.1
         | 
| 10 | 
            +
              class Context
         | 
| 11 | 
            +
                # Returns current, thread-local, context.
         | 
| 12 | 
            +
                # @return [self]
         | 
| 13 | 
            +
                def self.current
         | 
| 14 | 
            +
                  Thread.current[:airbrake_context] ||= new
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def initialize
         | 
| 18 | 
            +
                  @mutex = Mutex.new
         | 
| 19 | 
            +
                  @context = {}
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                # Merges the given context with the current one.
         | 
| 23 | 
            +
                #
         | 
| 24 | 
            +
                # @param [Hash{Object=>Object}] other
         | 
| 25 | 
            +
                # @return [void]
         | 
| 26 | 
            +
                def merge!(other)
         | 
| 27 | 
            +
                  @mutex.synchronize do
         | 
| 28 | 
            +
                    @context.merge!(other)
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                # @return [Hash] duplicated Hash context
         | 
| 33 | 
            +
                def to_h
         | 
| 34 | 
            +
                  @mutex.synchronize do
         | 
| 35 | 
            +
                    @context.dup
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                # @return [Hash] clears (resets) the current context
         | 
| 40 | 
            +
                def clear
         | 
| 41 | 
            +
                  @mutex.synchronize do
         | 
| 42 | 
            +
                    @context.clear
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                # @return [Boolean] checks whether the context has any data
         | 
| 47 | 
            +
                def empty?
         | 
| 48 | 
            +
                  @context.empty?
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
            end
         | 
| @@ -57,7 +57,9 @@ module Airbrake | |
| 57 57 | 
             
                # @return [void]
         | 
| 58 58 | 
             
                # @since v3.1.0
         | 
| 59 59 | 
             
                def delete_filter(filter_class)
         | 
| 60 | 
            +
                  # rubocop:disable Style/ClassEqualityComparison
         | 
| 60 61 | 
             
                  index = @filters.index { |f| f.class.name == filter_class.name }
         | 
| 62 | 
            +
                  # rubocop:enable Style/ClassEqualityComparison
         | 
| 61 63 | 
             
                  @filters.delete_at(index) if index
         | 
| 62 64 | 
             
                end
         | 
| 63 65 |  | 
| @@ -9,8 +9,7 @@ module Airbrake | |
| 9 9 | 
             
                  # @return [Integer]
         | 
| 10 10 | 
             
                  attr_reader :weight
         | 
| 11 11 |  | 
| 12 | 
            -
                  def initialize | 
| 13 | 
            -
                    @context = context
         | 
| 12 | 
            +
                  def initialize
         | 
| 14 13 | 
             
                    @weight = 119
         | 
| 15 14 | 
             
                    @mutex = Mutex.new
         | 
| 16 15 | 
             
                  end
         | 
| @@ -18,10 +17,10 @@ module Airbrake | |
| 18 17 | 
             
                  # @macro call_filter
         | 
| 19 18 | 
             
                  def call(notice)
         | 
| 20 19 | 
             
                    @mutex.synchronize do
         | 
| 21 | 
            -
                      return if  | 
| 20 | 
            +
                      return if Airbrake::Context.current.empty?
         | 
| 22 21 |  | 
| 23 | 
            -
                      notice[:params][:airbrake_context] =  | 
| 24 | 
            -
                       | 
| 22 | 
            +
                      notice[:params][:airbrake_context] = Airbrake::Context.current.to_h
         | 
| 23 | 
            +
                      Airbrake::Context.current.clear
         | 
| 25 24 | 
             
                    end
         | 
| 26 25 | 
             
                  end
         | 
| 27 26 | 
             
                end
         | 
| @@ -50,7 +50,7 @@ module Airbrake | |
| 50 50 | 
             
                  def last_checkout
         | 
| 51 51 | 
             
                    return unless (line = last_checkout_line)
         | 
| 52 52 |  | 
| 53 | 
            -
                    parts = line.chomp.split("\t").first.split | 
| 53 | 
            +
                    parts = line.chomp.split("\t").first.split
         | 
| 54 54 | 
             
                    if parts.size < MIN_HEAD_COLS
         | 
| 55 55 | 
             
                      logger.error(
         | 
| 56 56 | 
             
                        "#{LOG_LABEL} Airbrake::#{self.class.name}: can't parse line: #{line}",
         | 
| @@ -36,7 +36,7 @@ module Airbrake | |
| 36 36 | 
             
                        `cd #{@git_path} && git config --get remote.origin.url`.chomp
         | 
| 37 37 | 
             
                      else
         | 
| 38 38 | 
             
                        "`git remote get-url` is unsupported in git #{@git_version}. " \
         | 
| 39 | 
            -
             | 
| 39 | 
            +
                          'Consider an upgrade to 2.7+'
         | 
| 40 40 | 
             
                      end
         | 
| 41 41 |  | 
| 42 42 | 
             
                    return unless @repository
         | 
| @@ -82,7 +82,7 @@ module Airbrake | |
| 82 82 |  | 
| 83 83 | 
             
                  private
         | 
| 84 84 |  | 
| 85 | 
            -
                  def filter_hash(hash)
         | 
| 85 | 
            +
                  def filter_hash(hash) # rubocop:disable Metrics/AbcSize
         | 
| 86 86 | 
             
                    return hash unless hash.is_a?(Hash)
         | 
| 87 87 |  | 
| 88 88 | 
             
                    hash_copy = hash.dup
         | 
| @@ -103,7 +103,7 @@ module Airbrake | |
| 103 103 | 
             
                  end
         | 
| 104 104 |  | 
| 105 105 | 
             
                  def filter_url_params(url)
         | 
| 106 | 
            -
                    url.query =  | 
| 106 | 
            +
                    url.query = URI.decode_www_form(url.query).to_h.map do |key, val|
         | 
| 107 107 | 
             
                      should_filter?(key) ? "#{key}=[Filtered]" : "#{key}=#{val}"
         | 
| 108 108 | 
             
                    end.join('&')
         | 
| 109 109 |  | 
| @@ -27,13 +27,13 @@ module Airbrake | |
| 27 27 | 
             
                    single_quotes: /'(?:[^']|'')*?(?:\\'.*|'(?!'))/,
         | 
| 28 28 | 
             
                    double_quotes: /"(?:[^"]|"")*?(?:\\".*|"(?!"))/,
         | 
| 29 29 | 
             
                    dollar_quotes: /(\$(?!\d)[^$]*?\$).*?(?:\1|$)/,
         | 
| 30 | 
            -
                    uuids: /\{?(?:[0-9a-fA-F] | 
| 30 | 
            +
                    uuids: /\{?(?:[0-9a-fA-F]-*){32}\}?/,
         | 
| 31 31 | 
             
                    numeric_literals: /\b-?(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/,
         | 
| 32 32 | 
             
                    boolean_literals: /\b(?:true|false|null)\b/i,
         | 
| 33 33 | 
             
                    hexadecimal_literals: /0x[0-9a-fA-F]+/,
         | 
| 34 34 | 
             
                    comments: /(?:#|--).*?(?=\r|\n|$)/i,
         | 
| 35 35 | 
             
                    multi_line_comments: %r{/\*(?:[^/]|/[^*])*?(?:\*/|/\*.*)},
         | 
| 36 | 
            -
                    oracle_quoted_strings: /q'\[.*?(?:\]'|$)|q'\{.*?(?:\}'|$)|q' | 
| 36 | 
            +
                    oracle_quoted_strings: /q'\[.*?(?:\]'|$)|q'\{.*?(?:\}'|$)|q'<.*?(?:>'|$)|q'\(.*?(?:\)'|$)/,
         | 
| 37 37 | 
             
                    # rubocop:enable Layout/LineLength
         | 
| 38 38 | 
             
                  }.freeze
         | 
| 39 39 |  | 
| @@ -41,8 +41,7 @@ module Airbrake | |
| 41 41 | 
             
                      thread_info[:fiber_variables] = vars
         | 
| 42 42 | 
             
                    end
         | 
| 43 43 |  | 
| 44 | 
            -
                     | 
| 45 | 
            -
                    if th.respond_to?(:name) && (name = th.name)
         | 
| 44 | 
            +
                    if (name = th.name)
         | 
| 46 45 | 
             
                      thread_info[:name] = name
         | 
| 47 46 | 
             
                    end
         | 
| 48 47 |  | 
| @@ -84,7 +83,7 @@ module Airbrake | |
| 84 83 | 
             
                    when Array
         | 
| 85 84 | 
             
                      value = value.map { |elem| sanitize_value(elem) }
         | 
| 86 85 | 
             
                    when Hash
         | 
| 87 | 
            -
                       | 
| 86 | 
            +
                      value.transform_values { |v| sanitize_value(v) }
         | 
| 88 87 | 
             
                    else
         | 
| 89 88 | 
             
                      value.to_s
         | 
| 90 89 | 
             
                    end
         | 
| @@ -18,11 +18,9 @@ module Airbrake | |
| 18 18 | 
             
                # Checks whether the instance was ignored.
         | 
| 19 19 | 
             
                # @return [Boolean]
         | 
| 20 20 | 
             
                # @see #ignore!
         | 
| 21 | 
            -
                # rubocop:disable Style/DoubleNegation
         | 
| 22 21 | 
             
                def ignored?
         | 
| 23 22 | 
             
                  !!ignored
         | 
| 24 23 | 
             
                end
         | 
| 25 | 
            -
                # rubocop:enable Style/DoubleNegation
         | 
| 26 24 |  | 
| 27 25 | 
             
                # Ignores an instance. Ignored instances must never reach the Airbrake
         | 
| 28 26 | 
             
                # dashboard.
         | 
| @@ -20,14 +20,13 @@ module Airbrake | |
| 20 20 |  | 
| 21 21 | 
             
                def initialize
         | 
| 22 22 | 
             
                  @config = Airbrake::Config.instance
         | 
| 23 | 
            -
                  @context = {}
         | 
| 24 23 | 
             
                  @filter_chain = FilterChain.new
         | 
| 25 | 
            -
                  @async_sender = AsyncSender.new
         | 
| 24 | 
            +
                  @async_sender = AsyncSender.new(:post, self.class.name)
         | 
| 26 25 | 
             
                  @sync_sender = SyncSender.new
         | 
| 27 26 |  | 
| 28 27 | 
             
                  DEFAULT_FILTERS.each { |filter| add_filter(filter.new) }
         | 
| 29 28 |  | 
| 30 | 
            -
                  add_filter(Airbrake::Filters::ContextFilter.new | 
| 29 | 
            +
                  add_filter(Airbrake::Filters::ContextFilter.new)
         | 
| 31 30 | 
             
                  add_filter(Airbrake::Filters::ExceptionAttributesFilter.new)
         | 
| 32 31 | 
             
                end
         | 
| 33 32 |  | 
| @@ -79,7 +78,7 @@ module Airbrake | |
| 79 78 |  | 
| 80 79 | 
             
                # @see Airbrake.merge_context
         | 
| 81 80 | 
             
                def merge_context(context)
         | 
| 82 | 
            -
                   | 
| 81 | 
            +
                  Airbrake::Context.current.merge!(context)
         | 
| 83 82 | 
             
                end
         | 
| 84 83 |  | 
| 85 84 | 
             
                # @return [Boolean]
         | 
| @@ -12,7 +12,7 @@ module Airbrake | |
| 12 12 | 
             
                def initialize
         | 
| 13 13 | 
             
                  @config = Airbrake::Config.instance
         | 
| 14 14 | 
             
                  @flush_period = Airbrake::Config.instance.performance_stats_flush_period
         | 
| 15 | 
            -
                  @async_sender = AsyncSender.new(:put)
         | 
| 15 | 
            +
                  @async_sender = AsyncSender.new(:put, self.class.name)
         | 
| 16 16 | 
             
                  @sync_sender = SyncSender.new(:put)
         | 
| 17 17 | 
             
                  @schedule_flush = nil
         | 
| 18 18 | 
             
                  @filter_chain = FilterChain.new
         | 
| @@ -51,7 +51,6 @@ module Airbrake | |
| 51 51 | 
             
                  @payload.synchronize do
         | 
| 52 52 | 
             
                    @schedule_flush.kill if @schedule_flush
         | 
| 53 53 | 
             
                    @async_sender.close
         | 
| 54 | 
            -
                    logger.debug("#{LOG_LABEL} performance notifier closed")
         | 
| 55 54 | 
             
                  end
         | 
| 56 55 | 
             
                end
         | 
| 57 56 |  | 
| @@ -11,7 +11,7 @@ module Airbrake | |
| 11 11 | 
             
                #
         | 
| 12 12 | 
             
                #   settings_data.interval #=> 600
         | 
| 13 13 | 
             
                #
         | 
| 14 | 
            -
                # @since  | 
| 14 | 
            +
                # @since v5.0.0
         | 
| 15 15 | 
             
                # @api private
         | 
| 16 16 | 
             
                class SettingsData
         | 
| 17 17 | 
             
                  # @return [Integer] how frequently we should poll the config API
         | 
| @@ -59,7 +59,7 @@ module Airbrake | |
| 59 59 | 
             
                  # @return [String] where the config is stored on S3.
         | 
| 60 60 | 
             
                  def config_route(remote_config_host)
         | 
| 61 61 | 
             
                    if @data['config_route'] && !@data['config_route'].empty?
         | 
| 62 | 
            -
                      return remote_config_host.chomp('/') | 
| 62 | 
            +
                      return "#{remote_config_host.chomp('/')}/#{@data['config_route']}"
         | 
| 63 63 | 
             
                    end
         | 
| 64 64 |  | 
| 65 65 | 
             
                    format(
         | 
| @@ -8,7 +8,7 @@ module Airbrake | |
| 8 8 | 
             
              #     config.error_notifications = data.error_notifications?
         | 
| 9 9 | 
             
              #   end
         | 
| 10 10 | 
             
              #
         | 
| 11 | 
            -
              # @since  | 
| 11 | 
            +
              # @since v5.0.0
         | 
| 12 12 | 
             
              # @api private
         | 
| 13 13 | 
             
              class RemoteSettings
         | 
| 14 14 | 
             
                include Airbrake::Loggable
         | 
| @@ -22,6 +22,9 @@ module Airbrake | |
| 22 22 | 
             
                  language: "#{RUBY_ENGINE}/#{RUBY_VERSION}".freeze,
         | 
| 23 23 | 
             
                ).freeze
         | 
| 24 24 |  | 
| 25 | 
            +
                # @return [String]
         | 
| 26 | 
            +
                HTTP_OK = '200'.freeze
         | 
| 27 | 
            +
             | 
| 25 28 | 
             
                # Polls remote config of the given project.
         | 
| 26 29 | 
             
                #
         | 
| 27 30 | 
             
                # @param [Integer] project_id
         | 
| @@ -71,22 +74,20 @@ module Airbrake | |
| 71 74 | 
             
                def fetch_config
         | 
| 72 75 | 
             
                  response = nil
         | 
| 73 76 | 
             
                  begin
         | 
| 74 | 
            -
                    response = Net::HTTP. | 
| 77 | 
            +
                    response = Net::HTTP.get_response(build_config_uri)
         | 
| 75 78 | 
             
                  rescue StandardError => ex
         | 
| 76 79 | 
             
                    logger.error(ex)
         | 
| 77 80 | 
             
                    return {}
         | 
| 78 81 | 
             
                  end
         | 
| 79 82 |  | 
| 80 | 
            -
                   | 
| 81 | 
            -
             | 
| 82 | 
            -
                  if response.start_with?('<?xml ')
         | 
| 83 | 
            -
                    logger.error(response)
         | 
| 83 | 
            +
                  unless response.code == HTTP_OK
         | 
| 84 | 
            +
                    logger.error(response.body)
         | 
| 84 85 | 
             
                    return {}
         | 
| 85 86 | 
             
                  end
         | 
| 86 87 |  | 
| 87 88 | 
             
                  json = nil
         | 
| 88 89 | 
             
                  begin
         | 
| 89 | 
            -
                    json = JSON.parse(response)
         | 
| 90 | 
            +
                    json = JSON.parse(response.body)
         | 
| 90 91 | 
             
                  rescue JSON::ParserError => ex
         | 
| 91 92 | 
             
                    logger.error(ex)
         | 
| 92 93 | 
             
                    return {}
         | 
| @@ -24,6 +24,7 @@ module Airbrake | |
| 24 24 | 
             
                # @since v3.2.0
         | 
| 25 25 | 
             
                class Centroid
         | 
| 26 26 | 
             
                  attr_accessor :mean, :n, :cumn, :mean_cumn
         | 
| 27 | 
            +
             | 
| 27 28 | 
             
                  def initialize(mean, n, cumn, mean_cumn = nil)
         | 
| 28 29 | 
             
                    @mean      = mean
         | 
| 29 30 | 
             
                    @n         = n
         | 
| @@ -130,7 +131,7 @@ module Airbrake | |
| 130 131 | 
             
                  points = to_a
         | 
| 131 132 | 
             
                  reset!
         | 
| 132 133 | 
             
                  push_centroid(points.shuffle)
         | 
| 133 | 
            -
                  _cumulate(true, true)
         | 
| 134 | 
            +
                  _cumulate(exact: true, force: true)
         | 
| 134 135 | 
             
                  nil
         | 
| 135 136 | 
             
                end
         | 
| 136 137 |  | 
| @@ -175,7 +176,7 @@ module Airbrake | |
| 175 176 | 
             
                    elsif item > max[1].mean
         | 
| 176 177 | 
             
                      1.0
         | 
| 177 178 | 
             
                    else
         | 
| 178 | 
            -
                      _cumulate(true)
         | 
| 179 | 
            +
                      _cumulate(exact: true)
         | 
| 179 180 | 
             
                      bound = bound_mean(item)
         | 
| 180 181 | 
             
                      lower, upper = bound
         | 
| 181 182 | 
             
                      mean_cumn = lower.mean_cumn
         | 
| @@ -204,7 +205,7 @@ module Airbrake | |
| 204 205 | 
             
                    if size == 0
         | 
| 205 206 | 
             
                      nil
         | 
| 206 207 | 
             
                    else
         | 
| 207 | 
            -
                      _cumulate(true)
         | 
| 208 | 
            +
                      _cumulate(exact: true)
         | 
| 208 209 | 
             
                      h = @size * item
         | 
| 209 210 | 
             
                      lower, upper = bound_mean_cumn(h)
         | 
| 210 211 | 
             
                      if lower.nil? && upper.nil?
         | 
| @@ -255,7 +256,7 @@ module Airbrake | |
| 255 256 | 
             
                    array = bytes[start_idx..-1].unpack("G#{size}N#{size}")
         | 
| 256 257 | 
             
                    means, counts = array.each_slice(size).to_a if array.any?
         | 
| 257 258 | 
             
                  when SMALL_ENCODING
         | 
| 258 | 
            -
                    means = bytes[start_idx..(start_idx + 4 * size)].unpack("g#{size}")
         | 
| 259 | 
            +
                    means = bytes[start_idx..(start_idx + (4 * size))].unpack("g#{size}")
         | 
| 259 260 | 
             
                    # Decode delta encoding of means
         | 
| 260 261 | 
             
                    x = 0
         | 
| 261 262 | 
             
                    means.map! do |m|
         | 
| @@ -263,7 +264,7 @@ module Airbrake | |
| 263 264 | 
             
                      x = m
         | 
| 264 265 | 
             
                      m
         | 
| 265 266 | 
             
                    end
         | 
| 266 | 
            -
                    counts_bytes = bytes[(start_idx + 4 * size)..-1].unpack('C*')
         | 
| 267 | 
            +
                    counts_bytes = bytes[(start_idx + (4 * size))..-1].unpack('C*')
         | 
| 267 268 | 
             
                    counts = []
         | 
| 268 269 | 
             
                    # Decode variable length integer bytes
         | 
| 269 270 | 
             
                    size.times do
         | 
| @@ -306,7 +307,7 @@ module Airbrake | |
| 306 307 | 
             
                    centroid.mean += n * (x - centroid.mean) / (centroid.n + n)
         | 
| 307 308 | 
             
                  end
         | 
| 308 309 |  | 
| 309 | 
            -
                  _cumulate(false, true) if centroid.mean_cumn.nil?
         | 
| 310 | 
            +
                  _cumulate(exact: false, force: true) if centroid.mean_cumn.nil?
         | 
| 310 311 |  | 
| 311 312 | 
             
                  centroid.cumn += n
         | 
| 312 313 | 
             
                  centroid.mean_cumn += n / 2.0
         | 
| @@ -314,7 +315,7 @@ module Airbrake | |
| 314 315 | 
             
                end
         | 
| 315 316 |  | 
| 316 317 | 
             
                # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
         | 
| 317 | 
            -
                def _cumulate(exact  | 
| 318 | 
            +
                def _cumulate(exact: false, force: false)
         | 
| 318 319 | 
             
                  unless force
         | 
| 319 320 | 
             
                    factor = if @last_cumulate == 0
         | 
| 320 321 | 
             
                               Float::INFINITY
         | 
| @@ -326,7 +327,7 @@ module Airbrake | |
| 326 327 |  | 
| 327 328 | 
             
                  cumn = 0
         | 
| 328 329 | 
             
                  @centroids.each_value do |c|
         | 
| 329 | 
            -
                    c.mean_cumn = cumn + c.n / 2.0
         | 
| 330 | 
            +
                    c.mean_cumn = cumn + (c.n / 2.0)
         | 
| 330 331 | 
             
                    cumn = c.cumn = cumn + c.n
         | 
| 331 332 | 
             
                  end
         | 
| 332 333 | 
             
                  @size = @last_cumulate = cumn
         | 
| @@ -361,7 +362,7 @@ module Airbrake | |
| 361 362 | 
             
                    end
         | 
| 362 363 | 
             
                  end
         | 
| 363 364 |  | 
| 364 | 
            -
                  _cumulate(false)
         | 
| 365 | 
            +
                  _cumulate(exact: false)
         | 
| 365 366 |  | 
| 366 367 | 
             
                  # If the number of centroids has grown to a very large size,
         | 
| 367 368 | 
             
                  # it may be due to values being inserted in sorted order.
         | 
| @@ -6,6 +6,7 @@ module Airbrake | |
| 6 6 | 
             
              #   # Initialize a new thread pool with 5 workers and a queue size of 100. Set
         | 
| 7 7 | 
             
              #   # the block to be run concurrently.
         | 
| 8 8 | 
             
              #   thread_pool = ThreadPool.new(
         | 
| 9 | 
            +
              #     name: 'performance-notifier',
         | 
| 9 10 | 
             
              #     worker_size: 5,
         | 
| 10 11 | 
             
              #     queue_size: 100,
         | 
| 11 12 | 
             
              #     block: proc { |message| print "ECHO: #{message}..."}
         | 
| @@ -24,7 +25,8 @@ module Airbrake | |
| 24 25 | 
             
                # @note This is exposed for eaiser unit testing
         | 
| 25 26 | 
             
                attr_reader :workers
         | 
| 26 27 |  | 
| 27 | 
            -
                def initialize(worker_size:, queue_size:, block:)
         | 
| 28 | 
            +
                def initialize(worker_size:, queue_size:, block:, name: nil)
         | 
| 29 | 
            +
                  @name = name
         | 
| 28 30 | 
             
                  @worker_size = worker_size
         | 
| 29 31 | 
             
                  @queue_size = queue_size
         | 
| 30 32 | 
             
                  @block = block
         | 
| @@ -102,7 +104,7 @@ module Airbrake | |
| 102 104 |  | 
| 103 105 | 
             
                    unless @queue.empty?
         | 
| 104 106 | 
             
                      msg = "#{LOG_LABEL} waiting to process #{@queue.size} task(s)..."
         | 
| 105 | 
            -
                      logger.debug(msg  | 
| 107 | 
            +
                      logger.debug("#{msg} (Ctrl-C to abort)")
         | 
| 106 108 | 
             
                    end
         | 
| 107 109 |  | 
| 108 110 | 
             
                    @worker_size.times { @queue << :stop }
         | 
| @@ -111,7 +113,7 @@ module Airbrake | |
| 111 113 | 
             
                  end
         | 
| 112 114 |  | 
| 113 115 | 
             
                  threads.each(&:join)
         | 
| 114 | 
            -
                  logger.debug("#{LOG_LABEL} thread pool closed")
         | 
| 116 | 
            +
                  logger.debug("#{LOG_LABEL} #{@name} thread pool closed")
         | 
| 115 117 | 
             
                end
         | 
| 116 118 |  | 
| 117 119 | 
             
                def closed?
         | 
| @@ -3,10 +3,10 @@ | |
| 3 3 | 
             
            module Airbrake
         | 
| 4 4 | 
             
              # @return [String] the library version
         | 
| 5 5 | 
             
              # @api public
         | 
| 6 | 
            -
              AIRBRAKE_RUBY_VERSION = ' | 
| 6 | 
            +
              AIRBRAKE_RUBY_VERSION = '6.0.0'.freeze
         | 
| 7 7 |  | 
| 8 8 | 
             
              # @return [Hash{Symbol=>String}] the information about the notifier library
         | 
| 9 | 
            -
              # @since  | 
| 9 | 
            +
              # @since v5.0.0
         | 
| 10 10 | 
             
              # @api public
         | 
| 11 11 | 
             
              NOTIFIER_INFO = {
         | 
| 12 12 | 
             
                name: 'airbrake-ruby'.freeze,
         | 
    
        data/lib/airbrake-ruby.rb
    CHANGED
    
    | @@ -58,6 +58,7 @@ require 'airbrake-ruby/benchmark' | |
| 58 58 | 
             
            require 'airbrake-ruby/monotonic_time'
         | 
| 59 59 | 
             
            require 'airbrake-ruby/timed_trace'
         | 
| 60 60 | 
             
            require 'airbrake-ruby/queue'
         | 
| 61 | 
            +
            require 'airbrake-ruby/context'
         | 
| 61 62 |  | 
| 62 63 | 
             
            # Airbrake is a thin wrapper around instances of the notifier classes (such as
         | 
| 63 64 | 
             
            # notice, performance & deploy notifiers). It creates a way to access them via a
         | 
| @@ -273,7 +274,7 @@ module Airbrake | |
| 273 274 | 
             
                #   Airbrake.notify('App crashed!') #=> raises Airbrake::Error
         | 
| 274 275 | 
             
                #
         | 
| 275 276 | 
             
                # @return [nil]
         | 
| 276 | 
            -
                # rubocop:disable Style/IfUnlessModifier | 
| 277 | 
            +
                # rubocop:disable Style/IfUnlessModifier
         | 
| 277 278 | 
             
                def close
         | 
| 278 279 | 
             
                  if defined?(@notice_notifier) && @notice_notifier
         | 
| 279 280 | 
             
                    @notice_notifier.close
         | 
| @@ -289,7 +290,7 @@ module Airbrake | |
| 289 290 |  | 
| 290 291 | 
             
                  nil
         | 
| 291 292 | 
             
                end
         | 
| 292 | 
            -
                # rubocop:enable Style/IfUnlessModifier | 
| 293 | 
            +
                # rubocop:enable Style/IfUnlessModifier
         | 
| 293 294 |  | 
| 294 295 | 
             
                # Pings the Airbrake Deploy API endpoint about the occurred deploy.
         | 
| 295 296 | 
             
                #
         |