airbrake-ruby 4.1.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +5 -5
  2. data/lib/airbrake-ruby/async_sender.rb +22 -96
  3. data/lib/airbrake-ruby/backtrace.rb +8 -7
  4. data/lib/airbrake-ruby/benchmark.rb +39 -0
  5. data/lib/airbrake-ruby/code_hunk.rb +1 -1
  6. data/lib/airbrake-ruby/config/processor.rb +84 -0
  7. data/lib/airbrake-ruby/config/validator.rb +9 -3
  8. data/lib/airbrake-ruby/config.rb +76 -20
  9. data/lib/airbrake-ruby/deploy_notifier.rb +1 -1
  10. data/lib/airbrake-ruby/file_cache.rb +6 -0
  11. data/lib/airbrake-ruby/filter_chain.rb +16 -1
  12. data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
  13. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +2 -2
  14. data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
  15. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +5 -5
  16. data/lib/airbrake-ruby/filters/git_repository_filter.rb +3 -0
  17. data/lib/airbrake-ruby/filters/git_revision_filter.rb +2 -0
  18. data/lib/airbrake-ruby/filters/{keys_whitelist.rb → keys_allowlist.rb} +3 -3
  19. data/lib/airbrake-ruby/filters/{keys_blacklist.rb → keys_blocklist.rb} +3 -3
  20. data/lib/airbrake-ruby/filters/keys_filter.rb +39 -20
  21. data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
  22. data/lib/airbrake-ruby/filters/sql_filter.rb +30 -6
  23. data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
  24. data/lib/airbrake-ruby/filters/thread_filter.rb +4 -2
  25. data/lib/airbrake-ruby/grouppable.rb +12 -0
  26. data/lib/airbrake-ruby/ignorable.rb +1 -0
  27. data/lib/airbrake-ruby/inspectable.rb +2 -2
  28. data/lib/airbrake-ruby/loggable.rb +2 -2
  29. data/lib/airbrake-ruby/mergeable.rb +12 -0
  30. data/lib/airbrake-ruby/monotonic_time.rb +48 -0
  31. data/lib/airbrake-ruby/notice.rb +10 -20
  32. data/lib/airbrake-ruby/notice_notifier.rb +23 -42
  33. data/lib/airbrake-ruby/performance_breakdown.rb +52 -0
  34. data/lib/airbrake-ruby/performance_notifier.rb +126 -49
  35. data/lib/airbrake-ruby/promise.rb +1 -0
  36. data/lib/airbrake-ruby/query.rb +26 -11
  37. data/lib/airbrake-ruby/queue.rb +65 -0
  38. data/lib/airbrake-ruby/remote_settings/settings_data.rb +120 -0
  39. data/lib/airbrake-ruby/remote_settings.rb +145 -0
  40. data/lib/airbrake-ruby/request.rb +20 -6
  41. data/lib/airbrake-ruby/stashable.rb +15 -0
  42. data/lib/airbrake-ruby/stat.rb +34 -24
  43. data/lib/airbrake-ruby/sync_sender.rb +3 -2
  44. data/lib/airbrake-ruby/tdigest.rb +43 -58
  45. data/lib/airbrake-ruby/thread_pool.rb +138 -0
  46. data/lib/airbrake-ruby/timed_trace.rb +58 -0
  47. data/lib/airbrake-ruby/truncator.rb +10 -4
  48. data/lib/airbrake-ruby/version.rb +11 -1
  49. data/lib/airbrake-ruby.rb +219 -53
  50. data/spec/airbrake_spec.rb +428 -9
  51. data/spec/async_sender_spec.rb +26 -110
  52. data/spec/backtrace_spec.rb +44 -44
  53. data/spec/benchmark_spec.rb +33 -0
  54. data/spec/code_hunk_spec.rb +11 -11
  55. data/spec/config/processor_spec.rb +209 -0
  56. data/spec/config/validator_spec.rb +23 -6
  57. data/spec/config_spec.rb +77 -7
  58. data/spec/deploy_notifier_spec.rb +2 -2
  59. data/spec/{file_cache.rb → file_cache_spec.rb} +2 -4
  60. data/spec/filter_chain_spec.rb +28 -1
  61. data/spec/filters/dependency_filter_spec.rb +1 -1
  62. data/spec/filters/gem_root_filter_spec.rb +9 -9
  63. data/spec/filters/git_last_checkout_filter_spec.rb +21 -4
  64. data/spec/filters/git_repository_filter.rb +1 -1
  65. data/spec/filters/git_revision_filter_spec.rb +13 -11
  66. data/spec/filters/{keys_whitelist_spec.rb → keys_allowlist_spec.rb} +29 -28
  67. data/spec/filters/{keys_blacklist_spec.rb → keys_blocklist_spec.rb} +39 -29
  68. data/spec/filters/root_directory_filter_spec.rb +9 -9
  69. data/spec/filters/sql_filter_spec.rb +110 -55
  70. data/spec/filters/system_exit_filter_spec.rb +1 -1
  71. data/spec/filters/thread_filter_spec.rb +33 -31
  72. data/spec/fixtures/project_root/code.rb +9 -9
  73. data/spec/loggable_spec.rb +17 -0
  74. data/spec/monotonic_time_spec.rb +23 -0
  75. data/spec/{notice_notifier_spec → notice_notifier}/options_spec.rb +19 -21
  76. data/spec/notice_notifier_spec.rb +20 -80
  77. data/spec/notice_spec.rb +9 -11
  78. data/spec/performance_breakdown_spec.rb +11 -0
  79. data/spec/performance_notifier_spec.rb +360 -85
  80. data/spec/query_spec.rb +11 -0
  81. data/spec/queue_spec.rb +18 -0
  82. data/spec/remote_settings/settings_data_spec.rb +365 -0
  83. data/spec/remote_settings_spec.rb +230 -0
  84. data/spec/request_spec.rb +9 -0
  85. data/spec/response_spec.rb +8 -8
  86. data/spec/spec_helper.rb +9 -13
  87. data/spec/stashable_spec.rb +23 -0
  88. data/spec/stat_spec.rb +17 -15
  89. data/spec/sync_sender_spec.rb +14 -12
  90. data/spec/tdigest_spec.rb +6 -6
  91. data/spec/thread_pool_spec.rb +187 -0
  92. data/spec/timed_trace_spec.rb +125 -0
  93. data/spec/truncator_spec.rb +12 -12
  94. metadata +55 -18
@@ -0,0 +1,58 @@
1
+ module Airbrake
2
+ # TimedTrace represents a chunk of code performance of which was measured and
3
+ # stored under a label. The chunk is called a "span".
4
+ #
5
+ # @example
6
+ # timed_trace = TimedTrace.new
7
+ # timed_trace.span('http request') do
8
+ # http.get('example.com')
9
+ # end
10
+ # timed_trace.spans #=> { 'http request' => 0.123 }
11
+ #
12
+ # @api public
13
+ # @since v4.3.0
14
+ class TimedTrace
15
+ # @param [String] label
16
+ # @return [Airbrake::TimedTrace]
17
+ def self.span(label, &block)
18
+ new.tap { |timed_trace| timed_trace.span(label, &block) }
19
+ end
20
+
21
+ def initialize
22
+ @spans = {}
23
+ end
24
+
25
+ # @param [String] label
26
+ # @return [Boolean]
27
+ def span(label)
28
+ start_span(label)
29
+ yield
30
+ stop_span(label)
31
+ end
32
+
33
+ # @param [String] label
34
+ # @return [Boolean]
35
+ def start_span(label)
36
+ return false if @spans.key?(label)
37
+
38
+ @spans[label] = Airbrake::Benchmark.new
39
+ true
40
+ end
41
+
42
+ # @param [String] label
43
+ # @return [Boolean]
44
+ def stop_span(label)
45
+ return false unless @spans.key?(label)
46
+
47
+ @spans[label].stop
48
+ true
49
+ end
50
+
51
+ # @return [Hash<String=>Float>]
52
+ def spans
53
+ @spans.each_with_object({}) do |(label, benchmark), new_spans|
54
+ new_spans[label] = benchmark.duration
55
+ end
56
+ end
57
+ end
58
+ 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,13 +110,12 @@ 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
111
- temp_str.encode!(TEMP_ENCODING, ENCODING_OPTIONS) if utf8_string
112
- temp_str.encode!('utf-8', ENCODING_OPTIONS)
117
+ temp_str.encode!(TEMP_ENCODING, **ENCODING_OPTIONS) if utf8_string
118
+ temp_str.encode!('utf-8', **ENCODING_OPTIONS)
113
119
  end
114
120
  end
115
121
  end
@@ -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.1.0'.freeze
5
+ # @api public
6
+ AIRBRAKE_RUBY_VERSION = '5.0.0'.freeze
7
+
8
+ # @return [Hash{Symbol=>String}] the information about the notifier library
9
+ # @since 5.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
@@ -1,16 +1,22 @@
1
1
  require 'net/https'
2
2
  require 'logger'
3
3
  require 'json'
4
- require 'thread'
5
4
  require 'set'
6
5
  require 'socket'
7
6
  require 'time'
8
7
 
9
8
  require 'airbrake-ruby/version'
10
9
  require 'airbrake-ruby/loggable'
10
+ require 'airbrake-ruby/stashable'
11
+ require 'airbrake-ruby/mergeable'
12
+ require 'airbrake-ruby/grouppable'
11
13
  require 'airbrake-ruby/config'
12
14
  require 'airbrake-ruby/config/validator'
15
+ require 'airbrake-ruby/config/processor'
16
+ require 'airbrake-ruby/remote_settings/settings_data'
17
+ require 'airbrake-ruby/remote_settings'
13
18
  require 'airbrake-ruby/promise'
19
+ require 'airbrake-ruby/thread_pool'
14
20
  require 'airbrake-ruby/sync_sender'
15
21
  require 'airbrake-ruby/async_sender'
16
22
  require 'airbrake-ruby/response'
@@ -21,8 +27,8 @@ require 'airbrake-ruby/notice'
21
27
  require 'airbrake-ruby/backtrace'
22
28
  require 'airbrake-ruby/truncator'
23
29
  require 'airbrake-ruby/filters/keys_filter'
24
- require 'airbrake-ruby/filters/keys_whitelist'
25
- require 'airbrake-ruby/filters/keys_blacklist'
30
+ require 'airbrake-ruby/filters/keys_allowlist'
31
+ require 'airbrake-ruby/filters/keys_blocklist'
26
32
  require 'airbrake-ruby/filters/gem_root_filter'
27
33
  require 'airbrake-ruby/filters/system_exit_filter'
28
34
  require 'airbrake-ruby/filters/root_directory_filter'
@@ -46,6 +52,11 @@ require 'airbrake-ruby/time_truncate'
46
52
  require 'airbrake-ruby/tdigest'
47
53
  require 'airbrake-ruby/query'
48
54
  require 'airbrake-ruby/request'
55
+ require 'airbrake-ruby/performance_breakdown'
56
+ require 'airbrake-ruby/benchmark'
57
+ require 'airbrake-ruby/monotonic_time'
58
+ require 'airbrake-ruby/timed_trace'
59
+ require 'airbrake-ruby/queue'
49
60
 
50
61
  # Airbrake is a thin wrapper around instances of the notifier classes (such as
51
62
  # notice, performance & deploy notifiers). It creates a way to access them via a
@@ -63,6 +74,7 @@ require 'airbrake-ruby/request'
63
74
  #
64
75
  # @since v1.0.0
65
76
  # @api public
77
+ # rubocop:disable Metrics/ModuleLength
66
78
  module Airbrake
67
79
  # The general error that this library uses when it wants to raise.
68
80
  Error = Class.new(StandardError)
@@ -74,14 +86,26 @@ module Airbrake
74
86
  # special cases where we need to work around older implementations
75
87
  JRUBY = (RUBY_ENGINE == 'jruby')
76
88
 
77
- # @!macro see_public_api_method
78
- # @see Airbrake.$0
79
-
80
- @performance_notifier = PerformanceNotifier.new
81
- @notice_notifier = NoticeNotifier.new
82
- @deploy_notifier = DeployNotifier.new
89
+ # @return [Boolean] true if this Ruby supports safe levels and tainting,
90
+ # to guard against using deprecated or unsupported features.
91
+ HAS_SAFE_LEVEL = (
92
+ RUBY_ENGINE == 'ruby' &&
93
+ Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7')
94
+ )
83
95
 
84
96
  class << self
97
+ # @since v4.2.3
98
+ # @api private
99
+ attr_writer :performance_notifier
100
+
101
+ # @since v4.2.3
102
+ # @api private
103
+ attr_writer :notice_notifier
104
+
105
+ # @since v4.2.3
106
+ # @api private
107
+ attr_writer :deploy_notifier
108
+
85
109
  # Configures the Airbrake notifier.
86
110
  #
87
111
  # @example
@@ -90,28 +114,45 @@ module Airbrake
90
114
  # c.project_key = 'fd04e13d806a90f96614ad8e529b2822'
91
115
  # end
92
116
  #
93
- # @yield [config] The configuration object
117
+ # @yield [config]
94
118
  # @yieldparam config [Airbrake::Config]
95
119
  # @return [void]
96
- # @raise [Airbrake::Error] when trying to reconfigure already
97
- # existing notifier
98
- # @raise [Airbrake::Error] when either +project_id+ or +project_key+
99
- # is missing (or both)
100
- # @note There's no way to read config values outside of this library
101
120
  def configure
102
121
  yield config = Airbrake::Config.instance
122
+ Airbrake::Loggable.instance = config.logger
103
123
 
104
- if (result = config.validate).rejected?
105
- raise Airbrake::Error, result.value['error']
106
- end
124
+ config_processor = Airbrake::Config::Processor.new(config)
107
125
 
108
- Airbrake::Loggable.instance = config.logger
126
+ config_processor.process_blocklist(notice_notifier)
127
+ config_processor.process_allowlist(notice_notifier)
128
+
129
+ @remote_settings ||= config_processor.process_remote_configuration
130
+
131
+ config_processor.add_filters(notice_notifier)
132
+ end
133
+
134
+ # @since v4.2.3
135
+ # @api private
136
+ def performance_notifier
137
+ @performance_notifier ||= PerformanceNotifier.new
138
+ end
139
+
140
+ # @since v4.2.3
141
+ # @api private
142
+ def notice_notifier
143
+ @notice_notifier ||= NoticeNotifier.new
144
+ end
145
+
146
+ # @since v4.2.3
147
+ # @api private
148
+ def deploy_notifier
149
+ @deploy_notifier ||= DeployNotifier.new
109
150
  end
110
151
 
111
152
  # @return [Boolean] true if the notifier was configured, false otherwise
112
153
  # @since v2.3.0
113
154
  def configured?
114
- @notice_notifier.configured?
155
+ @notice_notifier && @notice_notifier.configured?
115
156
  end
116
157
 
117
158
  # Sends an exception to Airbrake asynchronously.
@@ -136,7 +177,7 @@ module Airbrake
136
177
  # @return [Airbrake::Promise]
137
178
  # @see .notify_sync
138
179
  def notify(exception, params = {}, &block)
139
- @notice_notifier.notify(exception, params, &block)
180
+ notice_notifier.notify(exception, params, &block)
140
181
  end
141
182
 
142
183
  # Sends an exception to Airbrake synchronously.
@@ -156,7 +197,7 @@ module Airbrake
156
197
  # @return [Airbrake::Promise] the reponse from the server
157
198
  # @see .notify
158
199
  def notify_sync(exception, params = {}, &block)
159
- @notice_notifier.notify_sync(exception, params, &block)
200
+ notice_notifier.notify_sync(exception, params, &block)
160
201
  end
161
202
 
162
203
  # Runs a callback before {.notify} or {.notify_sync} kicks in. This is
@@ -184,7 +225,7 @@ module Airbrake
184
225
  # @yieldreturn [void]
185
226
  # @return [void]
186
227
  def add_filter(filter = nil, &block)
187
- @notice_notifier.add_filter(filter, &block)
228
+ notice_notifier.add_filter(filter, &block)
188
229
  end
189
230
 
190
231
  # Deletes a filter added via {Airbrake#add_filter}.
@@ -201,7 +242,7 @@ module Airbrake
201
242
  # @since v3.1.0
202
243
  # @note This method cannot delete filters assigned via the Proc form.
203
244
  def delete_filter(filter_class)
204
- @notice_notifier.delete_filter(filter_class)
245
+ notice_notifier.delete_filter(filter_class)
205
246
  end
206
247
 
207
248
  # Builds an Airbrake notice. This is useful, if you want to add or modify a
@@ -219,7 +260,7 @@ module Airbrake
219
260
  # @return [Airbrake::Notice] the notice built with help of the given
220
261
  # arguments
221
262
  def build_notice(exception, params = {})
222
- @notice_notifier.build_notice(exception, params)
263
+ notice_notifier.build_notice(exception, params)
223
264
  end
224
265
 
225
266
  # Makes the notice notifier a no-op, which means you cannot use the
@@ -230,10 +271,24 @@ module Airbrake
230
271
  # Airbrake.close
231
272
  # Airbrake.notify('App crashed!') #=> raises Airbrake::Error
232
273
  #
233
- # @return [void]
274
+ # @return [nil]
275
+ # rubocop:disable Style/IfUnlessModifier, Metrics/CyclomaticComplexity
234
276
  def close
235
- @notice_notifier.close
277
+ if defined?(@notice_notifier) && @notice_notifier
278
+ @notice_notifier.close
279
+ end
280
+
281
+ if defined?(@performance_notifier) && @performance_notifier
282
+ @performance_notifier.close
283
+ end
284
+
285
+ if defined?(@remote_settings) && @remote_settings
286
+ @remote_settings.stop_polling
287
+ end
288
+
289
+ nil
236
290
  end
291
+ # rubocop:enable Style/IfUnlessModifier, Metrics/CyclomaticComplexity
237
292
 
238
293
  # Pings the Airbrake Deploy API endpoint about the occurred deploy.
239
294
  #
@@ -245,7 +300,7 @@ module Airbrake
245
300
  # @option deploy_info [Symbol] :version
246
301
  # @return [void]
247
302
  def notify_deploy(deploy_info)
248
- @deploy_notifier.notify(deploy_info)
303
+ deploy_notifier.notify(deploy_info)
249
304
  end
250
305
 
251
306
  # Merges +context+ with the current context.
@@ -293,12 +348,11 @@ module Airbrake
293
348
  # @param [Hash{Symbol=>Object}] context
294
349
  # @return [void]
295
350
  def merge_context(context)
296
- @notice_notifier.merge_context(context)
351
+ notice_notifier.merge_context(context)
297
352
  end
298
353
 
299
- # Increments request statistics of a certain +route+ that was invoked on
300
- # +start_time+ and ended on +end_time+ with +method+, and returned
301
- # +status_code+.
354
+ # Increments request statistics of a certain +route+ invoked with +method+,
355
+ # which returned +status_code+.
302
356
  #
303
357
  # After a certain amount of time (n seconds) the aggregated route
304
358
  # information will be sent to Airbrake.
@@ -311,8 +365,7 @@ module Airbrake
311
365
  # func: 'do_stuff',
312
366
  # file: 'app/models/foo.rb',
313
367
  # line: 452,
314
- # start_time: timestamp,
315
- # end_time: Time.now
368
+ # timing: 123.45 # ms
316
369
  # )
317
370
  #
318
371
  # @param [Hash{Symbol=>Object}] request_info
@@ -326,18 +379,31 @@ module Airbrake
326
379
  # called the query (optional)
327
380
  # @option request_info [Integer] :line The line that executes the query
328
381
  # (optional)
329
- # @option request_info [Date] :start_time When the request started
330
- # @option request_info [Time] :end_time When the request ended (optional)
382
+ # @option request_info [Float] :timing How much time it took to process the
383
+ # request (in ms)
384
+ # @param [Hash] stash What needs to be appeneded to the stash, so it's
385
+ # available in filters
331
386
  # @return [void]
332
387
  # @since v3.0.0
333
388
  # @see Airbrake::PerformanceNotifier#notify
334
- def notify_request(request_info)
335
- @performance_notifier.notify(Request.new(request_info))
389
+ def notify_request(request_info, stash = {})
390
+ request = Request.new(**request_info)
391
+ request.stash.merge!(stash)
392
+ performance_notifier.notify(request)
393
+ end
394
+
395
+ # Synchronously increments request statistics of a certain +route+ invoked
396
+ # with +method+, which returned +status_code+.
397
+ # @since v4.10.0
398
+ # @see .notify_request
399
+ def notify_request_sync(request_info, stash = {})
400
+ request = Request.new(**request_info)
401
+ request.stash.merge!(stash)
402
+ performance_notifier.notify_sync(request)
336
403
  end
337
404
 
338
- # Increments SQL statistics of a certain +query+ that was invoked on
339
- # +start_time+ and finished on +end_time+. When +method+ and +route+ are
340
- # provided, the query is grouped by these parameters.
405
+ # Increments SQL statistics of a certain +query+. When +method+ and +route+
406
+ # are provided, the query is grouped by these parameters.
341
407
  #
342
408
  # After a certain amount of time (n seconds) the aggregated query
343
409
  # information will be sent to Airbrake.
@@ -347,24 +413,112 @@ module Airbrake
347
413
  # method: 'GET',
348
414
  # route: '/things',
349
415
  # query: 'SELECT * FROM things',
350
- # start_time: timestamp,
351
- # end_time: Time.now
416
+ # timing: 123.45 # ms
352
417
  # )
353
418
  #
354
419
  # @param [Hash{Symbol=>Object}] query_info
355
- # @option request_info [String] :environment (optional)
356
- # @option request_info [String] :method The HTTP method that triggered this
420
+ # @option query_info [String] :method The HTTP method that triggered this
357
421
  # SQL query (optional)
358
- # @option request_info [String] :route The route that triggered this SQL
422
+ # @option query_info [String] :route The route that triggered this SQL
359
423
  # query (optional)
360
- # @option request_info [String] :query The query that was executed
361
- # @option request_info [Date] :start_time When the query started executing
362
- # @option request_info [Time] :end_time When the query finished (optional)
424
+ # @option query_info [String] :query The query that was executed
425
+ # @option query_info [Float] :timing How much time it took to process the
426
+ # query (in ms)
427
+ # @param [Hash] stash What needs to be appeneded to the stash, so it's
428
+ # available in filters
363
429
  # @return [void]
364
430
  # @since v3.2.0
365
431
  # @see Airbrake::PerformanceNotifier#notify
366
- def notify_query(query_info)
367
- @performance_notifier.notify(Query.new(query_info))
432
+ def notify_query(query_info, stash = {})
433
+ query = Query.new(**query_info)
434
+ query.stash.merge!(stash)
435
+ performance_notifier.notify(query)
436
+ end
437
+
438
+ # Synchronously increments SQL statistics of a certain +query+. When
439
+ # +method+ and +route+ are provided, the query is grouped by these
440
+ # parameters.
441
+ # @since v4.10.0
442
+ # @see .notify_query
443
+ def notify_query_sync(query_info, stash = {})
444
+ query = Query.new(**query_info)
445
+ query.stash.merge!(stash)
446
+ performance_notifier.notify_sync(query)
447
+ end
448
+
449
+ # Increments performance breakdown statistics of a certain route.
450
+ #
451
+ # @example
452
+ # Airbrake.notify_request(
453
+ # method: 'POST',
454
+ # route: '/thing/:id/create',
455
+ # response_type: 'json',
456
+ # groups: { db: 24.0, view: 0.4 }, # ms
457
+ # timing: 123.45 # ms
458
+ # )
459
+ #
460
+ # @param [Hash{Symbol=>Object}] breakdown_info
461
+ # @option breakdown_info [String] :method HTTP method
462
+ # @option breakdown_info [String] :route
463
+ # @option breakdown_info [String] :response_type
464
+ # @option breakdown_info [Array<Hash{Symbol=>Float}>] :groups
465
+ # @option breakdown_info [Float] :timing How much time it took to process
466
+ # the performance breakdown (in ms)
467
+ # @param [Hash] stash What needs to be appeneded to the stash, so it's
468
+ # available in filters
469
+ # @return [void]
470
+ # @since v4.2.0
471
+ def notify_performance_breakdown(breakdown_info, stash = {})
472
+ performance_breakdown = PerformanceBreakdown.new(**breakdown_info)
473
+ performance_breakdown.stash.merge!(stash)
474
+ performance_notifier.notify(performance_breakdown)
475
+ end
476
+
477
+ # Increments performance breakdown statistics of a certain route
478
+ # synchronously.
479
+ # @since v4.10.0
480
+ # @see .notify_performance_breakdown
481
+ def notify_performance_breakdown_sync(breakdown_info, stash = {})
482
+ performance_breakdown = PerformanceBreakdown.new(**breakdown_info)
483
+ performance_breakdown.stash.merge!(stash)
484
+ performance_notifier.notify_sync(performance_breakdown)
485
+ end
486
+
487
+ # Increments statistics of a certain queue (worker).
488
+ #
489
+ # @example
490
+ # Airbrake.notify_queue(
491
+ # queue: 'emails',
492
+ # error_count: 1,
493
+ # groups: { redis: 24.0, sql: 0.4 } # ms
494
+ # )
495
+ #
496
+ # @param [Hash{Symbol=>Object}] queue_info
497
+ # @option queue_info [String] :queue The name of the queue/worker
498
+ # @option queue_info [Integer] :error_count How many times this worker
499
+ # failed
500
+ # @option queue_info [Array<Hash{Symbol=>Float}>] :groups Where the job
501
+ # spent its time
502
+ # @option breakdown_info [Float] :timing How much time it took to process
503
+ # the queue (in ms)
504
+ # @param [Hash] stash What needs to be appended to the stash, so it's
505
+ # available in filters
506
+ # @return [void]
507
+ # @since v4.9.0
508
+ # @see .notify_queue_sync
509
+ def notify_queue(queue_info, stash = {})
510
+ queue = Queue.new(**queue_info)
511
+ queue.stash.merge!(stash)
512
+ performance_notifier.notify(queue)
513
+ end
514
+
515
+ # Increments statistics of a certain queue (worker) synchronously.
516
+ # @since v4.10.0
517
+ # @see .notify_queue
518
+ def notify_queue_sync(queue_info, stash = {})
519
+ queue = Queue.new(**queue_info)
520
+ queue.stash.merge!(stash)
521
+ performance_notifier.notify_sync(queue)
368
522
  end
369
523
 
370
524
  # Runs a callback before {.notify_request} or {.notify_query} kicks in. This
@@ -399,7 +553,7 @@ module Airbrake
399
553
  # @since v3.2.0
400
554
  # @see Airbrake::PerformanceNotifier#add_filter
401
555
  def add_performance_filter(filter = nil, &block)
402
- @performance_notifier.add_filter(filter, &block)
556
+ performance_notifier.add_filter(filter, &block)
403
557
  end
404
558
 
405
559
  # Deletes a filter added via {Airbrake#add_performance_filter}.
@@ -417,7 +571,19 @@ module Airbrake
417
571
  # @note This method cannot delete filters assigned via the Proc form.
418
572
  # @see Airbrake::PerformanceNotifier#delete_filter
419
573
  def delete_performance_filter(filter_class)
420
- @performance_notifier.delete_filter(filter_class)
574
+ performance_notifier.delete_filter(filter_class)
575
+ end
576
+
577
+ # Resets all notifiers, including its filters
578
+ # @return [void]
579
+ # @since v4.2.2
580
+ def reset
581
+ close
582
+
583
+ self.performance_notifier = PerformanceNotifier.new
584
+ self.notice_notifier = NoticeNotifier.new
585
+ self.deploy_notifier = DeployNotifier.new
421
586
  end
422
587
  end
423
588
  end
589
+ # rubocop:enable Metrics/ModuleLength