airbrake-ruby 4.13.0-java → 4.13.1-java

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e63f9645cf849006496087d1fefe38eb42ad4c448ff289aa4f84d5a95244d816
4
- data.tar.gz: fd3eeb0af67ed2e24496268829513c650e2fd2270514febd0a512c07d12119d2
3
+ metadata.gz: 591974a4b164f19bfa3a83b3d9b6441f500759d04fd094c36c44d830f44782ee
4
+ data.tar.gz: 2f2d9bd955015731f70abc13a6dafd3a73002567cea3b0b8b6bb0a1ae456a8be
5
5
  SHA512:
6
- metadata.gz: e7464407b11639d0bef4af861e98b506ffb04454ec0910ac9fc86276b471fbf4b6e141d636569c84f69dc2c0dce85c89452c424775b4aed9b54dfb47cd0640df
7
- data.tar.gz: 4f3fd32bd982ba1a71906ff4ba44d53bd5be061b94426786e5f975725757e365c9a22f5aa7ce08636ef1847662941ded3c052b9c5708ba113fc251d952e99a49
6
+ metadata.gz: 17715cc9ce22e0b1ac5972d7b26f6bc3a30bc1ea18c136eb531f5c57d344e2dc53ebc316bc21bd788e03615584bcb131b682cf1552c2ed48bbe3c4509dd7d91e
7
+ data.tar.gz: 65fbb12a214ea879b6b69405950f11d2c7d599f09bc1735e90bb3744e86f021482bf44e996a8392270bf6c6818294899eb9c0c672c25f8cd1a188ed5995f45fc
@@ -119,12 +119,13 @@ module Airbrake
119
119
 
120
120
  # @param [Hash{Symbol=>Object}] user_config the hash to be used to build the
121
121
  # config
122
+ # rubocop:disable Metrics/AbcSize
122
123
  def initialize(user_config = {})
123
124
  self.proxy = {}
124
125
  self.queue_size = 100
125
126
  self.workers = 1
126
127
  self.code_hunks = true
127
- self.logger = ::Logger.new(File::NULL)
128
+ self.logger = ::Logger.new(File::NULL).tap { |l| l.level = Logger::WARN }
128
129
  self.project_id = user_config[:project_id]
129
130
  self.project_key = user_config[:project_key]
130
131
  self.host = 'https://api.airbrake.io'
@@ -149,6 +150,7 @@ module Airbrake
149
150
 
150
151
  merge(user_config)
151
152
  end
153
+ # rubocop:enable Metrics/AbcSize
152
154
 
153
155
  # The full URL to the Airbrake Notice API. Based on the +:host+ option.
154
156
  # @return [URI] the endpoint address
@@ -22,7 +22,7 @@ module Airbrake
22
22
 
23
23
  # @return [Logger]
24
24
  def instance
25
- @instance ||= ::Logger.new(File::NULL)
25
+ @instance ||= ::Logger.new(File::NULL).tap { |l| l.level = ::Logger::WARN }
26
26
  end
27
27
  end
28
28
 
@@ -16,6 +16,11 @@ module Airbrake
16
16
  time_in_nanoseconds / (10.0**6)
17
17
  end
18
18
 
19
+ # @return [Integer] current monotonic time in seconds
20
+ def time_in_s
21
+ time_in_nanoseconds / (10.0**9)
22
+ end
23
+
19
24
  private
20
25
 
21
26
  if defined?(Process::CLOCK_MONOTONIC)
@@ -14,18 +14,20 @@ module Airbrake
14
14
  @flush_period = Airbrake::Config.instance.performance_stats_flush_period
15
15
  @async_sender = AsyncSender.new(:put)
16
16
  @sync_sender = SyncSender.new(:put)
17
- @payload = {}
18
17
  @schedule_flush = nil
19
- @mutex = Mutex.new
20
18
  @filter_chain = FilterChain.new
21
- @waiting = false
19
+
20
+ @payload = {}.extend(MonitorMixin)
21
+ @has_payload = @payload.new_cond
22
22
  end
23
23
 
24
24
  # @param [Hash] resource
25
25
  # @see Airbrake.notify_query
26
26
  # @see Airbrake.notify_request
27
27
  def notify(resource)
28
- send_resource(resource, sync: false)
28
+ @payload.synchronize do
29
+ send_resource(resource, sync: false)
30
+ end
29
31
  end
30
32
 
31
33
  # @param [Hash] resource
@@ -46,7 +48,7 @@ module Airbrake
46
48
  end
47
49
 
48
50
  def close
49
- @mutex.synchronize do
51
+ @payload.synchronize do
50
52
  @schedule_flush.kill if @schedule_flush
51
53
  @async_sender.close
52
54
  logger.debug("#{LOG_LABEL} performance notifier closed")
@@ -55,6 +57,46 @@ module Airbrake
55
57
 
56
58
  private
57
59
 
60
+ def schedule_flush
61
+ @schedule_flush ||= Thread.new do
62
+ loop do
63
+ @payload.synchronize do
64
+ @last_flush_time ||= MonotonicTime.time_in_s
65
+
66
+ while (MonotonicTime.time_in_s - @last_flush_time) < @flush_period
67
+ @has_payload.wait(@flush_period)
68
+ end
69
+
70
+ if @payload.none?
71
+ @last_flush_time = nil
72
+ next
73
+ end
74
+
75
+ send(@async_sender, @payload, Airbrake::Promise.new)
76
+ @payload.clear
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ def send_resource(resource, sync:)
83
+ promise = check_configuration(resource)
84
+ return promise if promise.rejected?
85
+
86
+ @filter_chain.refine(resource)
87
+ if resource.ignored?
88
+ return Promise.new.reject("#{resource.class} was ignored by a filter")
89
+ end
90
+
91
+ update_payload(resource)
92
+ if sync || @flush_period == 0
93
+ send(@sync_sender, @payload, promise)
94
+ else
95
+ @has_payload.signal
96
+ schedule_flush
97
+ end
98
+ end
99
+
58
100
  def update_payload(resource)
59
101
  if (total_stat = @payload[resource])
60
102
  @payload.key(total_stat).merge(resource)
@@ -83,61 +125,6 @@ module Airbrake
83
125
  end
84
126
  end
85
127
 
86
- def schedule_flush
87
- return if @payload.empty?
88
-
89
- if @schedule_flush && @schedule_flush.status == 'sleep' && @waiting
90
- begin
91
- @schedule_flush.run
92
- rescue ThreadError => exception
93
- logger.error("#{LOG_LABEL}: error occurred while flushing: #{exception}")
94
- end
95
- end
96
-
97
- @schedule_flush ||= spawn_timer
98
- end
99
-
100
- def spawn_timer
101
- Thread.new do
102
- loop do
103
- if @payload.none?
104
- @waiting = true
105
- Thread.stop
106
- @waiting = false
107
- end
108
-
109
- sleep(@flush_period)
110
-
111
- payload = nil
112
- @mutex.synchronize do
113
- payload = @payload
114
- @payload = {}
115
- end
116
-
117
- send(@async_sender, payload, Airbrake::Promise.new)
118
- end
119
- end
120
- end
121
-
122
- def send_resource(resource, sync:)
123
- promise = check_configuration(resource)
124
- return promise if promise.rejected?
125
-
126
- @filter_chain.refine(resource)
127
- if resource.ignored?
128
- return Promise.new.reject("#{resource.class} was ignored by a filter")
129
- end
130
-
131
- @mutex.synchronize do
132
- update_payload(resource)
133
- if sync || @flush_period == 0
134
- send(@sync_sender, @payload, promise)
135
- else
136
- schedule_flush
137
- end
138
- end
139
- end
140
-
141
128
  def check_configuration(resource)
142
129
  promise = @config.check_configuration
143
130
  return promise if promise.rejected?
@@ -153,16 +140,17 @@ module Airbrake
153
140
  end
154
141
 
155
142
  def send(sender, payload, promise)
156
- signature = "#{self.class.name}##{__method__}"
157
- raise "#{signature}: payload (#{payload}) cannot be empty. Race?" if payload.none?
158
-
159
- logger.debug { "#{LOG_LABEL} #{signature}: #{payload}" }
143
+ raise "payload cannot be empty. Race?" if payload.none?
160
144
 
161
145
  with_grouped_payload(payload) do |resource_hash, destination|
162
146
  url = URI.join(
163
147
  @config.host,
164
148
  "api/v5/projects/#{@config.project_id}/#{destination}",
165
149
  )
150
+
151
+ logger.debug do
152
+ "#{LOG_LABEL} #{self.class.name}##{__method__}: #{resource_hash}"
153
+ end
166
154
  sender.send(resource_hash, promise, url)
167
155
  end
168
156
 
@@ -14,15 +14,13 @@ module Airbrake
14
14
  #
15
15
  # @since v3.2.0
16
16
  class Stat
17
- attr_accessor :count, :sum, :sumsq, :tdigest
17
+ attr_accessor :sum, :sumsq, :tdigest
18
18
 
19
- # @param [Integer] count How many times this stat was incremented
20
19
  # @param [Float] sum The sum of duration in milliseconds
21
20
  # @param [Float] sumsq The squared sum of duration in milliseconds
22
21
  # @param [TDigest::TDigest] tdigest Packed durations. By default,
23
22
  # compression is 20
24
- def initialize(count: 0, sum: 0.0, sumsq: 0.0, tdigest: TDigest.new(0.05))
25
- @count = count
23
+ def initialize(sum: 0.0, sumsq: 0.0, tdigest: TDigest.new(0.05))
26
24
  @sum = sum
27
25
  @sumsq = sumsq
28
26
  @tdigest = tdigest
@@ -33,15 +31,15 @@ module Airbrake
33
31
  def to_h
34
32
  tdigest.compress!
35
33
  {
36
- 'count' => count,
34
+ 'count' => tdigest.size,
37
35
  'sum' => sum,
38
36
  'sumsq' => sumsq,
39
37
  'tdigest' => Base64.strict_encode64(tdigest.as_small_bytes),
40
38
  }
41
39
  end
42
40
 
43
- # Increments count and updates performance with the difference of +end_time+
44
- # and +start_time+.
41
+ # Increments tdigest timings and updates tdigest with the difference between
42
+ # +end_time+ and +start_time+.
45
43
  #
46
44
  # @param [Date] start_time
47
45
  # @param [Date] end_time
@@ -51,13 +49,11 @@ module Airbrake
51
49
  increment_ms((end_time - start_time) * 1000)
52
50
  end
53
51
 
54
- # Increments count and updates performance with given +ms+ value.
52
+ # Increments tdigest timings and updates tdigest with given +ms+ value.
55
53
  #
56
54
  # @param [Float] ms
57
55
  # @return [void]
58
56
  def increment_ms(ms)
59
- self.count += 1
60
-
61
57
  self.sum += ms
62
58
  self.sumsq += ms * ms
63
59
 
@@ -69,7 +65,7 @@ module Airbrake
69
65
  #
70
66
  # @return [String]
71
67
  def inspect
72
- "#<struct Airbrake::Stat count=#{count}, sum=#{sum}, sumsq=#{sumsq}>"
68
+ "#<struct Airbrake::Stat count=#{tdigest.size}, sum=#{sum}, sumsq=#{sumsq}>"
73
69
  end
74
70
  alias pretty_print inspect
75
71
  end
@@ -37,14 +37,15 @@ module Airbrake
37
37
  end
38
38
 
39
39
  attr_accessor :centroids
40
+ attr_reader :size
41
+
40
42
  def initialize(delta = 0.01, k = 25, cx = 1.1)
41
43
  @delta = delta
42
44
  @k = k
43
45
  @cx = cx
44
46
  @centroids = RBTree.new
45
- @nreset = 0
46
- @n = 0
47
- reset!
47
+ @size = 0
48
+ @last_cumulate = 0
48
49
  end
49
50
 
50
51
  def +(other)
@@ -59,8 +60,8 @@ module Airbrake
59
60
  # compression as defined by Java implementation
60
61
  size = @centroids.size
61
62
  output = [VERBOSE_ENCODING, compression, size]
62
- output += @centroids.map { |_, c| c.mean }
63
- output += @centroids.map { |_, c| c.n }
63
+ output += @centroids.each_value.map(&:mean)
64
+ output += @centroids.each_value.map(&:n)
64
65
  output.pack("NGNG#{size}N#{size}")
65
66
  end
66
67
 
@@ -70,14 +71,14 @@ module Airbrake
70
71
  output = [self.class::SMALL_ENCODING, compression, size]
71
72
  x = 0
72
73
  # delta encoding allows saving 4-bytes floats
73
- mean_arr = @centroids.map do |_, c|
74
+ mean_arr = @centroids.each_value.map do |c|
74
75
  val = c.mean - x
75
76
  x = c.mean
76
77
  val
77
78
  end
78
79
  output += mean_arr
79
80
  # Variable length encoding of numbers
80
- c_arr = @centroids.each_with_object([]) do |(_, c), arr|
81
+ c_arr = @centroids.each_value.each_with_object([]) do |c, arr|
81
82
  k = 0
82
83
  n = c.n
83
84
  while n < 0 || n > 0x7f
@@ -95,7 +96,7 @@ module Airbrake
95
96
  # rubocop:enable Metrics/AbcSize
96
97
 
97
98
  def as_json(_ = nil)
98
- @centroids.map { |_, c| c.as_json }
99
+ @centroids.each_value.map(&:as_json)
99
100
  end
100
101
 
101
102
  def bound_mean(x)
@@ -138,21 +139,17 @@ module Airbrake
138
139
  end
139
140
 
140
141
  def find_nearest(x)
141
- return nil if size == 0
142
-
143
- ceil = @centroids.upper_bound(x)
144
- floor = @centroids.lower_bound(x)
142
+ return if size == 0
145
143
 
146
- return floor[1] if ceil.nil?
147
- return ceil[1] if floor.nil?
144
+ upper_key, upper = @centroids.upper_bound(x)
145
+ lower_key, lower = @centroids.lower_bound(x)
146
+ return lower unless upper_key
147
+ return upper unless lower_key
148
148
 
149
- ceil_key = ceil[0]
150
- floor_key = floor[0]
151
-
152
- if (floor_key - x).abs < (ceil_key - x).abs
153
- floor[1]
149
+ if (lower_key - x).abs < (upper_key - x).abs
150
+ lower
154
151
  else
155
- ceil[1]
152
+ upper
156
153
  end
157
154
  end
158
155
 
@@ -186,7 +183,7 @@ module Airbrake
186
183
  mean_cumn += (item - lower.mean) * (upper.mean_cumn - lower.mean_cumn) \
187
184
  / (upper.mean - lower.mean)
188
185
  end
189
- mean_cumn / @n
186
+ mean_cumn / @size
190
187
  end
191
188
  end
192
189
  is_array ? x : x.first
@@ -207,7 +204,7 @@ module Airbrake
207
204
  nil
208
205
  else
209
206
  _cumulate(true)
210
- h = @n * item
207
+ h = @size * item
211
208
  lower, upper = bound_mean_cumn(h)
212
209
  if lower.nil? && upper.nil?
213
210
  nil
@@ -237,17 +234,12 @@ module Airbrake
237
234
 
238
235
  def reset!
239
236
  @centroids.clear
240
- @n = 0
241
- @nreset += 1
237
+ @size = 0
242
238
  @last_cumulate = 0
243
239
  end
244
240
 
245
- def size
246
- @n || 0
247
- end
248
-
249
241
  def to_a
250
- @centroids.map { |_, c| c }
242
+ @centroids.each_value.to_a
251
243
  end
252
244
 
253
245
  # rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength
@@ -307,16 +299,16 @@ module Airbrake
307
299
 
308
300
  private
309
301
 
310
- def _add_weight(nearest, x, n)
311
- nearest.mean += n * (x - nearest.mean) / (nearest.n + n) unless x == nearest.mean
312
-
313
- _cumulate(false, true) if nearest.mean_cumn.nil?
302
+ def _add_weight(centroid, x, n)
303
+ unless x == centroid.mean
304
+ centroid.mean += n * (x - centroid.mean) / (centroid.n + n)
305
+ end
314
306
 
315
- nearest.cumn += n
316
- nearest.mean_cumn += n / 2.0
317
- nearest.n += n
307
+ _cumulate(false, true) if centroid.mean_cumn.nil?
318
308
 
319
- nil
309
+ centroid.cumn += n
310
+ centroid.mean_cumn += n / 2.0
311
+ centroid.n += n
320
312
  end
321
313
 
322
314
  # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
@@ -325,17 +317,17 @@ module Airbrake
325
317
  factor = if @last_cumulate == 0
326
318
  Float::INFINITY
327
319
  else
328
- (@n.to_f / @last_cumulate)
320
+ (@size.to_f / @last_cumulate)
329
321
  end
330
- return if @n == @last_cumulate || (!exact && @cx && @cx > factor)
322
+ return if @size == @last_cumulate || (!exact && @cx && @cx > factor)
331
323
  end
332
324
 
333
325
  cumn = 0
334
- @centroids.each do |_, c|
326
+ @centroids.each_value do |c|
335
327
  c.mean_cumn = cumn + c.n / 2.0
336
328
  cumn = c.cumn = cumn + c.n
337
329
  end
338
- @n = @last_cumulate = cumn
330
+ @size = @last_cumulate = cumn
339
331
  nil
340
332
  end
341
333
  # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
@@ -345,28 +337,25 @@ module Airbrake
345
337
  def _digest(x, n)
346
338
  # Use 'first' and 'last' instead of min/max because of performance reasons
347
339
  # This works because RBTree is sorted
348
- min = @centroids.first
349
- max = @centroids.last
350
-
351
- min = min.nil? ? nil : min[1]
352
- max = max.nil? ? nil : max[1]
340
+ min = min.last if (min = @centroids.first)
341
+ max = max.last if (max = @centroids.last)
353
342
  nearest = find_nearest(x)
354
343
 
355
- @n += n
344
+ @size += n
356
345
 
357
346
  if nearest && nearest.mean == x
358
347
  _add_weight(nearest, x, n)
359
348
  elsif nearest == min
360
- _new_centroid(x, n, 0)
349
+ @centroids[x] = Centroid.new(x, n, 0)
361
350
  elsif nearest == max
362
- _new_centroid(x, n, @n)
351
+ @centroids[x] = Centroid.new(x, n, @size)
363
352
  else
364
- p = nearest.mean_cumn.to_f / @n
365
- max_n = (4 * @n * @delta * p * (1 - p)).floor
353
+ p = nearest.mean_cumn.to_f / @size
354
+ max_n = (4 * @size * @delta * p * (1 - p)).floor
366
355
  if max_n - nearest.n >= n
367
356
  _add_weight(nearest, x, n)
368
357
  else
369
- _new_centroid(x, n, nearest.cumn)
358
+ @centroids[x] = Centroid.new(x, n, nearest.cumn)
370
359
  end
371
360
  end
372
361
 
@@ -382,12 +371,6 @@ module Airbrake
382
371
  end
383
372
  # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity,
384
373
  # rubocop:enable Metrics/AbcSize
385
-
386
- def _new_centroid(x, n, cumn)
387
- c = Centroid.new(x, n, cumn)
388
- @centroids[x] = c
389
- c
390
- end
391
374
  end
392
375
  # rubocop:enable Metrics/ClassLength
393
376
  end
@@ -2,5 +2,5 @@
2
2
  # More information: http://semver.org/
3
3
  module Airbrake
4
4
  # @return [String] the library version
5
- AIRBRAKE_RUBY_VERSION = '4.13.0'.freeze
5
+ AIRBRAKE_RUBY_VERSION = '4.13.1'.freeze
6
6
  end
@@ -163,4 +163,10 @@ RSpec.describe Airbrake::Config do
163
163
  end
164
164
  end
165
165
  end
166
+
167
+ describe "#logger" do
168
+ it "sets logger level to Logger::WARN" do
169
+ expect(subject.logger.level).to eq(Logger::WARN)
170
+ end
171
+ end
166
172
  end
@@ -0,0 +1,17 @@
1
+ RSpec.describe Airbrake::Loggable do
2
+ describe ".instance" do
3
+ it "returns a logger" do
4
+ expect(described_class.instance).to be_a(Logger)
5
+ end
6
+ end
7
+
8
+ describe "#logger" do
9
+ let(:subject) do
10
+ Class.new { include Airbrake::Loggable }.new
11
+ end
12
+
13
+ it "returns a logger that has Logger::WARN severity" do
14
+ expect(subject.logger.level).to eq(Logger::WARN)
15
+ end
16
+ end
17
+ end
@@ -9,4 +9,15 @@ RSpec.describe Airbrake::MonotonicTime do
9
9
  expect(subject.time_in_ms).to be > old_time
10
10
  end
11
11
  end
12
+
13
+ describe ".time_in_s" do
14
+ it "returns monotonic time in seconds" do
15
+ expect(subject.time_in_s).to be_a(Float)
16
+ end
17
+
18
+ it "always returns time in the future" do
19
+ old_time = subject.time_in_s
20
+ expect(subject.time_in_s).to be > old_time
21
+ end
22
+ end
12
23
  end
@@ -22,7 +22,6 @@ RSpec.describe Airbrake::Stat do
22
22
  describe "#increment_ms" do
23
23
  before { subject.increment_ms(1000) }
24
24
 
25
- its(:count) { is_expected.to eq(1) }
26
25
  its(:sum) { is_expected.to eq(1000) }
27
26
  its(:sumsq) { is_expected.to eq(1000000) }
28
27
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airbrake-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.13.0
4
+ version: 4.13.1
5
5
  platform: java
6
6
  authors:
7
7
  - Airbrake Technologies, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-27 00:00:00.000000000 Z
11
+ date: 2020-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbtree-jruby
@@ -120,6 +120,7 @@ files:
120
120
  - spec/helpers.rb
121
121
  - spec/ignorable_spec.rb
122
122
  - spec/inspectable_spec.rb
123
+ - spec/loggable_spec.rb
123
124
  - spec/monotonic_time_spec.rb
124
125
  - spec/nested_exception_spec.rb
125
126
  - spec/notice_notifier/options_spec.rb
@@ -189,6 +190,7 @@ test_files:
189
190
  - spec/tdigest_spec.rb
190
191
  - spec/async_sender_spec.rb
191
192
  - spec/stat_spec.rb
193
+ - spec/loggable_spec.rb
192
194
  - spec/backtrace_spec.rb
193
195
  - spec/notice_notifier_spec.rb
194
196
  - spec/time_truncate_spec.rb