airbrake-ruby 4.15.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby/async_sender.rb +4 -2
  3. data/lib/airbrake-ruby/backtrace.rb +6 -5
  4. data/lib/airbrake-ruby/config/processor.rb +77 -0
  5. data/lib/airbrake-ruby/config/validator.rb +6 -0
  6. data/lib/airbrake-ruby/config.rb +44 -35
  7. data/lib/airbrake-ruby/context.rb +51 -0
  8. data/lib/airbrake-ruby/file_cache.rb +1 -1
  9. data/lib/airbrake-ruby/filter_chain.rb +3 -0
  10. data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
  11. data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
  12. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
  13. data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
  14. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +3 -4
  15. data/lib/airbrake-ruby/filters/git_repository_filter.rb +11 -2
  16. data/lib/airbrake-ruby/filters/git_revision_filter.rb +3 -1
  17. data/lib/airbrake-ruby/filters/keys_filter.rb +23 -15
  18. data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
  19. data/lib/airbrake-ruby/filters/sql_filter.rb +11 -11
  20. data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
  21. data/lib/airbrake-ruby/filters/thread_filter.rb +4 -3
  22. data/lib/airbrake-ruby/grouppable.rb +1 -1
  23. data/lib/airbrake-ruby/ignorable.rb +1 -2
  24. data/lib/airbrake-ruby/mergeable.rb +1 -1
  25. data/lib/airbrake-ruby/monotonic_time.rb +1 -1
  26. data/lib/airbrake-ruby/notice.rb +1 -8
  27. data/lib/airbrake-ruby/notice_notifier.rb +4 -4
  28. data/lib/airbrake-ruby/performance_breakdown.rb +1 -6
  29. data/lib/airbrake-ruby/performance_notifier.rb +40 -54
  30. data/lib/airbrake-ruby/promise.rb +1 -0
  31. data/lib/airbrake-ruby/query.rb +1 -6
  32. data/lib/airbrake-ruby/queue.rb +1 -8
  33. data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
  34. data/lib/airbrake-ruby/remote_settings/settings_data.rb +116 -0
  35. data/lib/airbrake-ruby/remote_settings.rb +128 -0
  36. data/lib/airbrake-ruby/request.rb +1 -8
  37. data/lib/airbrake-ruby/stat.rb +2 -13
  38. data/lib/airbrake-ruby/sync_sender.rb +3 -2
  39. data/lib/airbrake-ruby/tdigest.rb +12 -9
  40. data/lib/airbrake-ruby/thread_pool.rb +9 -6
  41. data/lib/airbrake-ruby/time_truncate.rb +2 -2
  42. data/lib/airbrake-ruby/timed_trace.rb +1 -3
  43. data/lib/airbrake-ruby/truncator.rb +8 -2
  44. data/lib/airbrake-ruby/version.rb +11 -1
  45. data/lib/airbrake-ruby.rb +44 -54
  46. data/spec/airbrake_spec.rb +178 -92
  47. data/spec/async_sender_spec.rb +10 -8
  48. data/spec/backtrace_spec.rb +39 -36
  49. data/spec/benchmark_spec.rb +7 -5
  50. data/spec/code_hunk_spec.rb +26 -17
  51. data/spec/config/processor_spec.rb +167 -0
  52. data/spec/config/validator_spec.rb +23 -3
  53. data/spec/config_spec.rb +43 -55
  54. data/spec/context_spec.rb +54 -0
  55. data/spec/deploy_notifier_spec.rb +6 -4
  56. data/spec/file_cache_spec.rb +1 -0
  57. data/spec/filter_chain_spec.rb +29 -24
  58. data/spec/filters/context_filter_spec.rb +14 -5
  59. data/spec/filters/dependency_filter_spec.rb +3 -1
  60. data/spec/filters/exception_attributes_filter_spec.rb +5 -3
  61. data/spec/filters/gem_root_filter_spec.rb +9 -6
  62. data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
  63. data/spec/filters/{git_repository_filter.rb → git_repository_filter_spec.rb} +26 -15
  64. data/spec/filters/git_revision_filter_spec.rb +20 -20
  65. data/spec/filters/keys_allowlist_spec.rb +26 -16
  66. data/spec/filters/keys_blocklist_spec.rb +35 -18
  67. data/spec/filters/root_directory_filter_spec.rb +7 -7
  68. data/spec/filters/sql_filter_spec.rb +28 -28
  69. data/spec/filters/system_exit_filter_spec.rb +4 -2
  70. data/spec/filters/thread_filter_spec.rb +16 -14
  71. data/spec/loggable_spec.rb +2 -2
  72. data/spec/monotonic_time_spec.rb +8 -6
  73. data/spec/nested_exception_spec.rb +46 -46
  74. data/spec/notice_notifier/options_spec.rb +25 -15
  75. data/spec/notice_notifier_spec.rb +54 -49
  76. data/spec/notice_spec.rb +7 -3
  77. data/spec/performance_breakdown_spec.rb +0 -12
  78. data/spec/performance_notifier_spec.rb +69 -87
  79. data/spec/promise_spec.rb +38 -32
  80. data/spec/query_spec.rb +1 -11
  81. data/spec/queue_spec.rb +1 -13
  82. data/spec/remote_settings/callback_spec.rb +162 -0
  83. data/spec/remote_settings/settings_data_spec.rb +348 -0
  84. data/spec/remote_settings_spec.rb +201 -0
  85. data/spec/request_spec.rb +1 -13
  86. data/spec/response_spec.rb +34 -12
  87. data/spec/spec_helper.rb +4 -4
  88. data/spec/stashable_spec.rb +5 -5
  89. data/spec/stat_spec.rb +7 -14
  90. data/spec/sync_sender_spec.rb +52 -17
  91. data/spec/tdigest_spec.rb +61 -56
  92. data/spec/thread_pool_spec.rb +67 -58
  93. data/spec/time_truncate_spec.rb +23 -6
  94. data/spec/timed_trace_spec.rb +32 -30
  95. data/spec/truncator_spec.rb +72 -43
  96. metadata +67 -51
@@ -0,0 +1,128 @@
1
+ module Airbrake
2
+ # RemoteSettings polls the remote config of the passed project at fixed
3
+ # intervals. The fetched config is yielded as a callback parameter so that the
4
+ # invoker can define read config values. Supports proxies.
5
+ #
6
+ # @example Disable/enable error notifications based on the remote value
7
+ # RemoteSettings.poll do |data|
8
+ # config.error_notifications = data.error_notifications?
9
+ # end
10
+ #
11
+ # @since v5.0.0
12
+ # @api private
13
+ class RemoteSettings
14
+ include Airbrake::Loggable
15
+
16
+ # @return [Hash{Symbol=>String}] metadata to be attached to every GET
17
+ # request
18
+ QUERY_PARAMS = URI.encode_www_form(
19
+ notifier_name: Airbrake::NOTIFIER_INFO[:name],
20
+ notifier_version: Airbrake::NOTIFIER_INFO[:version],
21
+ os: RUBY_PLATFORM,
22
+ language: "#{RUBY_ENGINE}/#{RUBY_VERSION}".freeze,
23
+ ).freeze
24
+
25
+ # @return [String]
26
+ HTTP_OK = '200'.freeze
27
+
28
+ # Polls remote config of the given project.
29
+ #
30
+ # @param [Integer] project_id
31
+ # @param [String] host
32
+ # @yield [data]
33
+ # @yieldparam data [Airbrake::RemoteSettings::SettingsData]
34
+ # @return [Airbrake::RemoteSettings]
35
+ def self.poll(project_id, host, &block)
36
+ new(project_id, host, &block).poll
37
+ end
38
+
39
+ # @param [Integer] project_id
40
+ # @yield [data]
41
+ # @yieldparam data [Airbrake::RemoteSettings::SettingsData]
42
+ def initialize(project_id, host, &block)
43
+ @data = SettingsData.new(project_id, {})
44
+ @host = host
45
+ @block = block
46
+ @config = Airbrake::Config.instance
47
+ @poll = nil
48
+ end
49
+
50
+ # Polls remote config of the given project in background.
51
+ #
52
+ # @return [self]
53
+ def poll
54
+ @poll ||= Thread.new do
55
+ @block.call(@data)
56
+
57
+ loop do
58
+ @block.call(@data.merge!(fetch_config))
59
+ sleep(@data.interval)
60
+ end
61
+ end
62
+
63
+ self
64
+ end
65
+
66
+ # Stops the background poller thread.
67
+ #
68
+ # @return [void]
69
+ def stop_polling
70
+ @poll.kill if @poll
71
+ end
72
+
73
+ private
74
+
75
+ def fetch_config
76
+ uri = build_config_uri
77
+ https = build_https(uri)
78
+ req = Net::HTTP::Get.new(uri.request_uri)
79
+ response = nil
80
+
81
+ begin
82
+ response = https.request(req)
83
+ rescue StandardError => ex
84
+ reason = "#{LOG_LABEL} HTTP error: #{ex}"
85
+ logger.error(reason)
86
+ return {}
87
+ end
88
+
89
+ unless response.code == HTTP_OK
90
+ logger.error(response.body)
91
+ return {}
92
+ end
93
+
94
+ json = nil
95
+ begin
96
+ json = JSON.parse(response.body)
97
+ rescue JSON::ParserError => ex
98
+ logger.error(ex)
99
+ return {}
100
+ end
101
+
102
+ json
103
+ end
104
+
105
+ def build_config_uri
106
+ uri = URI(@data.config_route(@host))
107
+ uri.query = QUERY_PARAMS
108
+ uri
109
+ end
110
+
111
+ def build_https(uri)
112
+ Net::HTTP.new(uri.host, uri.port, *proxy_params).tap do |https|
113
+ https.use_ssl = uri.is_a?(URI::HTTPS)
114
+ if @config.timeout
115
+ https.open_timeout = @config.timeout
116
+ https.read_timeout = @config.timeout
117
+ end
118
+ end
119
+ end
120
+
121
+ def proxy_params
122
+ return unless @config.proxy.key?(:host)
123
+
124
+ [@config.proxy[:host], @config.proxy[:port], @config.proxy[:user],
125
+ @config.proxy[:password]]
126
+ end
127
+ end
128
+ end
@@ -4,7 +4,6 @@ module Airbrake
4
4
  # @see Airbrake.notify_request
5
5
  # @api public
6
6
  # @since v3.2.0
7
- # rubocop:disable Metrics/ParameterLists
8
7
  class Request
9
8
  include HashKeyable
10
9
  include Ignorable
@@ -12,15 +11,12 @@ module Airbrake
12
11
  include Mergeable
13
12
  include Grouppable
14
13
 
15
- attr_accessor :method, :route, :status_code, :start_time, :end_time,
16
- :timing, :time
14
+ attr_accessor :method, :route, :status_code, :timing, :time
17
15
 
18
16
  def initialize(
19
17
  method:,
20
18
  route:,
21
19
  status_code:,
22
- start_time: Time.now,
23
- end_time: start_time + 1,
24
20
  timing: nil,
25
21
  time: Time.now
26
22
  )
@@ -28,8 +24,6 @@ module Airbrake
28
24
  @method = method
29
25
  @route = route
30
26
  @status_code = status_code
31
- @start_time = start_time
32
- @end_time = end_time
33
27
  @timing = timing
34
28
  @time = time
35
29
  end
@@ -51,5 +45,4 @@ module Airbrake
51
45
  }.delete_if { |_key, val| val.nil? }
52
46
  end
53
47
  end
54
- # rubocop:enable Metrics/ParameterLists
55
48
  end
@@ -4,12 +4,12 @@ module Airbrake
4
4
  # Stat is a data structure that allows accumulating performance data (route
5
5
  # performance, SQL query performance and such). It's powered by TDigests.
6
6
  #
7
- # Usually, one Stat corresponds to one resource (route or query,
7
+ # Usually, one Stat corresponds to one metric (route or query,
8
8
  # etc.). Incrementing a stat means pushing new performance statistics.
9
9
  #
10
10
  # @example
11
11
  # stat = Airbrake::Stat.new
12
- # stat.increment(Time.now - 200)
12
+ # stat.increment_ms(2000)
13
13
  # stat.to_h # Pack and serialize data so it can be transmitted.
14
14
  #
15
15
  # @since v3.2.0
@@ -41,17 +41,6 @@ module Airbrake
41
41
  end
42
42
  end
43
43
 
44
- # Increments tdigest timings and updates tdigest with the difference between
45
- # +end_time+ and +start_time+.
46
- #
47
- # @param [Date] start_time
48
- # @param [Date] end_time
49
- # @return [void]
50
- def increment(start_time, end_time = nil)
51
- end_time ||= Time.new
52
- increment_ms((end_time - start_time) * 1000)
53
- end
54
-
55
44
  # Increments tdigest timings and updates tdigest with given +ms+ value.
56
45
  #
57
46
  # @param [Float] ms
@@ -23,7 +23,7 @@ module Airbrake
23
23
  # @param [#to_json] data
24
24
  # @param [URI::HTTPS] endpoint
25
25
  # @return [Hash{String=>String}] the parsed HTTP response
26
- def send(data, promise, endpoint = @config.endpoint)
26
+ def send(data, promise, endpoint = @config.error_endpoint)
27
27
  return promise if rate_limited_ip?(promise)
28
28
 
29
29
  response = nil
@@ -47,6 +47,7 @@ module Airbrake
47
47
  end
48
48
 
49
49
  return promise.reject(parsed_resp['error']) if parsed_resp.key?('error')
50
+
50
51
  promise.resolve(parsed_resp)
51
52
  end
52
53
 
@@ -79,7 +80,7 @@ module Airbrake
79
80
  req['Authorization'] = "Bearer #{@config.project_key}"
80
81
  req['Content-Type'] = CONTENT_TYPE
81
82
  req['User-Agent'] =
82
- "#{Airbrake::Notice::NOTIFIER[:name]}/#{Airbrake::AIRBRAKE_RUBY_VERSION}" \
83
+ "#{Airbrake::NOTIFIER_INFO[:name]}/#{Airbrake::AIRBRAKE_RUBY_VERSION}" \
83
84
  " Ruby/#{RUBY_VERSION}"
84
85
 
85
86
  req
@@ -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
@@ -200,10 +201,11 @@ module Airbrake
200
201
  unless (0..1).cover?(item)
201
202
  raise ArgumentError, "p should be in [0,1], got #{item}"
202
203
  end
204
+
203
205
  if size == 0
204
206
  nil
205
207
  else
206
- _cumulate(true)
208
+ _cumulate(exact: true)
207
209
  h = @size * item
208
210
  lower, upper = bound_mean_cumn(h)
209
211
  if lower.nil? && upper.nil?
@@ -254,7 +256,7 @@ module Airbrake
254
256
  array = bytes[start_idx..-1].unpack("G#{size}N#{size}")
255
257
  means, counts = array.each_slice(size).to_a if array.any?
256
258
  when SMALL_ENCODING
257
- means = bytes[start_idx..(start_idx + 4 * size)].unpack("g#{size}")
259
+ means = bytes[start_idx..(start_idx + (4 * size))].unpack("g#{size}")
258
260
  # Decode delta encoding of means
259
261
  x = 0
260
262
  means.map! do |m|
@@ -262,7 +264,7 @@ module Airbrake
262
264
  x = m
263
265
  m
264
266
  end
265
- counts_bytes = bytes[(start_idx + 4 * size)..-1].unpack('C*')
267
+ counts_bytes = bytes[(start_idx + (4 * size))..-1].unpack('C*')
266
268
  counts = []
267
269
  # Decode variable length integer bytes
268
270
  size.times do
@@ -271,6 +273,7 @@ module Airbrake
271
273
  shift = 7
272
274
  while (v & 0x80) != 0
273
275
  raise 'Shift too large in decode' if shift > 28
276
+
274
277
  v = counts_bytes.shift || 0
275
278
  z += (v & 0x7f) << shift
276
279
  shift += 7
@@ -304,7 +307,7 @@ module Airbrake
304
307
  centroid.mean += n * (x - centroid.mean) / (centroid.n + n)
305
308
  end
306
309
 
307
- _cumulate(false, true) if centroid.mean_cumn.nil?
310
+ _cumulate(exact: false, force: true) if centroid.mean_cumn.nil?
308
311
 
309
312
  centroid.cumn += n
310
313
  centroid.mean_cumn += n / 2.0
@@ -312,7 +315,7 @@ module Airbrake
312
315
  end
313
316
 
314
317
  # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
315
- def _cumulate(exact = false, force = false)
318
+ def _cumulate(exact: false, force: false)
316
319
  unless force
317
320
  factor = if @last_cumulate == 0
318
321
  Float::INFINITY
@@ -324,7 +327,7 @@ module Airbrake
324
327
 
325
328
  cumn = 0
326
329
  @centroids.each_value do |c|
327
- c.mean_cumn = cumn + c.n / 2.0
330
+ c.mean_cumn = cumn + (c.n / 2.0)
328
331
  cumn = c.cumn = cumn + c.n
329
332
  end
330
333
  @size = @last_cumulate = cumn
@@ -359,7 +362,7 @@ module Airbrake
359
362
  end
360
363
  end
361
364
 
362
- _cumulate(false)
365
+ _cumulate(exact: false)
363
366
 
364
367
  # If the number of centroids has grown to a very large size,
365
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
@@ -46,11 +48,11 @@ module Airbrake
46
48
  # false if the queue is full
47
49
  def <<(message)
48
50
  if backlog >= @queue_size
49
- logger.error(
51
+ logger.info do
50
52
  "#{LOG_LABEL} ThreadPool has reached its capacity of " \
51
53
  "#{@queue_size} and the following message will not be " \
52
- "processed: #{message.inspect}",
53
- )
54
+ "processed: #{message.inspect}"
55
+ end
54
56
  return false
55
57
  end
56
58
 
@@ -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 + ' (Ctrl-C to abort)')
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?
@@ -129,6 +131,7 @@ module Airbrake
129
131
  Thread.new do
130
132
  while (message = @queue.pop)
131
133
  break if message == :stop
134
+
132
135
  @block.call(message)
133
136
  end
134
137
  end
@@ -6,10 +6,10 @@ module Airbrake
6
6
  module TimeTruncate
7
7
  # Truncate +time+ to floor minute and turn it into an RFC3339 timestamp.
8
8
  #
9
- # @param [Time] time
9
+ # @param [Time, Integer, Float] time
10
10
  # @return [String]
11
11
  def self.utc_truncate_minutes(time)
12
- tm = time.getutc
12
+ tm = Time.at(time).getutc
13
13
 
14
14
  Time.utc(tm.year, tm.month, tm.day, tm.hour, tm.min).to_datetime.rfc3339
15
15
  end
@@ -50,9 +50,7 @@ module Airbrake
50
50
 
51
51
  # @return [Hash<String=>Float>]
52
52
  def spans
53
- @spans.each_with_object({}) do |(label, benchmark), new_spans|
54
- new_spans[label] = benchmark.duration
55
- end
53
+ @spans.transform_values(&:duration)
56
54
  end
57
55
  end
58
56
  end
@@ -12,6 +12,10 @@ module Airbrake
12
12
  # strings with +ENCODING_OPTIONS+
13
13
  TEMP_ENCODING = 'utf-16'.freeze
14
14
 
15
+ # @return [Array<Encoding>] encodings that are eligible for fixing invalid
16
+ # characters
17
+ SUPPORTED_ENCODINGS = [Encoding::UTF_8, Encoding::ASCII].freeze
18
+
15
19
  # @return [String] what to append when something is a circular reference
16
20
  CIRCULAR = '[Circular]'.freeze
17
21
 
@@ -35,6 +39,7 @@ module Airbrake
35
39
  def truncate(object, seen = Set.new)
36
40
  if seen.include?(object.object_id)
37
41
  return CIRCULAR if CIRCULAR_TYPES.any? { |t| object.is_a?(t) }
42
+
38
43
  return object
39
44
  end
40
45
  truncate_object(object, seen << object.object_id)
@@ -63,6 +68,7 @@ module Airbrake
63
68
  def truncate_string(str)
64
69
  fixed_str = replace_invalid_characters(str)
65
70
  return fixed_str if fixed_str.length <= @max_size
71
+
66
72
  (fixed_str.slice(0, @max_size) + TRUNCATED).freeze
67
73
  end
68
74
 
@@ -76,6 +82,7 @@ module Airbrake
76
82
  truncated_hash = {}
77
83
  hash.each_with_index do |(key, val), idx|
78
84
  break if idx + 1 > @max_size
85
+
79
86
  truncated_hash[key] = truncate(val, seen)
80
87
  end
81
88
 
@@ -103,8 +110,7 @@ module Airbrake
103
110
  # @return [String] a UTF-8 encoded string
104
111
  # @see https://github.com/flori/json/commit/3e158410e81f94dbbc3da6b7b35f4f64983aa4e3
105
112
  def replace_invalid_characters(str)
106
- encoding = str.encoding
107
- utf8_string = (encoding == Encoding::UTF_8 || encoding == Encoding::ASCII)
113
+ utf8_string = SUPPORTED_ENCODINGS.include?(str.encoding)
108
114
  return str if utf8_string && str.valid_encoding?
109
115
 
110
116
  temp_str = str.dup
@@ -2,5 +2,15 @@
2
2
  # More information: http://semver.org/
3
3
  module Airbrake
4
4
  # @return [String] the library version
5
- AIRBRAKE_RUBY_VERSION = '4.15.0'.freeze
5
+ # @api public
6
+ AIRBRAKE_RUBY_VERSION = '6.1.0'.freeze
7
+
8
+ # @return [Hash{Symbol=>String}] the information about the notifier library
9
+ # @since v5.0.0
10
+ # @api public
11
+ NOTIFIER_INFO = {
12
+ name: 'airbrake-ruby'.freeze,
13
+ version: Airbrake::AIRBRAKE_RUBY_VERSION,
14
+ url: 'https://github.com/airbrake/airbrake-ruby'.freeze,
15
+ }.freeze
6
16
  end
data/lib/airbrake-ruby.rb CHANGED
@@ -12,6 +12,10 @@ require 'airbrake-ruby/mergeable'
12
12
  require 'airbrake-ruby/grouppable'
13
13
  require 'airbrake-ruby/config'
14
14
  require 'airbrake-ruby/config/validator'
15
+ require 'airbrake-ruby/config/processor'
16
+ require 'airbrake-ruby/remote_settings/callback'
17
+ require 'airbrake-ruby/remote_settings/settings_data'
18
+ require 'airbrake-ruby/remote_settings'
15
19
  require 'airbrake-ruby/promise'
16
20
  require 'airbrake-ruby/thread_pool'
17
21
  require 'airbrake-ruby/sync_sender'
@@ -54,6 +58,7 @@ require 'airbrake-ruby/benchmark'
54
58
  require 'airbrake-ruby/monotonic_time'
55
59
  require 'airbrake-ruby/timed_trace'
56
60
  require 'airbrake-ruby/queue'
61
+ require 'airbrake-ruby/context'
57
62
 
58
63
  # Airbrake is a thin wrapper around instances of the notifier classes (such as
59
64
  # notice, performance & deploy notifiers). It creates a way to access them via a
@@ -117,7 +122,15 @@ module Airbrake
117
122
  def configure
118
123
  yield config = Airbrake::Config.instance
119
124
  Airbrake::Loggable.instance = config.logger
120
- process_config_options(config)
125
+
126
+ config_processor = Airbrake::Config::Processor.new(config)
127
+
128
+ config_processor.process_blocklist(notice_notifier)
129
+ config_processor.process_allowlist(notice_notifier)
130
+
131
+ @remote_settings ||= config_processor.process_remote_configuration
132
+
133
+ config_processor.add_filters(notice_notifier)
121
134
  end
122
135
 
123
136
  # @since v4.2.3
@@ -260,8 +273,8 @@ module Airbrake
260
273
  # Airbrake.close
261
274
  # Airbrake.notify('App crashed!') #=> raises Airbrake::Error
262
275
  #
263
- # @return [void]
264
- # rubocop:disable Style/GuardClause, Style/IfUnlessModifier
276
+ # @return [nil]
277
+ # rubocop:disable Style/IfUnlessModifier
265
278
  def close
266
279
  if defined?(@notice_notifier) && @notice_notifier
267
280
  @notice_notifier.close
@@ -270,8 +283,14 @@ module Airbrake
270
283
  if defined?(@performance_notifier) && @performance_notifier
271
284
  @performance_notifier.close
272
285
  end
286
+
287
+ if defined?(@remote_settings) && @remote_settings
288
+ @remote_settings.stop_polling
289
+ end
290
+
291
+ nil
273
292
  end
274
- # rubocop:enable Style/GuardClause, Style/IfUnlessModifier
293
+ # rubocop:enable Style/IfUnlessModifier
275
294
 
276
295
  # Pings the Airbrake Deploy API endpoint about the occurred deploy.
277
296
  #
@@ -345,23 +364,14 @@ module Airbrake
345
364
  # method: 'POST',
346
365
  # route: '/thing/:id/create',
347
366
  # status_code: 200,
348
- # func: 'do_stuff',
349
- # file: 'app/models/foo.rb',
350
- # line: 452,
351
367
  # timing: 123.45 # ms
352
368
  # )
353
369
  #
354
370
  # @param [Hash{Symbol=>Object}] request_info
355
371
  # @option request_info [String] :method The HTTP method that was invoked
356
372
  # @option request_info [String] :route The route that was invoked
357
- # @option request_info [Integer] :status_code The respose code that the
373
+ # @option request_info [Integer] :status_code The response code that the
358
374
  # route returned
359
- # @option request_info [String] :func The function that called the query
360
- # (optional)
361
- # @option request_info [String] :file The file that has the function that
362
- # called the query (optional)
363
- # @option request_info [Integer] :line The line that executes the query
364
- # (optional)
365
375
  # @option request_info [Float] :timing How much time it took to process the
366
376
  # request (in ms)
367
377
  # @param [Hash] stash What needs to be appeneded to the stash, so it's
@@ -396,6 +406,9 @@ module Airbrake
396
406
  # method: 'GET',
397
407
  # route: '/things',
398
408
  # query: 'SELECT * FROM things',
409
+ # func: 'do_stuff',
410
+ # file: 'app/models/foo.rb',
411
+ # line: 452,
399
412
  # timing: 123.45 # ms
400
413
  # )
401
414
  #
@@ -405,6 +418,12 @@ module Airbrake
405
418
  # @option query_info [String] :route The route that triggered this SQL
406
419
  # query (optional)
407
420
  # @option query_info [String] :query The query that was executed
421
+ # @option request_info [String] :func The function that called the query
422
+ # (optional)
423
+ # @option request_info [String] :file The file that has the function that
424
+ # called the query (optional)
425
+ # @option request_info [Integer] :line The line that executes the query
426
+ # (optional)
408
427
  # @option query_info [Float] :timing How much time it took to process the
409
428
  # query (in ms)
410
429
  # @param [Hash] stash What needs to be appeneded to the stash, so it's
@@ -432,7 +451,7 @@ module Airbrake
432
451
  # Increments performance breakdown statistics of a certain route.
433
452
  #
434
453
  # @example
435
- # Airbrake.notify_request(
454
+ # Airbrake.notify_performance_breakdown(
436
455
  # method: 'POST',
437
456
  # route: '/thing/:id/create',
438
457
  # response_type: 'json',
@@ -504,24 +523,24 @@ module Airbrake
504
523
  performance_notifier.notify_sync(queue)
505
524
  end
506
525
 
507
- # Runs a callback before {.notify_request} or {.notify_query} kicks in. This
508
- # is useful if you want to ignore specific resources or filter the data the
509
- # resource contains.
526
+ # Runs a callback before {.notify_request}, {.notify_query}, {.notify_queue}
527
+ # or {.notify_performance_breakdown} kicks in. This is useful if you want to
528
+ # ignore specific metrics or filter the data the metric contains.
510
529
  #
511
- # @example Ignore all resources
530
+ # @example Ignore all metrics
512
531
  # Airbrake.add_performance_filter(&:ignore!)
513
532
  # @example Filter sensitive data
514
- # Airbrake.add_performance_filter do |resource|
515
- # case resource
533
+ # Airbrake.add_performance_filter do |metric|
534
+ # case metric
516
535
  # when Airbrake::Query
517
- # resource.route = '[Filtered]'
536
+ # metric.route = '[Filtered]'
518
537
  # when Airbrake::Request
519
- # resource.query = '[Filtered]'
538
+ # metric.query = '[Filtered]'
520
539
  # end
521
540
  # end
522
541
  # @example Filter with help of a class
523
542
  # class MyFilter
524
- # def call(resource)
543
+ # def call(metric)
525
544
  # # ...
526
545
  # end
527
546
  # end
@@ -529,7 +548,7 @@ module Airbrake
529
548
  # Airbrake.add_performance_filter(MyFilter.new)
530
549
  #
531
550
  # @param [#call] filter The filter object
532
- # @yield [resource] The resource to filter
551
+ # @yield [metric] The metric to filter
533
552
  # @yieldparam [Airbrake::Query, Airbrake::Request]
534
553
  # @yieldreturn [void]
535
554
  # @return [void]
@@ -567,35 +586,6 @@ module Airbrake
567
586
  self.notice_notifier = NoticeNotifier.new
568
587
  self.deploy_notifier = DeployNotifier.new
569
588
  end
570
-
571
- private
572
-
573
- # rubocop:disable Metrics/AbcSize
574
- def process_config_options(config)
575
- if config.blocklist_keys.any?
576
- blocklist = Airbrake::Filters::KeysBlocklist.new(config.blocklist_keys)
577
- notice_notifier.add_filter(blocklist)
578
- end
579
-
580
- if config.allowlist_keys.any?
581
- allowlist = Airbrake::Filters::KeysAllowlist.new(config.allowlist_keys)
582
- notice_notifier.add_filter(allowlist)
583
- end
584
-
585
- return unless config.root_directory
586
-
587
- [
588
- Airbrake::Filters::RootDirectoryFilter,
589
- Airbrake::Filters::GitRevisionFilter,
590
- Airbrake::Filters::GitRepositoryFilter,
591
- Airbrake::Filters::GitLastCheckoutFilter,
592
- ].each do |filter|
593
- next if notice_notifier.has_filter?(filter)
594
-
595
- notice_notifier.add_filter(filter.new(config.root_directory))
596
- end
597
- end
598
- # rubocop:enable Metrics/AbcSize
599
589
  end
600
590
  end
601
591
  # rubocop:enable Metrics/ModuleLength