airbrake-ruby 4.10.1 → 4.12.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48ada7ef05512e70461f565b7d0f501d3109c1b6934449106cb5006bdb7281db
4
- data.tar.gz: 343e472ce390b3882543423bdb8ee50a4cc311ff3907f557a553fa57631305d7
3
+ metadata.gz: 8c5e41d6b33c6a201ef67d32e32e69bbef6e560c1af80dc19ae8f4192d6b84fd
4
+ data.tar.gz: 34e30b5ce530edc18c512ba0be5392a2c53cdee68ec23eb43174e9690715f821
5
5
  SHA512:
6
- metadata.gz: 7d68da52b648cff0b0e4c64016f5e0dd6d0143f1cf547e5604ed41ee58f9f03511e689c3acd35eef7df632d998cb56a416212ff1c952c9331ec173459641c20c
7
- data.tar.gz: '079ac6ce90ab7b885561e7f17ab6d770630d59cbaa066664c2b0c2cabd4c28b2c594101863ef04b8e4a92e369ac5e9f3c886159f227eec370a485544cf035250'
6
+ metadata.gz: '0081a23db3f3ff08f56382e97a67685a7c28eb81c5c93963a440a5f216ddf322ffaf8dae6be14a1394edc079dbd1644511f817693a14eebb3e097243f03f74c9'
7
+ data.tar.gz: c9c58c197046e16f7706cddbfb4caab70837f03b457418ff22f756499efe6bd98762eca8547a9e716af9d04e20c53a4440a9ca83affc7c1713623d3a191cb560
@@ -328,9 +328,8 @@ module Airbrake
328
328
  notice_notifier.merge_context(context)
329
329
  end
330
330
 
331
- # Increments request statistics of a certain +route+ that was invoked on
332
- # +start_time+ and ended on +end_time+ with +method+, and returned
333
- # +status_code+.
331
+ # Increments request statistics of a certain +route+ invoked with +method+,
332
+ # which returned +status_code+.
334
333
  #
335
334
  # After a certain amount of time (n seconds) the aggregated route
336
335
  # information will be sent to Airbrake.
@@ -343,8 +342,7 @@ module Airbrake
343
342
  # func: 'do_stuff',
344
343
  # file: 'app/models/foo.rb',
345
344
  # line: 452,
346
- # start_time: timestamp,
347
- # end_time: Time.now
345
+ # timing: 123.45 # ms
348
346
  # )
349
347
  #
350
348
  # @param [Hash{Symbol=>Object}] request_info
@@ -358,8 +356,8 @@ module Airbrake
358
356
  # called the query (optional)
359
357
  # @option request_info [Integer] :line The line that executes the query
360
358
  # (optional)
361
- # @option request_info [Date] :start_time When the request started
362
- # @option request_info [Time] :end_time When the request ended (optional)
359
+ # @option request_info [Float] :timing How much time it took to process the
360
+ # request (in ms)
363
361
  # @param [Hash] stash What needs to be appeneded to the stash, so it's
364
362
  # available in filters
365
363
  # @return [void]
@@ -371,9 +369,8 @@ module Airbrake
371
369
  performance_notifier.notify(request)
372
370
  end
373
371
 
374
- # Synchronously Increments request statistics of a certain +route+ that was
375
- # invoked on +start_time+ and ended on +end_time+ with +method+, and
376
- # returned +status_code+.
372
+ # Synchronously increments request statistics of a certain +route+ invoked
373
+ # with +method+, which returned +status_code+.
377
374
  # @since v4.10.0
378
375
  # @see .notify_request
379
376
  def notify_request_sync(request_info, stash = {})
@@ -382,9 +379,8 @@ module Airbrake
382
379
  performance_notifier.notify_sync(request)
383
380
  end
384
381
 
385
- # Increments SQL statistics of a certain +query+ that was invoked on
386
- # +start_time+ and finished on +end_time+. When +method+ and +route+ are
387
- # provided, the query is grouped by these parameters.
382
+ # Increments SQL statistics of a certain +query+. When +method+ and +route+
383
+ # are provided, the query is grouped by these parameters.
388
384
  #
389
385
  # After a certain amount of time (n seconds) the aggregated query
390
386
  # information will be sent to Airbrake.
@@ -394,18 +390,17 @@ module Airbrake
394
390
  # method: 'GET',
395
391
  # route: '/things',
396
392
  # query: 'SELECT * FROM things',
397
- # start_time: timestamp,
398
- # end_time: Time.now
393
+ # timing: 123.45 # ms
399
394
  # )
400
395
  #
401
396
  # @param [Hash{Symbol=>Object}] query_info
402
- # @option request_info [String] :method The HTTP method that triggered this
397
+ # @option query_info [String] :method The HTTP method that triggered this
403
398
  # SQL query (optional)
404
- # @option request_info [String] :route The route that triggered this SQL
399
+ # @option query_info [String] :route The route that triggered this SQL
405
400
  # query (optional)
406
- # @option request_info [String] :query The query that was executed
407
- # @option request_info [Date] :start_time When the query started executing
408
- # @option request_info [Time] :end_time When the query finished (optional)
401
+ # @option query_info [String] :query The query that was executed
402
+ # @option query_info [Float] :timing How much time it took to process the
403
+ # query (in ms)
409
404
  # @param [Hash] stash What needs to be appeneded to the stash, so it's
410
405
  # available in filters
411
406
  # @return [void]
@@ -417,9 +412,9 @@ module Airbrake
417
412
  performance_notifier.notify(query)
418
413
  end
419
414
 
420
- # Synchronously increments SQL statistics of a certain +query+ that was
421
- # invoked on +start_time+ and finished on +end_time+. When +method+ and
422
- # +route+ are provided, the query is grouped by these parameters.
415
+ # Synchronously increments SQL statistics of a certain +query+. When
416
+ # +method+ and +route+ are provided, the query is grouped by these
417
+ # parameters.
423
418
  # @since v4.10.0
424
419
  # @see .notify_query
425
420
  def notify_query_sync(query_info, stash = {})
@@ -436,8 +431,7 @@ module Airbrake
436
431
  # route: '/thing/:id/create',
437
432
  # response_type: 'json',
438
433
  # groups: { db: 24.0, view: 0.4 }, # ms
439
- # start_time: timestamp,
440
- # end_time: Time.now
434
+ # timing: 123.45 # ms
441
435
  # )
442
436
  #
443
437
  # @param [Hash{Symbol=>Object}] breakdown_info
@@ -445,7 +439,8 @@ module Airbrake
445
439
  # @option breakdown_info [String] :route
446
440
  # @option breakdown_info [String] :response_type
447
441
  # @option breakdown_info [Array<Hash{Symbol=>Float}>] :groups
448
- # @option breakdown_info [Date] :start_time
442
+ # @option breakdown_info [Float] :timing How much time it took to process
443
+ # the performance breakdown (in ms)
449
444
  # @param [Hash] stash What needs to be appeneded to the stash, so it's
450
445
  # available in filters
451
446
  # @return [void]
@@ -481,6 +476,8 @@ module Airbrake
481
476
  # failed
482
477
  # @option queue_info [Array<Hash{Symbol=>Float}>] :groups Where the job
483
478
  # spent its time
479
+ # @option breakdown_info [Float] :timing How much time it took to process
480
+ # the queue (in ms)
484
481
  # @param [Hash] stash What needs to be appended to the stash, so it's
485
482
  # available in filters
486
483
  # @return [void]
@@ -2,7 +2,7 @@ module Airbrake
2
2
  # Benchmark benchmarks Ruby code.
3
3
  #
4
4
  # @since v4.2.4
5
- # @api private
5
+ # @api public
6
6
  class Benchmark
7
7
  # Measures monotonic time for the given operation.
8
8
  #
@@ -101,6 +101,12 @@ module Airbrake
101
101
  # @since v4.6.0
102
102
  attr_accessor :query_stats
103
103
 
104
+ # @return [Boolean] true if the library should send job/queue/worker stats
105
+ # to Airbrake, false otherwise
106
+ # @api public
107
+ # @since v4.12.0
108
+ attr_accessor :job_stats
109
+
104
110
  class << self
105
111
  # @return [Config]
106
112
  attr_writer :instance
@@ -139,6 +145,7 @@ module Airbrake
139
145
  self.performance_stats = true
140
146
  self.performance_stats_flush_period = 15
141
147
  self.query_stats = true
148
+ self.job_stats = true
142
149
 
143
150
  merge(user_config)
144
151
  end
@@ -213,6 +220,8 @@ module Airbrake
213
220
  promise.reject("The Performance Stats feature is disabled")
214
221
  elsif resource.is_a?(Airbrake::Query) && !query_stats
215
222
  promise.reject("The Query Stats feature is disabled")
223
+ elsif resource.is_a?(Airbrake::Queue) && !job_stats
224
+ promise.reject("The Job Stats feature is disabled")
216
225
  else
217
226
  promise
218
227
  end
@@ -55,7 +55,8 @@ module Airbrake
55
55
  def build_notice(exception, params = {})
56
56
  if @async_sender.closed?
57
57
  raise Airbrake::Error,
58
- "attempted to build #{exception} with closed Airbrake instance"
58
+ "Airbrake is closed; can't build exception: " \
59
+ "#{exception.class}: #{exception}"
59
60
  end
60
61
 
61
62
  if exception.is_a?(Airbrake::Notice)
@@ -7,7 +7,8 @@ module Airbrake
7
7
  # @since v4.2.0
8
8
  # rubocop:disable Metrics/BlockLength, Metrics/ParameterLists
9
9
  PerformanceBreakdown = Struct.new(
10
- :method, :route, :response_type, :groups, :start_time, :end_time
10
+ :method, :route, :response_type, :groups, :start_time, :end_time, :timing,
11
+ :time
11
12
  ) do
12
13
  include HashKeyable
13
14
  include Ignorable
@@ -19,11 +20,15 @@ module Airbrake
19
20
  route:,
20
21
  response_type:,
21
22
  groups:,
22
- start_time:,
23
- end_time: start_time + 1
23
+ start_time: Time.now,
24
+ end_time: start_time + 1,
25
+ timing: nil,
26
+ time: Time.now
24
27
  )
25
- @start_time_utc = TimeTruncate.utc_truncate_minutes(start_time)
26
- super(method, route, response_type, groups, start_time, end_time)
28
+ @time_utc = TimeTruncate.utc_truncate_minutes(time)
29
+ super(
30
+ method, route, response_type, groups, start_time, end_time, timing, time
31
+ )
27
32
  end
28
33
 
29
34
  def destination
@@ -39,7 +44,7 @@ module Airbrake
39
44
  'method' => method,
40
45
  'route' => route,
41
46
  'responseType' => response_type,
42
- 'time' => @start_time_utc,
47
+ 'time' => @time_utc,
43
48
  }.delete_if { |_key, val| val.nil? }
44
49
  end
45
50
  end
@@ -62,7 +62,7 @@ module Airbrake
62
62
  @payload[resource] = { total: Airbrake::Stat.new }
63
63
  end
64
64
 
65
- @payload[resource][:total].increment(resource.start_time, resource.end_time)
65
+ update_total(resource, @payload[resource][:total])
66
66
 
67
67
  resource.groups.each do |name, ms|
68
68
  @payload[resource][name] ||= Airbrake::Stat.new
@@ -70,6 +70,19 @@ module Airbrake
70
70
  end
71
71
  end
72
72
 
73
+ def update_total(resource, total)
74
+ if resource.timing
75
+ total.increment_ms(resource.timing)
76
+ else
77
+ loc = caller_locations(6..6).first
78
+ Kernel.warn(
79
+ "#{loc.path}:#{loc.lineno}: warning: :start_time and :end_time are " \
80
+ "deprecated. Use :timing & :time instead",
81
+ )
82
+ total.increment(resource.start_time, resource.end_time)
83
+ end
84
+ end
85
+
73
86
  def schedule_flush
74
87
  return if @payload.empty?
75
88
 
@@ -107,14 +120,13 @@ module Airbrake
107
120
  end
108
121
 
109
122
  def send_resource(resource, sync:)
110
- promise = @config.check_configuration
111
- return promise if promise.rejected?
112
-
113
- promise = @config.check_performance_options(resource)
123
+ promise = check_configuration(resource)
114
124
  return promise if promise.rejected?
115
125
 
116
126
  @filter_chain.refine(resource)
117
- return if resource.ignored?
127
+ if resource.ignored?
128
+ return Promise.new.reject("#{resource.class} was ignored by a filter")
129
+ end
118
130
 
119
131
  @mutex.synchronize do
120
132
  update_payload(resource)
@@ -126,6 +138,20 @@ module Airbrake
126
138
  end
127
139
  end
128
140
 
141
+ def check_configuration(resource)
142
+ promise = @config.check_configuration
143
+ return promise if promise.rejected?
144
+
145
+ promise = @config.check_performance_options(resource)
146
+ return promise if promise.rejected?
147
+
148
+ if resource.timing && resource.timing == 0
149
+ return Promise.new.reject(':timing cannot be zero')
150
+ end
151
+
152
+ Promise.new
153
+ end
154
+
129
155
  def send(sender, payload, promise)
130
156
  signature = "#{self.class.name}##{__method__}"
131
157
  raise "#{signature}: payload (#{payload}) cannot be empty. Race?" if payload.none?
@@ -6,7 +6,8 @@ module Airbrake
6
6
  # @since v3.2.0
7
7
  # rubocop:disable Metrics/ParameterLists, Metrics/BlockLength
8
8
  Query = Struct.new(
9
- :method, :route, :query, :func, :file, :line, :start_time, :end_time
9
+ :method, :route, :query, :func, :file, :line, :start_time, :end_time,
10
+ :timing, :time
10
11
  ) do
11
12
  include HashKeyable
12
13
  include Ignorable
@@ -21,11 +22,16 @@ module Airbrake
21
22
  func: nil,
22
23
  file: nil,
23
24
  line: nil,
24
- start_time:,
25
- end_time: start_time + 1
25
+ start_time: Time.now,
26
+ end_time: start_time + 1,
27
+ timing: nil,
28
+ time: Time.now
26
29
  )
27
- @start_time_utc = TimeTruncate.utc_truncate_minutes(start_time)
28
- super(method, route, query, func, file, line, start_time, end_time)
30
+ @time_utc = TimeTruncate.utc_truncate_minutes(time)
31
+ super(
32
+ method, route, query, func, file, line, start_time, end_time, timing,
33
+ time
34
+ )
29
35
  end
30
36
 
31
37
  def destination
@@ -41,7 +47,7 @@ module Airbrake
41
47
  'method' => method,
42
48
  'route' => route,
43
49
  'query' => query,
44
- 'time' => @start_time_utc,
50
+ 'time' => @time_utc,
45
51
  'function' => func,
46
52
  'file' => file,
47
53
  'line' => line,
@@ -4,8 +4,10 @@ module Airbrake
4
4
  # @see Airbrake.notify_queue
5
5
  # @api public
6
6
  # @since v4.9.0
7
- # rubocop:disable Metrics/BlockLength
8
- Queue = Struct.new(:queue, :error_count, :groups, :start_time, :end_time) do
7
+ # rubocop:disable Metrics/BlockLength, Metrics/ParameterLists
8
+ Queue = Struct.new(
9
+ :queue, :error_count, :groups, :start_time, :end_time, :timing, :time
10
+ ) do
9
11
  include HashKeyable
10
12
  include Ignorable
11
13
  include Stashable
@@ -15,10 +17,12 @@ module Airbrake
15
17
  error_count:,
16
18
  groups: {},
17
19
  start_time: Time.now,
18
- end_time: start_time + 1
20
+ end_time: start_time + 1,
21
+ timing: nil,
22
+ time: Time.now
19
23
  )
20
- @start_time_utc = TimeTruncate.utc_truncate_minutes(start_time)
21
- super(queue, error_count, groups, start_time, end_time)
24
+ @time_utc = TimeTruncate.utc_truncate_minutes(time)
25
+ super(queue, error_count, groups, start_time, end_time, timing, time)
22
26
  end
23
27
 
24
28
  def destination
@@ -33,14 +37,14 @@ module Airbrake
33
37
  {
34
38
  'queue' => queue,
35
39
  'errorCount' => error_count,
36
- 'time' => @start_time_utc,
40
+ 'time' => @time_utc,
37
41
  }
38
42
  end
39
43
 
40
44
  def hash
41
45
  {
42
46
  'queue' => queue,
43
- 'time' => @start_time_utc,
47
+ 'time' => @time_utc,
44
48
  }.hash
45
49
  end
46
50
 
@@ -48,5 +52,5 @@ module Airbrake
48
52
  self.error_count += other.error_count
49
53
  end
50
54
  end
51
- # rubocop:enable Metrics/BlockLength
55
+ # rubocop:enable Metrics/BlockLength, Metrics/ParameterLists
52
56
  end
@@ -4,8 +4,10 @@ module Airbrake
4
4
  # @see Airbrake.notify_request
5
5
  # @api public
6
6
  # @since v3.2.0
7
- # rubocop:disable Metrics/BlockLength
8
- Request = Struct.new(:method, :route, :status_code, :start_time, :end_time) do
7
+ # rubocop:disable Metrics/BlockLength, Metrics/ParameterLists
8
+ Request = Struct.new(
9
+ :method, :route, :status_code, :start_time, :end_time, :timing, :time
10
+ ) do
9
11
  include HashKeyable
10
12
  include Ignorable
11
13
  include Stashable
@@ -16,11 +18,13 @@ module Airbrake
16
18
  method:,
17
19
  route:,
18
20
  status_code:,
19
- start_time:,
20
- end_time: start_time + 1
21
+ start_time: Time.now,
22
+ end_time: start_time + 1,
23
+ timing: nil,
24
+ time: Time.now
21
25
  )
22
- @start_time_utc = TimeTruncate.utc_truncate_minutes(start_time)
23
- super(method, route, status_code, start_time, end_time)
26
+ @time_utc = TimeTruncate.utc_truncate_minutes(time)
27
+ super(method, route, status_code, start_time, end_time, timing, time)
24
28
  end
25
29
 
26
30
  def destination
@@ -36,9 +40,9 @@ module Airbrake
36
40
  'method' => method,
37
41
  'route' => route,
38
42
  'statusCode' => status_code,
39
- 'time' => @start_time_utc,
43
+ 'time' => @time_utc,
40
44
  }.delete_if { |_key, val| val.nil? }
41
45
  end
42
46
  end
43
- # rubocop:enable Metrics/BlockLength
47
+ # rubocop:enable Metrics/BlockLength, Metrics/ParameterLists
44
48
  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.10.1'.freeze
5
+ AIRBRAKE_RUBY_VERSION = '4.12.0'.freeze
6
6
  end
@@ -171,7 +171,7 @@ RSpec.describe Airbrake do
171
171
  method: 'GET',
172
172
  route: '/',
173
173
  status_code: 200,
174
- start_time: Time.now,
174
+ timing: 1,
175
175
  )
176
176
  end
177
177
  end
@@ -187,7 +187,7 @@ RSpec.describe Airbrake do
187
187
  method: 'GET',
188
188
  route: '/',
189
189
  status_code: 200,
190
- start_time: Time.now,
190
+ timing: 1,
191
191
  },
192
192
  request_id: 1,
193
193
  )
@@ -204,7 +204,7 @@ RSpec.describe Airbrake do
204
204
  method: 'GET',
205
205
  route: '/',
206
206
  status_code: 200,
207
- start_time: Time.now,
207
+ timing: 1,
208
208
  },
209
209
  request_id: 1,
210
210
  )
@@ -222,7 +222,7 @@ RSpec.describe Airbrake do
222
222
  method: 'GET',
223
223
  route: '/',
224
224
  query: '',
225
- start_time: Time.now,
225
+ timing: 1,
226
226
  )
227
227
  end
228
228
  end
@@ -238,7 +238,7 @@ RSpec.describe Airbrake do
238
238
  method: 'GET',
239
239
  route: '/',
240
240
  query: '',
241
- start_time: Time.now,
241
+ timing: 1,
242
242
  },
243
243
  request_id: 1,
244
244
  )
@@ -255,7 +255,7 @@ RSpec.describe Airbrake do
255
255
  method: 'GET',
256
256
  route: '/',
257
257
  query: '',
258
- start_time: Time.now,
258
+ timing: 1,
259
259
  },
260
260
  request_id: 1,
261
261
  )
@@ -273,7 +273,7 @@ RSpec.describe Airbrake do
273
273
  method: 'GET',
274
274
  route: '/',
275
275
  query: '',
276
- start_time: Time.now,
276
+ timing: 1,
277
277
  )
278
278
  end
279
279
  end
@@ -292,7 +292,7 @@ RSpec.describe Airbrake do
292
292
  route: '/',
293
293
  response_type: :html,
294
294
  groups: {},
295
- start_time: Time.now,
295
+ timing: 1,
296
296
  },
297
297
  request_id: 1,
298
298
  )
@@ -310,7 +310,7 @@ RSpec.describe Airbrake do
310
310
  route: '/',
311
311
  response_type: :html,
312
312
  groups: {},
313
- start_time: Time.now,
313
+ timing: 1,
314
314
  },
315
315
  request_id: 1,
316
316
  )
@@ -22,6 +22,7 @@ RSpec.describe Airbrake::Config do
22
22
  its(:performance_stats) { is_expected.to eq(true) }
23
23
  its(:performance_stats_flush_period) { is_expected.to eq(15) }
24
24
  its(:query_stats) { is_expected.to eq(true) }
25
+ its(:job_stats) { is_expected.to eq(true) }
25
26
 
26
27
  describe "#new" do
27
28
  context "when user config is passed" do
@@ -110,9 +111,7 @@ RSpec.describe Airbrake::Config do
110
111
 
111
112
  describe "#check_performance_options" do
112
113
  it "returns a promise" do
113
- resource = Airbrake::Query.new(
114
- method: '', route: '', query: '', start_time: Time.now,
115
- )
114
+ resource = Airbrake::Query.new(method: '', route: '', query: '', timing: 1)
116
115
  expect(subject.check_performance_options(resource))
117
116
  .to be_an(Airbrake::Promise)
118
117
  end
@@ -122,7 +121,7 @@ RSpec.describe Airbrake::Config do
122
121
 
123
122
  let(:resource) do
124
123
  Airbrake::Request.new(
125
- method: 'GET', route: '/foo', status_code: 200, start_time: Time.new,
124
+ method: 'GET', route: '/foo', status_code: 200, timing: 1,
126
125
  )
127
126
  end
128
127
 
@@ -138,9 +137,7 @@ RSpec.describe Airbrake::Config do
138
137
  before { subject.query_stats = false }
139
138
 
140
139
  let(:resource) do
141
- Airbrake::Query.new(
142
- method: 'GET', route: '/foo', query: '', start_time: Time.new,
143
- )
140
+ Airbrake::Query.new(method: 'GET', route: '/foo', query: '', timing: 1)
144
141
  end
145
142
 
146
143
  it "returns a rejected promise" do
@@ -150,5 +147,20 @@ RSpec.describe Airbrake::Config do
150
147
  )
151
148
  end
152
149
  end
150
+
151
+ context "when job stats are disabled" do
152
+ before { subject.job_stats = false }
153
+
154
+ let(:resource) do
155
+ Airbrake::Queue.new(queue: 'foo_queue', error_count: 0, timing: 1)
156
+ end
157
+
158
+ it "returns a rejected promise" do
159
+ promise = subject.check_performance_options(resource)
160
+ expect(promise.value).to eq(
161
+ 'error' => "The Job Stats feature is disabled",
162
+ )
163
+ end
164
+ end
153
165
  end
154
166
  end
@@ -13,9 +13,7 @@ RSpec.describe Airbrake::Filters::SqlFilter do
13
13
  shared_examples "query blacklisting" do |query, opts|
14
14
  it "ignores '#{query}'" do
15
15
  filter = described_class.new('postgres')
16
- q = Airbrake::Query.new(
17
- query: query, method: 'GET', route: '/', start_time: Time.now,
18
- )
16
+ q = Airbrake::Query.new(query: query, method: 'GET', route: '/', timing: 1)
19
17
  filter.call(q)
20
18
 
21
19
  expect(q.ignored?).to eq(opts[:should_ignore])
@@ -328,9 +328,9 @@ RSpec.describe Airbrake::NoticeNotifier do
328
328
  end
329
329
 
330
330
  it "raises error" do
331
- expect { subject.build_notice(Exception.new) }.to raise_error(
331
+ expect { subject.build_notice(Exception.new('oops')) }.to raise_error(
332
332
  Airbrake::Error,
333
- 'attempted to build Exception with closed Airbrake instance',
333
+ "Airbrake is closed; can't build exception: Exception: oops",
334
334
  )
335
335
  end
336
336
  end
@@ -16,6 +16,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
16
16
  performance_stats: true,
17
17
  performance_stats_flush_period: 0,
18
18
  query_stats: true,
19
+ job_stats: true,
19
20
  )
20
21
  end
21
22
 
@@ -29,8 +30,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
29
30
  func: 'foo',
30
31
  file: 'foo.rb',
31
32
  line: 123,
32
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
33
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
33
+ timing: 60000,
34
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
34
35
  ),
35
36
  )
36
37
  subject.close
@@ -59,8 +60,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
59
60
  method: 'POST',
60
61
  route: '/foo',
61
62
  status_code: 200,
62
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
63
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
63
+ timing: 60000,
64
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
64
65
  ),
65
66
  )
66
67
  subject.close
@@ -86,8 +87,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
86
87
  method: 'DELETE',
87
88
  route: '/routes-breakdowns',
88
89
  response_type: 'json',
89
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
90
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
90
+ timing: 60000,
91
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
91
92
  groups: { db: 131, view: 421 },
92
93
  ),
93
94
  )
@@ -128,8 +129,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
128
129
  queue: 'emails',
129
130
  error_count: 2,
130
131
  groups: { redis: 131, sql: 421 },
131
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
132
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
132
+ timing: 60000,
133
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
133
134
  ),
134
135
  )
135
136
  subject.close
@@ -168,7 +169,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
168
169
  method: 'GET',
169
170
  route: '/foo',
170
171
  status_code: 200,
171
- start_time: Time.new(2018, 1, 1, 0, 0, 20, 0),
172
+ timing: 60000,
173
+ time: Time.new(2018, 1, 1, 0, 0, 20, 0),
172
174
  ),
173
175
  )
174
176
  subject.close
@@ -184,7 +186,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
184
186
  method: 'GET',
185
187
  route: '/foo',
186
188
  status_code: 200,
187
- start_time: Time.new(2018, 1, 1, 0, 0, 20, 0),
189
+ timing: 213,
188
190
  ),
189
191
  )
190
192
  subject.notify(
@@ -192,7 +194,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
192
194
  method: 'GET',
193
195
  route: '/foo',
194
196
  status_code: 200,
195
- start_time: Time.new(2018, 1, 1, 0, 0, 50, 0),
197
+ timing: 123,
196
198
  ),
197
199
  )
198
200
  subject.close
@@ -208,8 +210,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
208
210
  method: 'GET',
209
211
  route: '/foo',
210
212
  status_code: 200,
211
- start_time: Time.new(2018, 1, 1, 0, 0, 49, 0),
212
- end_time: Time.new(2018, 1, 1, 0, 0, 50, 0),
213
+ timing: 1000,
214
+ time: Time.new(2018, 1, 1, 0, 0, 49, 0),
213
215
  ),
214
216
  )
215
217
  subject.notify(
@@ -217,8 +219,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
217
219
  method: 'GET',
218
220
  route: '/foo',
219
221
  status_code: 200,
220
- start_time: Time.new(2018, 1, 1, 0, 1, 49, 0),
221
- end_time: Time.new(2018, 1, 1, 0, 1, 55, 0),
222
+ timing: 6000,
223
+ time: Time.new(2018, 1, 1, 0, 1, 49, 0),
222
224
  ),
223
225
  )
224
226
  subject.close
@@ -244,8 +246,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
244
246
  method: 'GET',
245
247
  route: '/foo',
246
248
  status_code: 200,
247
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
248
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
249
+ timing: 60000,
250
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
249
251
  ),
250
252
  )
251
253
  subject.notify(
@@ -253,8 +255,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
253
255
  method: 'POST',
254
256
  route: '/foo',
255
257
  status_code: 200,
256
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
257
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
258
+ timing: 60000,
259
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
258
260
  ),
259
261
  )
260
262
  subject.close
@@ -280,8 +282,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
280
282
  method: 'DELETE',
281
283
  route: '/routes-breakdowns',
282
284
  response_type: 'json',
283
- start_time: Time.new(2018, 1, 1, 0, 0, 20, 0),
284
- end_time: Time.new(2018, 1, 1, 0, 0, 22, 0),
285
+ timing: 2000,
286
+ time: Time.new(2018, 1, 1, 0, 0, 20, 0),
285
287
  groups: { db: 131, view: 421 },
286
288
  ),
287
289
  )
@@ -290,8 +292,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
290
292
  method: 'DELETE',
291
293
  route: '/routes-breakdowns',
292
294
  response_type: 'json',
293
- start_time: Time.new(2018, 1, 1, 0, 0, 30, 0),
294
- end_time: Time.new(2018, 1, 1, 0, 0, 32, 0),
295
+ timing: 2000,
296
+ time: Time.new(2018, 1, 1, 0, 0, 30, 0),
295
297
  groups: { db: 55, view: 11 },
296
298
  ),
297
299
  )
@@ -332,8 +334,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
332
334
  queue: 'emails',
333
335
  error_count: 2,
334
336
  groups: { redis: 131, sql: 421 },
335
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
336
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
337
+ timing: 60000,
338
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
337
339
  ),
338
340
  )
339
341
  subject.notify(
@@ -341,8 +343,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
341
343
  queue: 'emails',
342
344
  error_count: 3,
343
345
  groups: { redis: 131, sql: 421 },
344
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
345
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
346
+ timing: 60000,
347
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
346
348
  ),
347
349
  )
348
350
  subject.close
@@ -381,7 +383,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
381
383
  method: 'GET',
382
384
  route: '/foo',
383
385
  status_code: 200,
384
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
386
+ timing: 123,
385
387
  ),
386
388
  )
387
389
  subject.close
@@ -392,7 +394,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
392
394
 
393
395
  it "checks performance stat configuration" do
394
396
  request = Airbrake::Request.new(
395
- method: 'GET', route: '/foo', status_code: 200, start_time: Time.new,
397
+ method: 'GET', route: '/foo', status_code: 200, timing: 123,
396
398
  )
397
399
  expect(Airbrake::Config.instance).to receive(:check_performance_options)
398
400
  .with(request).and_return(Airbrake::Promise.new)
@@ -408,7 +410,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
408
410
  method: 'POST',
409
411
  route: '/foo',
410
412
  status_code: 200,
411
- start_time: Time.new,
413
+ timing: 123,
412
414
  ),
413
415
  )
414
416
  subject.close
@@ -445,7 +447,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
445
447
  method: 'GET',
446
448
  route: '/foo',
447
449
  status_code: 200,
448
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
450
+ timing: 123,
449
451
  ),
450
452
  )
451
453
 
@@ -454,7 +456,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
454
456
  method: 'POST',
455
457
  route: '/foo',
456
458
  query: 'SELECT * FROM things',
457
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
459
+ timing: 123,
458
460
  ),
459
461
  )
460
462
 
@@ -474,7 +476,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
474
476
  method: 'GET',
475
477
  route: '/foo',
476
478
  status_code: 200,
477
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
479
+ timing: 1,
478
480
  ),
479
481
  )
480
482
  subject.close
@@ -488,13 +490,29 @@ RSpec.describe Airbrake::PerformanceNotifier do
488
490
  method: 'POST',
489
491
  route: '/foo',
490
492
  query: 'SELECT * FROM things',
491
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
493
+ timing: 1,
492
494
  ),
493
495
  )
494
496
  subject.close
495
497
 
496
498
  expect(a_request(:put, queries)).not_to have_been_made
497
499
  end
500
+
501
+ it "returns a rejected promise" do
502
+ promise = subject.notify(
503
+ Airbrake::Query.new(
504
+ method: 'POST',
505
+ route: '/foo',
506
+ query: 'SELECT * FROM things',
507
+ timing: 1,
508
+ ),
509
+ )
510
+ subject.close
511
+
512
+ expect(promise.value).to eq(
513
+ 'error' => 'Airbrake::Query was ignored by a filter',
514
+ )
515
+ end
498
516
  end
499
517
 
500
518
  context "when a filter that modifies payload was defined" do
@@ -510,7 +528,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
510
528
  method: 'POST',
511
529
  route: '/foo',
512
530
  query: 'SELECT * FROM things',
513
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
531
+ timing: 123,
514
532
  ),
515
533
  )
516
534
  subject.close
@@ -522,6 +540,49 @@ RSpec.describe Airbrake::PerformanceNotifier do
522
540
  ).to have_been_made
523
541
  end
524
542
  end
543
+
544
+ context "when :start_time is specified (deprecated)" do
545
+ before do
546
+ allow(Kernel).to receive(:warn)
547
+ end
548
+
549
+ it "uses the value of :start_time to update stat" do
550
+ subject.notify(
551
+ Airbrake::Query.new(
552
+ method: 'POST',
553
+ route: '/foo',
554
+ query: 'SELECT * FROM things',
555
+ start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
556
+ end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
557
+ ),
558
+ )
559
+ subject.close
560
+
561
+ expect(
562
+ a_request(:put, queries).with(
563
+ body: /"count":1,"sum":60000.0,"sumsq":3600000000.0/,
564
+ ),
565
+ ).to have_been_made
566
+ end
567
+ end
568
+
569
+ context "when provided :timing is zero" do
570
+ it "doesn't notify" do
571
+ queue = Airbrake::Queue.new(queue: 'bananas', error_count: 0, timing: 0)
572
+ subject.notify(queue)
573
+ subject.close
574
+
575
+ expect(a_request(:put, queues)).not_to have_been_made
576
+ end
577
+
578
+ it "returns a rejected promise" do
579
+ queue = Airbrake::Queue.new(queue: 'bananas', error_count: 0, timing: 0)
580
+ promise = subject.notify(queue)
581
+ subject.close
582
+
583
+ expect(promise.value).to eq('error' => ':timing cannot be zero')
584
+ end
585
+ end
525
586
  end
526
587
 
527
588
  describe "#notify_sync" do
@@ -531,7 +592,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
531
592
  method: 'POST',
532
593
  route: '/foo',
533
594
  query: 'SELECT * FROM things',
534
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
595
+ timing: 123,
535
596
  ),
536
597
  )
537
598
 
@@ -560,7 +621,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
560
621
  method: 'POST',
561
622
  route: '/foo',
562
623
  query: 'SELECT * FROM things',
563
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
624
+ timing: 123,
564
625
  ),
565
626
  )
566
627
  subject.close
@@ -591,7 +652,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
591
652
  method: 'POST',
592
653
  route: '/foo',
593
654
  status_code: 200,
594
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
655
+ timing: 123,
595
656
  ),
596
657
  )
597
658
  subject.close
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.10.1
4
+ version: 4.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Airbrake Technologies, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-12 00:00:00.000000000 Z
11
+ date: 2020-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbtree3