airbrake-ruby 4.13.0-java → 4.13.1-java

Sign up to get free protection for your applications and to get access to all the features.
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