airbrake-ruby 4.6.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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/lib/airbrake-ruby.rb +513 -0
  3. data/lib/airbrake-ruby/async_sender.rb +142 -0
  4. data/lib/airbrake-ruby/backtrace.rb +196 -0
  5. data/lib/airbrake-ruby/benchmark.rb +39 -0
  6. data/lib/airbrake-ruby/code_hunk.rb +51 -0
  7. data/lib/airbrake-ruby/config.rb +229 -0
  8. data/lib/airbrake-ruby/config/validator.rb +91 -0
  9. data/lib/airbrake-ruby/deploy_notifier.rb +36 -0
  10. data/lib/airbrake-ruby/file_cache.rb +48 -0
  11. data/lib/airbrake-ruby/filter_chain.rb +95 -0
  12. data/lib/airbrake-ruby/filters/context_filter.rb +29 -0
  13. data/lib/airbrake-ruby/filters/dependency_filter.rb +31 -0
  14. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +46 -0
  15. data/lib/airbrake-ruby/filters/gem_root_filter.rb +33 -0
  16. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +92 -0
  17. data/lib/airbrake-ruby/filters/git_repository_filter.rb +64 -0
  18. data/lib/airbrake-ruby/filters/git_revision_filter.rb +66 -0
  19. data/lib/airbrake-ruby/filters/keys_blacklist.rb +49 -0
  20. data/lib/airbrake-ruby/filters/keys_filter.rb +140 -0
  21. data/lib/airbrake-ruby/filters/keys_whitelist.rb +48 -0
  22. data/lib/airbrake-ruby/filters/root_directory_filter.rb +28 -0
  23. data/lib/airbrake-ruby/filters/sql_filter.rb +104 -0
  24. data/lib/airbrake-ruby/filters/system_exit_filter.rb +23 -0
  25. data/lib/airbrake-ruby/filters/thread_filter.rb +92 -0
  26. data/lib/airbrake-ruby/hash_keyable.rb +37 -0
  27. data/lib/airbrake-ruby/ignorable.rb +44 -0
  28. data/lib/airbrake-ruby/inspectable.rb +39 -0
  29. data/lib/airbrake-ruby/loggable.rb +34 -0
  30. data/lib/airbrake-ruby/monotonic_time.rb +43 -0
  31. data/lib/airbrake-ruby/nested_exception.rb +38 -0
  32. data/lib/airbrake-ruby/notice.rb +162 -0
  33. data/lib/airbrake-ruby/notice_notifier.rb +134 -0
  34. data/lib/airbrake-ruby/performance_breakdown.rb +45 -0
  35. data/lib/airbrake-ruby/performance_notifier.rb +125 -0
  36. data/lib/airbrake-ruby/promise.rb +109 -0
  37. data/lib/airbrake-ruby/query.rb +53 -0
  38. data/lib/airbrake-ruby/request.rb +45 -0
  39. data/lib/airbrake-ruby/response.rb +74 -0
  40. data/lib/airbrake-ruby/stashable.rb +15 -0
  41. data/lib/airbrake-ruby/stat.rb +73 -0
  42. data/lib/airbrake-ruby/sync_sender.rb +113 -0
  43. data/lib/airbrake-ruby/tdigest.rb +393 -0
  44. data/lib/airbrake-ruby/time_truncate.rb +17 -0
  45. data/lib/airbrake-ruby/timed_trace.rb +58 -0
  46. data/lib/airbrake-ruby/truncator.rb +115 -0
  47. data/lib/airbrake-ruby/version.rb +6 -0
  48. data/spec/airbrake_spec.rb +324 -0
  49. data/spec/async_sender_spec.rb +155 -0
  50. data/spec/backtrace_spec.rb +427 -0
  51. data/spec/benchmark_spec.rb +33 -0
  52. data/spec/code_hunk_spec.rb +115 -0
  53. data/spec/config/validator_spec.rb +184 -0
  54. data/spec/config_spec.rb +154 -0
  55. data/spec/deploy_notifier_spec.rb +48 -0
  56. data/spec/file_cache.rb +36 -0
  57. data/spec/filter_chain_spec.rb +92 -0
  58. data/spec/filters/context_filter_spec.rb +23 -0
  59. data/spec/filters/dependency_filter_spec.rb +12 -0
  60. data/spec/filters/exception_attributes_filter_spec.rb +50 -0
  61. data/spec/filters/gem_root_filter_spec.rb +41 -0
  62. data/spec/filters/git_last_checkout_filter_spec.rb +46 -0
  63. data/spec/filters/git_repository_filter.rb +61 -0
  64. data/spec/filters/git_revision_filter_spec.rb +126 -0
  65. data/spec/filters/keys_blacklist_spec.rb +225 -0
  66. data/spec/filters/keys_whitelist_spec.rb +194 -0
  67. data/spec/filters/root_directory_filter_spec.rb +39 -0
  68. data/spec/filters/sql_filter_spec.rb +219 -0
  69. data/spec/filters/system_exit_filter_spec.rb +14 -0
  70. data/spec/filters/thread_filter_spec.rb +277 -0
  71. data/spec/fixtures/notroot.txt +7 -0
  72. data/spec/fixtures/project_root/code.rb +221 -0
  73. data/spec/fixtures/project_root/empty_file.rb +0 -0
  74. data/spec/fixtures/project_root/long_line.txt +1 -0
  75. data/spec/fixtures/project_root/short_file.rb +3 -0
  76. data/spec/fixtures/project_root/vendor/bundle/ignored_file.rb +5 -0
  77. data/spec/helpers.rb +9 -0
  78. data/spec/ignorable_spec.rb +14 -0
  79. data/spec/inspectable_spec.rb +45 -0
  80. data/spec/monotonic_time_spec.rb +12 -0
  81. data/spec/nested_exception_spec.rb +73 -0
  82. data/spec/notice_notifier_spec.rb +356 -0
  83. data/spec/notice_notifier_spec/options_spec.rb +259 -0
  84. data/spec/notice_spec.rb +296 -0
  85. data/spec/performance_breakdown_spec.rb +12 -0
  86. data/spec/performance_notifier_spec.rb +435 -0
  87. data/spec/promise_spec.rb +197 -0
  88. data/spec/query_spec.rb +11 -0
  89. data/spec/request_spec.rb +11 -0
  90. data/spec/response_spec.rb +88 -0
  91. data/spec/spec_helper.rb +100 -0
  92. data/spec/stashable_spec.rb +23 -0
  93. data/spec/stat_spec.rb +47 -0
  94. data/spec/sync_sender_spec.rb +133 -0
  95. data/spec/tdigest_spec.rb +230 -0
  96. data/spec/time_truncate_spec.rb +13 -0
  97. data/spec/timed_trace_spec.rb +125 -0
  98. data/spec/truncator_spec.rb +238 -0
  99. metadata +213 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cf81123734caec939f2b487e0ca743ea26659f46
4
+ data.tar.gz: ba8e315a20b3f59d0863d027010e54311ba15d9d
5
+ SHA512:
6
+ metadata.gz: 551704a67996c2064820507d4fb3dd0218df863e7433d77356dd45bc62ecab112508372125a98c8d2f651c2693716e96c86b8e0172ffd265b60de0258d1b7acf
7
+ data.tar.gz: c32da13a83d385bc91b7cc2f236324ae29918005bac9450076d03fc0b707f49b2474049dac7c13fb78f1b0c848c2a1e95579f3c5f1c2315581c8db7d8c1eb3e0
@@ -0,0 +1,513 @@
1
+ require 'net/https'
2
+ require 'logger'
3
+ require 'json'
4
+ require 'thread'
5
+ require 'set'
6
+ require 'socket'
7
+ require 'time'
8
+
9
+ require 'airbrake-ruby/version'
10
+ require 'airbrake-ruby/loggable'
11
+ require 'airbrake-ruby/stashable'
12
+ require 'airbrake-ruby/config'
13
+ require 'airbrake-ruby/config/validator'
14
+ require 'airbrake-ruby/promise'
15
+ require 'airbrake-ruby/sync_sender'
16
+ require 'airbrake-ruby/async_sender'
17
+ require 'airbrake-ruby/response'
18
+ require 'airbrake-ruby/nested_exception'
19
+ require 'airbrake-ruby/ignorable'
20
+ require 'airbrake-ruby/inspectable'
21
+ require 'airbrake-ruby/notice'
22
+ require 'airbrake-ruby/backtrace'
23
+ require 'airbrake-ruby/truncator'
24
+ require 'airbrake-ruby/filters/keys_filter'
25
+ require 'airbrake-ruby/filters/keys_whitelist'
26
+ require 'airbrake-ruby/filters/keys_blacklist'
27
+ require 'airbrake-ruby/filters/gem_root_filter'
28
+ require 'airbrake-ruby/filters/system_exit_filter'
29
+ require 'airbrake-ruby/filters/root_directory_filter'
30
+ require 'airbrake-ruby/filters/thread_filter'
31
+ require 'airbrake-ruby/filters/context_filter'
32
+ require 'airbrake-ruby/filters/exception_attributes_filter'
33
+ require 'airbrake-ruby/filters/dependency_filter'
34
+ require 'airbrake-ruby/filters/git_revision_filter'
35
+ require 'airbrake-ruby/filters/git_repository_filter'
36
+ require 'airbrake-ruby/filters/git_last_checkout_filter'
37
+ require 'airbrake-ruby/filters/sql_filter'
38
+ require 'airbrake-ruby/filter_chain'
39
+ require 'airbrake-ruby/code_hunk'
40
+ require 'airbrake-ruby/file_cache'
41
+ require 'airbrake-ruby/hash_keyable'
42
+ require 'airbrake-ruby/performance_notifier'
43
+ require 'airbrake-ruby/notice_notifier'
44
+ require 'airbrake-ruby/deploy_notifier'
45
+ require 'airbrake-ruby/stat'
46
+ require 'airbrake-ruby/time_truncate'
47
+ require 'airbrake-ruby/tdigest'
48
+ require 'airbrake-ruby/query'
49
+ require 'airbrake-ruby/request'
50
+ require 'airbrake-ruby/performance_breakdown'
51
+ require 'airbrake-ruby/benchmark'
52
+ require 'airbrake-ruby/monotonic_time'
53
+ require 'airbrake-ruby/timed_trace'
54
+
55
+ # Airbrake is a thin wrapper around instances of the notifier classes (such as
56
+ # notice, performance & deploy notifiers). It creates a way to access them via a
57
+ # consolidated global interface.
58
+ #
59
+ # Prior to using it, you must {configure} it.
60
+ #
61
+ # @example
62
+ # Airbrake.configure do |c|
63
+ # c.project_id = 113743
64
+ # c.project_key = 'fd04e13d806a90f96614ad8e529b2822'
65
+ # end
66
+ #
67
+ # Airbrake.notify('Oops!')
68
+ #
69
+ # @since v1.0.0
70
+ # @api public
71
+ module Airbrake
72
+ # The general error that this library uses when it wants to raise.
73
+ Error = Class.new(StandardError)
74
+
75
+ # @return [String] the label to be prepended to the log output
76
+ LOG_LABEL = '**Airbrake:'.freeze
77
+
78
+ # @return [Boolean] true if current Ruby is JRuby. The result is used for
79
+ # special cases where we need to work around older implementations
80
+ JRUBY = (RUBY_ENGINE == 'jruby')
81
+
82
+ class << self
83
+ # @since v4.2.3
84
+ # @api private
85
+ attr_writer :performance_notifier
86
+
87
+ # @since v4.2.3
88
+ # @api private
89
+ attr_writer :notice_notifier
90
+
91
+ # @since v4.2.3
92
+ # @api private
93
+ attr_writer :deploy_notifier
94
+
95
+ # Configures the Airbrake notifier.
96
+ #
97
+ # @example
98
+ # Airbrake.configure do |c|
99
+ # c.project_id = 113743
100
+ # c.project_key = 'fd04e13d806a90f96614ad8e529b2822'
101
+ # end
102
+ #
103
+ # @yield [config]
104
+ # @yieldparam config [Airbrake::Config]
105
+ # @return [void]
106
+ def configure
107
+ yield config = Airbrake::Config.instance
108
+ Airbrake::Loggable.instance = config.logger
109
+ process_config_options(config)
110
+ end
111
+
112
+ # @since v4.2.3
113
+ # @api private
114
+ def performance_notifier
115
+ @performance_notifier ||= PerformanceNotifier.new
116
+ end
117
+
118
+ # @since v4.2.3
119
+ # @api private
120
+ def notice_notifier
121
+ @notice_notifier ||= NoticeNotifier.new
122
+ end
123
+
124
+ # @since v4.2.3
125
+ # @api private
126
+ def deploy_notifier
127
+ @deploy_notifier ||= DeployNotifier.new
128
+ end
129
+
130
+ # @return [Boolean] true if the notifier was configured, false otherwise
131
+ # @since v2.3.0
132
+ def configured?
133
+ notice_notifier.configured?
134
+ end
135
+
136
+ # Sends an exception to Airbrake asynchronously.
137
+ #
138
+ # @example Sending an exception
139
+ # Airbrake.notify(RuntimeError.new('Oops!'))
140
+ # @example Sending a string
141
+ # # Converted to RuntimeError.new('Oops!') internally
142
+ # Airbrake.notify('Oops!')
143
+ # @example Sending a Notice
144
+ # notice = airbrake.build_notice(RuntimeError.new('Oops!'))
145
+ # airbrake.notify(notice)
146
+ #
147
+ # @param [Exception, String, Airbrake::Notice] exception The exception to be
148
+ # sent to Airbrake
149
+ # @param [Hash] params The additional payload to be sent to Airbrake. Can
150
+ # contain any values. The provided values will be displayed in the Params
151
+ # tab in your project's dashboard
152
+ # @yield [notice] The notice to filter
153
+ # @yieldparam [Airbrake::Notice]
154
+ # @yieldreturn [void]
155
+ # @return [Airbrake::Promise]
156
+ # @see .notify_sync
157
+ def notify(exception, params = {}, &block)
158
+ notice_notifier.notify(exception, params, &block)
159
+ end
160
+
161
+ # Sends an exception to Airbrake synchronously.
162
+ #
163
+ # @example
164
+ # Airbrake.notify_sync('App crashed!')
165
+ # #=> {"id"=>"123", "url"=>"https://airbrake.io/locate/321"}
166
+ #
167
+ # @param [Exception, String, Airbrake::Notice] exception The exception to be
168
+ # sent to Airbrake
169
+ # @param [Hash] params The additional payload to be sent to Airbrake. Can
170
+ # contain any values. The provided values will be displayed in the Params
171
+ # tab in your project's dashboard
172
+ # @yield [notice] The notice to filter
173
+ # @yieldparam [Airbrake::Notice]
174
+ # @yieldreturn [void]
175
+ # @return [Airbrake::Promise] the reponse from the server
176
+ # @see .notify
177
+ def notify_sync(exception, params = {}, &block)
178
+ notice_notifier.notify_sync(exception, params, &block)
179
+ end
180
+
181
+ # Runs a callback before {.notify} or {.notify_sync} kicks in. This is
182
+ # useful if you want to ignore specific notices or filter the data the
183
+ # notice contains.
184
+ #
185
+ # @example Ignore all notices
186
+ # Airbrake.add_filter(&:ignore!)
187
+ # @example Ignore based on some condition
188
+ # Airbrake.add_filter do |notice|
189
+ # notice.ignore! if notice[:error_class] == 'StandardError'
190
+ # end
191
+ # @example Ignore with help of a class
192
+ # class MyFilter
193
+ # def call(notice)
194
+ # # ...
195
+ # end
196
+ # end
197
+ #
198
+ # Airbrake.add_filter(MyFilter.new)
199
+ #
200
+ # @param [#call] filter The filter object
201
+ # @yield [notice] The notice to filter
202
+ # @yieldparam [Airbrake::Notice]
203
+ # @yieldreturn [void]
204
+ # @return [void]
205
+ def add_filter(filter = nil, &block)
206
+ notice_notifier.add_filter(filter, &block)
207
+ end
208
+
209
+ # Deletes a filter added via {Airbrake#add_filter}.
210
+ #
211
+ # @example
212
+ # # Add a MyFilter filter (we pass an instance here).
213
+ # Airbrake.add_filter(MyFilter.new)
214
+ #
215
+ # # Delete the filter (we pass class name here).
216
+ # Airbrake.delete_filter(MyFilter)
217
+ #
218
+ # @param [Class] filter_class The class of the filter you want to delete
219
+ # @return [void]
220
+ # @since v3.1.0
221
+ # @note This method cannot delete filters assigned via the Proc form.
222
+ def delete_filter(filter_class)
223
+ notice_notifier.delete_filter(filter_class)
224
+ end
225
+
226
+ # Builds an Airbrake notice. This is useful, if you want to add or modify a
227
+ # value only for a specific notice. When you're done modifying the notice,
228
+ # send it with {.notify} or {.notify_sync}.
229
+ #
230
+ # @example
231
+ # notice = airbrake.build_notice('App crashed!')
232
+ # notice[:params][:username] = user.name
233
+ # airbrake.notify_sync(notice)
234
+ #
235
+ # @param [Exception] exception The exception on top of which the notice
236
+ # should be built
237
+ # @param [Hash] params The additional params attached to the notice
238
+ # @return [Airbrake::Notice] the notice built with help of the given
239
+ # arguments
240
+ def build_notice(exception, params = {})
241
+ notice_notifier.build_notice(exception, params)
242
+ end
243
+
244
+ # Makes the notice notifier a no-op, which means you cannot use the
245
+ # {.notify} and {.notify_sync} methods anymore. It also stops the notice
246
+ # notifier's worker threads.
247
+ #
248
+ # @example
249
+ # Airbrake.close
250
+ # Airbrake.notify('App crashed!') #=> raises Airbrake::Error
251
+ #
252
+ # @return [void]
253
+ def close
254
+ notice_notifier.close
255
+ end
256
+
257
+ # Pings the Airbrake Deploy API endpoint about the occurred deploy.
258
+ #
259
+ # @param [Hash{Symbol=>String}] deploy_info The params for the API
260
+ # @option deploy_info [Symbol] :environment
261
+ # @option deploy_info [Symbol] :username
262
+ # @option deploy_info [Symbol] :repository
263
+ # @option deploy_info [Symbol] :revision
264
+ # @option deploy_info [Symbol] :version
265
+ # @return [void]
266
+ def notify_deploy(deploy_info)
267
+ deploy_notifier.notify(deploy_info)
268
+ end
269
+
270
+ # Merges +context+ with the current context.
271
+ #
272
+ # The context will be attached to the notice object upon a notify call and
273
+ # cleared after it's attached. The context data is attached to the
274
+ # `params/airbrake_context` key.
275
+ #
276
+ # @example
277
+ # class MerryGrocer
278
+ # def load_fruits(fruits)
279
+ # Airbrake.merge_context(fruits: fruits)
280
+ # end
281
+ #
282
+ # def deliver_fruits
283
+ # Airbrake.notify('fruitception')
284
+ # end
285
+ #
286
+ # def load_veggies(veggies)
287
+ # Airbrake.merge_context(veggies: veggies)
288
+ # end
289
+ #
290
+ # def deliver_veggies
291
+ # Airbrake.notify('veggieboom!')
292
+ # end
293
+ # end
294
+ #
295
+ # grocer = MerryGrocer.new
296
+ #
297
+ # # Load some fruits to the context.
298
+ # grocer.load_fruits(%w(mango banana apple))
299
+ #
300
+ # # Deliver the fruits. Note that we are not passing anything,
301
+ # # `deliver_fruits` knows that we loaded something.
302
+ # grocer.deliver_fruits
303
+ #
304
+ # # Load some vegetables and deliver them to Airbrake. Note that the
305
+ # # fruits have been delivered and therefore the grocer doesn't have them
306
+ # # anymore. We merge veggies with the new context.
307
+ # grocer.load_veggies(%w(cabbage carrot onion))
308
+ # grocer.deliver_veggies
309
+ #
310
+ # # The context is empty again, feel free to load more.
311
+ #
312
+ # @param [Hash{Symbol=>Object}] context
313
+ # @return [void]
314
+ def merge_context(context)
315
+ notice_notifier.merge_context(context)
316
+ end
317
+
318
+ # Increments request statistics of a certain +route+ that was invoked on
319
+ # +start_time+ and ended on +end_time+ with +method+, and returned
320
+ # +status_code+.
321
+ #
322
+ # After a certain amount of time (n seconds) the aggregated route
323
+ # information will be sent to Airbrake.
324
+ #
325
+ # @example
326
+ # Airbrake.notify_request(
327
+ # method: 'POST',
328
+ # route: '/thing/:id/create',
329
+ # status_code: 200,
330
+ # func: 'do_stuff',
331
+ # file: 'app/models/foo.rb',
332
+ # line: 452,
333
+ # start_time: timestamp,
334
+ # end_time: Time.now
335
+ # )
336
+ #
337
+ # @param [Hash{Symbol=>Object}] request_info
338
+ # @option request_info [String] :method The HTTP method that was invoked
339
+ # @option request_info [String] :route The route that was invoked
340
+ # @option request_info [Integer] :status_code The respose code that the
341
+ # route returned
342
+ # @option request_info [String] :func The function that called the query
343
+ # (optional)
344
+ # @option request_info [String] :file The file that has the function that
345
+ # called the query (optional)
346
+ # @option request_info [Integer] :line The line that executes the query
347
+ # (optional)
348
+ # @option request_info [Date] :start_time When the request started
349
+ # @option request_info [Time] :end_time When the request ended (optional)
350
+ # @param [Hash] stash What needs to be appeneded to the stash, so it's
351
+ # available in filters
352
+ # @return [void]
353
+ # @since v3.0.0
354
+ # @see Airbrake::PerformanceNotifier#notify
355
+ def notify_request(request_info, stash = {})
356
+ request = Request.new(request_info)
357
+ request.stash.merge!(stash)
358
+ performance_notifier.notify(request)
359
+ end
360
+
361
+ # Increments SQL statistics of a certain +query+ that was invoked on
362
+ # +start_time+ and finished on +end_time+. When +method+ and +route+ are
363
+ # provided, the query is grouped by these parameters.
364
+ #
365
+ # After a certain amount of time (n seconds) the aggregated query
366
+ # information will be sent to Airbrake.
367
+ #
368
+ # @example
369
+ # Airbrake.notify_query(
370
+ # method: 'GET',
371
+ # route: '/things',
372
+ # query: 'SELECT * FROM things',
373
+ # start_time: timestamp,
374
+ # end_time: Time.now
375
+ # )
376
+ #
377
+ # @param [Hash{Symbol=>Object}] query_info
378
+ # @option request_info [String] :method The HTTP method that triggered this
379
+ # SQL query (optional)
380
+ # @option request_info [String] :route The route that triggered this SQL
381
+ # query (optional)
382
+ # @option request_info [String] :query The query that was executed
383
+ # @option request_info [Date] :start_time When the query started executing
384
+ # @option request_info [Time] :end_time When the query finished (optional)
385
+ # @param [Hash] stash What needs to be appeneded to the stash, so it's
386
+ # available in filters
387
+ # @return [void]
388
+ # @since v3.2.0
389
+ # @see Airbrake::PerformanceNotifier#notify
390
+ def notify_query(query_info, stash = {})
391
+ query = Query.new(query_info)
392
+ query.stash.merge!(stash)
393
+ performance_notifier.notify(query)
394
+ end
395
+
396
+ # Increments performance breakdown statistics of a certain route.
397
+ #
398
+ # @example
399
+ # Airbrake.notify_request(
400
+ # method: 'POST',
401
+ # route: '/thing/:id/create',
402
+ # response_type: 'json',
403
+ # groups: { db: 24.0, view: 0.4 }, # ms
404
+ # start_time: timestamp,
405
+ # end_time: Time.now
406
+ # )
407
+ #
408
+ # @param [Hash{Symbol=>Object}] breakdown_info
409
+ # @option breakdown_info [String] :method HTTP method
410
+ # @option breakdown_info [String] :route
411
+ # @option breakdown_info [String] :response_type
412
+ # @option breakdown_info [Array<Hash{Symbol=>Float}>] :groups
413
+ # @option breakdown_info [Date] :start_time
414
+ # @param [Hash] stash What needs to be appeneded to the stash, so it's
415
+ # available in filters
416
+ # @return [void]
417
+ # @since v4.2.0
418
+ def notify_performance_breakdown(breakdown_info, stash = {})
419
+ performance_breakdown = PerformanceBreakdown.new(breakdown_info)
420
+ performance_breakdown.stash.merge!(stash)
421
+ performance_notifier.notify(performance_breakdown)
422
+ end
423
+
424
+ # Runs a callback before {.notify_request} or {.notify_query} kicks in. This
425
+ # is useful if you want to ignore specific resources or filter the data the
426
+ # resource contains.
427
+ #
428
+ # @example Ignore all resources
429
+ # Airbrake.add_performance_filter(&:ignore!)
430
+ # @example Filter sensitive data
431
+ # Airbrake.add_performance_filter do |resource|
432
+ # case resource
433
+ # when Airbrake::Query
434
+ # resource.route = '[Filtered]'
435
+ # when Airbrake::Request
436
+ # resource.query = '[Filtered]'
437
+ # end
438
+ # end
439
+ # @example Filter with help of a class
440
+ # class MyFilter
441
+ # def call(resource)
442
+ # # ...
443
+ # end
444
+ # end
445
+ #
446
+ # Airbrake.add_performance_filter(MyFilter.new)
447
+ #
448
+ # @param [#call] filter The filter object
449
+ # @yield [resource] The resource to filter
450
+ # @yieldparam [Airbrake::Query, Airbrake::Request]
451
+ # @yieldreturn [void]
452
+ # @return [void]
453
+ # @since v3.2.0
454
+ # @see Airbrake::PerformanceNotifier#add_filter
455
+ def add_performance_filter(filter = nil, &block)
456
+ performance_notifier.add_filter(filter, &block)
457
+ end
458
+
459
+ # Deletes a filter added via {Airbrake#add_performance_filter}.
460
+ #
461
+ # @example
462
+ # # Add a MyFilter filter (we pass an instance here).
463
+ # Airbrake.add_performance_filter(MyFilter.new)
464
+ #
465
+ # # Delete the filter (we pass class name here).
466
+ # Airbrake.delete_performance_filter(MyFilter)
467
+ #
468
+ # @param [Class] filter_class The class of the filter you want to delete
469
+ # @return [void]
470
+ # @since v3.2.0
471
+ # @note This method cannot delete filters assigned via the Proc form.
472
+ # @see Airbrake::PerformanceNotifier#delete_filter
473
+ def delete_performance_filter(filter_class)
474
+ performance_notifier.delete_filter(filter_class)
475
+ end
476
+
477
+ # Resets all notifiers, including its filters
478
+ # @return [void]
479
+ # @since v4.2.2
480
+ def reset
481
+ close if notice_notifier && configured?
482
+
483
+ self.performance_notifier = PerformanceNotifier.new
484
+ self.notice_notifier = NoticeNotifier.new
485
+ self.deploy_notifier = DeployNotifier.new
486
+ end
487
+
488
+ private
489
+
490
+ def process_config_options(config)
491
+ if config.blacklist_keys.any?
492
+ blacklist = Airbrake::Filters::KeysBlacklist.new(config.blacklist_keys)
493
+ notice_notifier.add_filter(blacklist)
494
+ end
495
+
496
+ if config.whitelist_keys.any?
497
+ whitelist = Airbrake::Filters::KeysWhitelist.new(config.whitelist_keys)
498
+ notice_notifier.add_filter(whitelist)
499
+ end
500
+
501
+ return unless config.root_directory
502
+
503
+ [
504
+ Airbrake::Filters::RootDirectoryFilter,
505
+ Airbrake::Filters::GitRevisionFilter,
506
+ Airbrake::Filters::GitRepositoryFilter,
507
+ Airbrake::Filters::GitLastCheckoutFilter
508
+ ].each do |filter|
509
+ notice_notifier.add_filter(filter.new(config.root_directory))
510
+ end
511
+ end
512
+ end
513
+ end