rollbar 2.19.1 → 2.27.1

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 (86) hide show
  1. checksums.yaml +5 -5
  2. data/.github/pull_request_template.md +25 -0
  3. data/.rubocop.yml +168 -0
  4. data/.travis.yml +63 -34
  5. data/Appraisals +10 -10
  6. data/Gemfile +35 -14
  7. data/README.md +5 -2
  8. data/Rakefile +0 -0
  9. data/data/rollbar.snippet.js +1 -1
  10. data/docs/configuration.md +17 -0
  11. data/gemfiles/rails30.gemfile +10 -10
  12. data/gemfiles/rails31.gemfile +10 -9
  13. data/gemfiles/rails32.gemfile +10 -9
  14. data/gemfiles/rails40.gemfile +10 -9
  15. data/gemfiles/rails41.gemfile +10 -9
  16. data/gemfiles/rails42.gemfile +12 -9
  17. data/gemfiles/rails50.gemfile +21 -14
  18. data/gemfiles/rails51.gemfile +21 -14
  19. data/gemfiles/rails52.gemfile +15 -12
  20. data/gemfiles/rails60.gemfile +67 -0
  21. data/lib/generators/rollbar/rollbar_generator.rb +1 -1
  22. data/lib/rails/rollbar_runner.rb +4 -2
  23. data/lib/rollbar/capistrano.rb +1 -1
  24. data/lib/rollbar/capistrano3.rb +6 -3
  25. data/lib/rollbar/capistrano_tasks.rb +29 -21
  26. data/lib/rollbar/configuration.rb +86 -16
  27. data/lib/rollbar/delay/girl_friday.rb +4 -8
  28. data/lib/rollbar/delay/resque.rb +3 -6
  29. data/lib/rollbar/delay/sidekiq.rb +4 -10
  30. data/lib/rollbar/delay/sucker_punch.rb +16 -19
  31. data/lib/rollbar/delay/thread.rb +16 -2
  32. data/lib/rollbar/deploy.rb +52 -29
  33. data/lib/rollbar/encoding/encoder.rb +17 -10
  34. data/lib/rollbar/exception_reporter.rb +19 -5
  35. data/lib/rollbar/item/backtrace.rb +13 -3
  36. data/lib/rollbar/item/frame.rb +9 -1
  37. data/lib/rollbar/item/locals.rb +100 -0
  38. data/lib/rollbar/item.rb +56 -17
  39. data/lib/rollbar/json.rb +6 -51
  40. data/lib/rollbar/language_support.rb +4 -20
  41. data/lib/rollbar/lazy_store.rb +5 -5
  42. data/lib/rollbar/logger.rb +1 -0
  43. data/lib/rollbar/logger_proxy.rb +6 -2
  44. data/lib/rollbar/middleware/js.rb +28 -18
  45. data/lib/rollbar/middleware/rack.rb +4 -1
  46. data/lib/rollbar/middleware/rails/rollbar.rb +10 -1
  47. data/lib/rollbar/notifier/trace_with_bindings.rb +65 -0
  48. data/lib/rollbar/notifier.rb +225 -89
  49. data/lib/rollbar/plugin.rb +54 -6
  50. data/lib/rollbar/plugins/active_job.rb +6 -2
  51. data/lib/rollbar/plugins/basic_socket.rb +21 -6
  52. data/lib/rollbar/plugins/delayed_job/job_data.rb +3 -3
  53. data/lib/rollbar/plugins/delayed_job/plugin.rb +13 -3
  54. data/lib/rollbar/plugins/error_context.rb +11 -0
  55. data/lib/rollbar/plugins/goalie.rb +11 -3
  56. data/lib/rollbar/plugins/rails/controller_methods.rb +15 -3
  57. data/lib/rollbar/plugins/rake.rb +2 -2
  58. data/lib/rollbar/plugins/sidekiq/plugin.rb +5 -4
  59. data/lib/rollbar/plugins.rb +7 -1
  60. data/lib/rollbar/rake_tasks.rb +4 -148
  61. data/lib/rollbar/request_data_extractor.rb +31 -21
  62. data/lib/rollbar/rollbar_test.rb +36 -0
  63. data/lib/rollbar/scrubbers/params.rb +19 -18
  64. data/lib/rollbar/scrubbers/url.rb +18 -9
  65. data/lib/rollbar/scrubbers.rb +3 -3
  66. data/lib/rollbar/truncation/frames_strategy.rb +1 -1
  67. data/lib/rollbar/truncation/min_body_strategy.rb +2 -3
  68. data/lib/rollbar/truncation/mixin.rb +1 -1
  69. data/lib/rollbar/truncation/remove_any_key_strategy.rb +123 -0
  70. data/lib/rollbar/truncation/remove_extra_strategy.rb +35 -0
  71. data/lib/rollbar/truncation/remove_request_strategy.rb +21 -0
  72. data/lib/rollbar/truncation/strings_strategy.rb +6 -5
  73. data/lib/rollbar/truncation.rb +9 -2
  74. data/lib/rollbar/util/hash.rb +15 -0
  75. data/lib/rollbar/util/ip_anonymizer.rb +8 -7
  76. data/lib/rollbar/util/ip_obfuscator.rb +1 -1
  77. data/lib/rollbar/util.rb +6 -2
  78. data/lib/rollbar/version.rb +1 -1
  79. data/lib/rollbar.rb +2 -3
  80. data/lib/tasks/benchmark.rake +103 -0
  81. data/rollbar.gemspec +13 -5
  82. data/spec/support/rollbar_api.rb +67 -0
  83. metadata +21 -23
  84. data/gemfiles/ruby_1_8_and_1_9_2.gemfile +0 -49
  85. data/lib/rollbar/json/default.rb +0 -11
  86. data/lib/rollbar/json/oj.rb +0 -16
@@ -8,6 +8,7 @@ require 'rollbar/delay/girl_friday'
8
8
  require 'rollbar/delay/thread'
9
9
  require 'rollbar/logger_proxy'
10
10
  require 'rollbar/item'
11
+ require 'rollbar/notifier/trace_with_bindings'
11
12
  require 'ostruct'
12
13
 
13
14
  module Rollbar
@@ -18,7 +19,9 @@ module Rollbar
18
19
  attr_accessor :last_report
19
20
  attr_accessor :scope_object
20
21
 
21
- @file_semaphore = Mutex.new
22
+ MUTEX = Mutex.new
23
+ EXTENSION_REGEXP = /.rollbar\z/.freeze
24
+ FAILSAFE_STRING_LENGTH = 10_000
22
25
 
23
26
  def initialize(parent_notifier = nil, payload_options = nil, scope = nil)
24
27
  if parent_notifier
@@ -41,21 +44,21 @@ module Rollbar
41
44
  # Similar to configure below, but used only internally within the gem
42
45
  # to configure it without initializing any of the third party hooks
43
46
  def preconfigure
44
- yield(configuration)
47
+ yield(configuration.configured_options)
45
48
  end
46
49
 
47
50
  # Configures the notifier instance
48
51
  def configure
49
52
  configuration.enabled = true if configuration.enabled.nil?
50
53
 
51
- yield(configuration)
54
+ yield(configuration.configured_options)
52
55
  end
53
56
 
54
57
  def reconfigure
55
58
  self.configuration = Configuration.new
56
59
  configuration.enabled = true
57
60
 
58
- yield(configuration)
61
+ yield(configuration.configured_options)
59
62
  end
60
63
 
61
64
  def unconfigure
@@ -95,17 +98,17 @@ module Rollbar
95
98
  # @yield Block which exceptions won't be reported.
96
99
  def silenced
97
100
  yield
98
- rescue => e
101
+ rescue StandardError => e
99
102
  e.instance_variable_set(:@_rollbar_do_not_report, true)
100
103
  raise
101
104
  end
102
105
 
103
106
  # Sends a report to Rollbar.
104
107
  #
105
- # Accepts any number of arguments. The last String argument will become
106
- # the message or description of the report. The last Exception argument
107
- # will become the associated exception for the report. The last hash
108
- # argument will be used as the extra data for the report.
108
+ # Accepts a level string plus any number of arguments. The last String
109
+ # argument will become the message or description of the report. The last
110
+ # Exception argument will become the associated exception for the report.
111
+ # The last hash argument will be used as the extra data for the report.
109
112
  #
110
113
  # If the extra hash contains a symbol key :custom_data_method_context
111
114
  # the value of the key will be used as the context for
@@ -116,17 +119,17 @@ module Rollbar
116
119
  # begin
117
120
  # foo = bar
118
121
  # rescue => e
119
- # Rollbar.log(e)
122
+ # Rollbar.log('error', e)
120
123
  # end
121
124
  #
122
125
  # @example
123
- # Rollbar.log('This is a simple log message')
126
+ # Rollbar.log('info', 'This is a simple log message')
124
127
  #
125
128
  # @example
126
- # Rollbar.log(e, 'This is a description of the exception')
129
+ # Rollbar.log('error', e, 'This is a description of the exception')
127
130
  #
128
131
  def log(level, *args)
129
- return 'disabled' unless configuration.enabled
132
+ return 'disabled' unless enabled?
130
133
 
131
134
  message, exception, extra, context = extract_arguments(args)
132
135
  use_exception_level_filters = use_exception_level_filters?(extra)
@@ -146,13 +149,25 @@ module Rollbar
146
149
  level = lookup_exception_level(level, exception,
147
150
  use_exception_level_filters)
148
151
 
149
- begin
150
- report(level, message, exception, extra, context)
151
- rescue StandardError, SystemStackError => e
152
- report_internal_error(e)
152
+ ret = report_with_rescue(level, message, exception, extra, context)
153
153
 
154
- 'error'
155
- end
154
+ raise(exception) if configuration.raise_on_error && exception
155
+
156
+ ret
157
+ end
158
+
159
+ def report_with_rescue(level, message, exception, extra, context)
160
+ report(level, message, exception, extra, context)
161
+ rescue StandardError, SystemStackError => e
162
+ original_error = {
163
+ :message => message,
164
+ :exception => exception,
165
+ :configuration => configuration
166
+ }
167
+
168
+ report_internal_error(e, original_error)
169
+
170
+ 'error'
156
171
  end
157
172
 
158
173
  # See log() above
@@ -185,21 +200,28 @@ module Rollbar
185
200
  log('critical', *args)
186
201
  end
187
202
 
203
+ def enabled?
204
+ # Require access_token so we don't try to send events when unconfigured.
205
+ configuration.enabled && configuration.access_token && !configuration.access_token.empty?
206
+ end
207
+
188
208
  def process_item(item)
189
209
  if configuration.write_to_file
190
210
  if configuration.use_async
191
- @file_semaphore.synchronize do
192
- write_item(item)
211
+ MUTEX.synchronize do
212
+ do_write_item(item)
193
213
  end
194
214
  else
195
- write_item(item)
215
+ do_write_item(item)
196
216
  end
197
217
  else
198
218
  send_item(item)
199
219
  end
200
- rescue => e
220
+ rescue StandardError => e
201
221
  log_error("[Rollbar] Error processing the item: #{e.class}, #{e.message}. Item: #{item.payload.inspect}")
202
- raise e
222
+ raise e unless via_failsafe?(item)
223
+
224
+ log_error('[Rollbar] Item has already failed. Not re-raising')
203
225
  end
204
226
 
205
227
  # We will reraise exceptions in this method so async queues
@@ -226,17 +248,20 @@ module Rollbar
226
248
  # Using Rollbar.silenced we avoid the above behavior but Sidekiq
227
249
  # will have a chance to retry the original job.
228
250
  def process_from_async_handler(payload)
229
- payload = Rollbar::JSON.load(payload) if payload.is_a?(String)
230
-
231
- item = Item.build_with(payload,
232
- :notifier => self,
233
- :configuration => configuration,
234
- :logger => logger)
235
-
236
251
  Rollbar.silenced do
237
252
  begin
238
- process_item(item)
239
- rescue => e
253
+ if payload.is_a?(String)
254
+ # The final payload has already been built.
255
+ send_body(payload)
256
+ else
257
+ item = Item.build_with(payload,
258
+ :notifier => self,
259
+ :configuration => configuration,
260
+ :logger => logger)
261
+
262
+ process_item(item)
263
+ end
264
+ rescue StandardError => e
240
265
  report_internal_error(e)
241
266
 
242
267
  raise
@@ -244,35 +269,34 @@ module Rollbar
244
269
  end
245
270
  end
246
271
 
247
- def send_failsafe(message, exception, uuid = nil, host = nil)
248
- exception_reason = failsafe_reason(message, exception)
249
-
250
- log_error "[Rollbar] Sending failsafe response due to #{exception_reason}"
251
-
252
- body = failsafe_body(exception_reason)
253
-
254
- failsafe_data = {
272
+ def failsafe_initial_data(exception_reason)
273
+ {
255
274
  :level => 'error',
256
275
  :environment => configuration.environment.to_s,
257
276
  :body => {
258
277
  :message => {
259
- :body => body
278
+ :body => failsafe_body(exception_reason)
260
279
  }
261
280
  },
262
281
  :notifier => {
263
282
  :name => 'rollbar-gem',
264
283
  :version => VERSION
265
284
  },
266
- :custom => {
267
- :orig_uuid => uuid,
268
- :orig_host => host
269
- },
270
285
  :internal => true,
271
- :failsafe => true
286
+ 'failsafe' => true
272
287
  }
288
+ end
289
+
290
+ def send_failsafe(message, exception, original_error = nil)
291
+ exception_reason = failsafe_reason(message, exception)
292
+
293
+ log_error "[Rollbar] Sending failsafe response due to #{exception_reason}"
294
+
295
+ failsafe_data = failsafe_initial_data(exception_reason)
296
+
297
+ failsafe_add_original_error_data(failsafe_data[:notifier], original_error)
273
298
 
274
299
  failsafe_payload = {
275
- 'access_token' => configuration.access_token,
276
300
  'data' => failsafe_data
277
301
  }
278
302
 
@@ -281,16 +305,69 @@ module Rollbar
281
305
  :notifier => self,
282
306
  :configuration => configuration,
283
307
  :logger => logger)
284
- schedule_item(item)
285
- rescue => e
308
+
309
+ process_item(item)
310
+ log_and_return_item_data(item)
311
+ rescue StandardError => e
286
312
  log_error "[Rollbar] Error sending failsafe : #{e}"
287
313
  end
288
314
 
289
315
  failsafe_payload
290
316
  end
291
317
 
318
+ def failsafe_add_original_error_data(payload_notifier, original_error)
319
+ return unless original_error
320
+
321
+ payload_notifier[:diagnostic] ||= {}
322
+
323
+ add_original_host(payload_notifier[:diagnostic], original_error)
324
+ add_original_uuid(payload_notifier[:diagnostic], original_error)
325
+ add_original_message(payload_notifier[:diagnostic], original_error)
326
+ add_original_error(payload_notifier[:diagnostic], original_error)
327
+ add_configured_options(payload_notifier, original_error)
328
+ end
329
+
330
+ def add_original_message(diagnostic, original_error)
331
+ diagnostic[:original_message] = original_error[:message].truncate(FAILSAFE_STRING_LENGTH) if original_error[:message]
332
+
333
+ rescue StandardError => e
334
+ diagnostic[:original_message] = "Failed: #{e.message}"
335
+ end
336
+
337
+ def add_original_error(diagnostic, original_error)
338
+ if original_error[:exception]
339
+ backtrace = original_error[:exception].backtrace
340
+ message = original_error[:exception].message
341
+ diagnostic[:original_error] = {
342
+ :message => message && message.truncate(FAILSAFE_STRING_LENGTH),
343
+ :stack => backtrace && backtrace.join(', ').truncate(FAILSAFE_STRING_LENGTH)
344
+ }
345
+ end
346
+
347
+ rescue StandardError => e
348
+ diagnostic[:original_error] = "Failed: #{e.message}"
349
+ end
350
+
351
+ def add_configured_options(payload_notifier, original_error)
352
+ if original_error[:configuration]
353
+ configured = original_error[:configuration].configured_options.configured
354
+ payload_notifier[:configured_options] = ::JSON.generate(configured).truncate(FAILSAFE_STRING_LENGTH)
355
+ end
356
+
357
+ rescue StandardError => e
358
+ payload_notifier[:configured_options] = "Failed: #{e.message}"
359
+ end
360
+
361
+ def add_original_host(diagnostic, original_error)
362
+ diagnostic[:original_host] = original_error[:host] if original_error[:host]
363
+ end
364
+
365
+ def add_original_uuid(diagnostic, original_error)
366
+ diagnostic[:original_uuid] = original_error[:uuid] if original_error[:uuid]
367
+ end
368
+
292
369
  ## Logging
293
- %w(debug info warn error).each do |level|
370
+ %w[debug info warn error].each do |level|
294
371
  define_method(:"log_#{level}") do |message|
295
372
  logger.send(level, message)
296
373
  end
@@ -300,6 +377,30 @@ module Rollbar
300
377
  @logger ||= LoggerProxy.new(configuration.logger)
301
378
  end
302
379
 
380
+ def trace_with_bindings
381
+ @trace_with_bindings ||= TraceWithBindings.new
382
+ end
383
+
384
+ def exception_bindings
385
+ trace_with_bindings.exception_frames
386
+ end
387
+
388
+ def current_bindings
389
+ trace_with_bindings.frames
390
+ end
391
+
392
+ def enable_locals?
393
+ configuration.locals[:enabled] && [:app, :all].include?(configuration.send_extra_frame_data)
394
+ end
395
+
396
+ def enable_locals
397
+ trace_with_bindings.enable if enable_locals?
398
+ end
399
+
400
+ def disable_locals
401
+ trace_with_bindings.disable if enable_locals?
402
+ end
403
+
303
404
  private
304
405
 
305
406
  def use_exception_level_filters?(options)
@@ -326,7 +427,7 @@ module Rollbar
326
427
  return 'ignored' if status == 'ignored'
327
428
  rescue Rollbar::Ignore
328
429
  raise
329
- rescue => e
430
+ rescue StandardError => e
330
431
  log_error("[Rollbar] Error calling the `before_process` hook: #{e}")
331
432
 
332
433
  break
@@ -399,43 +500,52 @@ module Rollbar
399
500
 
400
501
  return 'ignored' if item.ignored?
401
502
 
402
- schedule_item(item)
503
+ schedule_item(item) if configuration.transmit
504
+
505
+ log_and_return_item_data(item)
506
+ end
403
507
 
508
+ def log_and_return_item_data(item)
404
509
  data = item['data']
405
510
  log_instance_link(data)
406
511
  Rollbar.last_report = data
512
+ log_data(data) if configuration.log_payload
407
513
 
408
514
  data
409
515
  end
410
516
 
517
+ def log_data(data)
518
+ log_info "[Rollbar] Data: #{data}"
519
+ end
520
+
411
521
  # Reports an internal error in the Rollbar library. This will be reported within the configured
412
522
  # Rollbar project. We'll first attempt to provide a report including the exception traceback.
413
523
  # If that fails, we'll fall back to a more static failsafe response.
414
- def report_internal_error(exception)
524
+ def report_internal_error(exception, original_error = nil)
415
525
  log_error '[Rollbar] Reporting internal error encountered while sending data to Rollbar.'
416
526
 
417
527
  configuration.execute_hook(:on_report_internal_error, exception)
418
528
 
419
529
  begin
420
530
  item = build_item('error', nil, exception, { :internal => true }, nil)
421
- rescue => e
422
- send_failsafe('build_item in exception_data', e)
531
+ rescue StandardError => e
532
+ send_failsafe('build_item in exception_data', e, original_error)
423
533
  log_error "[Rollbar] Exception: #{exception}"
424
534
  return
425
535
  end
426
536
 
427
537
  begin
428
538
  process_item(item)
429
- rescue => e
430
- send_failsafe('error in process_item', e)
539
+ rescue StandardError => e
540
+ send_failsafe('error in process_item', e, original_error)
431
541
  log_error "[Rollbar] Item: #{item}"
432
542
  return
433
543
  end
434
544
 
435
545
  begin
436
546
  log_instance_link(item['data'])
437
- rescue => e
438
- send_failsafe('error logging instance link', e)
547
+ rescue StandardError => e
548
+ send_failsafe('error logging instance link', e, original_error)
439
549
  log_error "[Rollbar] Item: #{item}"
440
550
  return
441
551
  end
@@ -464,14 +574,18 @@ module Rollbar
464
574
 
465
575
  ## Delivery functions
466
576
 
467
- def send_item_using_eventmachine(item, uri)
468
- body = item.dump
469
- return unless body
577
+ def send_using_eventmachine(body)
578
+ uri = URI.parse(configuration.endpoint)
470
579
 
471
- headers = { 'X-Rollbar-Access-Token' => item['access_token'] }
580
+ headers = { 'X-Rollbar-Access-Token' => configuration.access_token }
472
581
  options = http_proxy_for_em(uri)
473
582
  req = EventMachine::HttpRequest.new(uri.to_s, options).post(:body => body, :head => headers)
474
583
 
584
+ eventmachine_callback(req)
585
+ eventmachine_errback(req)
586
+ end
587
+
588
+ def eventmachine_callback(req)
475
589
  req.callback do
476
590
  if req.response_header.status == 200
477
591
  log_info '[Rollbar] Success'
@@ -480,7 +594,9 @@ module Rollbar
480
594
  log_info "[Rollbar] Response: #{req.response}"
481
595
  end
482
596
  end
597
+ end
483
598
 
599
+ def eventmachine_errback(req)
484
600
  req.errback do
485
601
  log_warning "[Rollbar] Call to API failed, status code: #{req.response_header.status}"
486
602
  log_info "[Rollbar] Error's response: #{req.response}"
@@ -493,14 +609,20 @@ module Rollbar
493
609
  body = item.dump
494
610
  return unless body
495
611
 
496
- uri = URI.parse(configuration.endpoint)
497
-
498
612
  if configuration.use_eventmachine
499
- send_item_using_eventmachine(item, uri)
613
+ send_using_eventmachine(body)
500
614
  return
501
615
  end
502
616
 
503
- handle_response(do_post(uri, body, item['access_token']))
617
+ send_body(body)
618
+ end
619
+
620
+ def send_body(body)
621
+ log_info '[Rollbar] Sending json'
622
+
623
+ uri = URI.parse(configuration.endpoint)
624
+
625
+ handle_response(do_post(uri, body, configuration.access_token))
504
626
  end
505
627
 
506
628
  def do_post(uri, body, access_token)
@@ -512,8 +634,6 @@ module Rollbar
512
634
 
513
635
  if uri.scheme == 'https'
514
636
  http.use_ssl = true
515
- # This is needed to have 1.8.7 passing tests
516
- http.ca_file = ENV['ROLLBAR_SSL_CERT_FILE'] if ENV.key?('ROLLBAR_SSL_CERT_FILE')
517
637
  http.verify_mode = ssl_verify_mode
518
638
  end
519
639
 
@@ -594,7 +714,7 @@ module Rollbar
594
714
  end
595
715
 
596
716
  def skip_retries?
597
- Rollbar::LanguageSupport.ruby_18? || Rollbar::LanguageSupport.ruby_19?
717
+ Rollbar::LanguageSupport.ruby_19?
598
718
  end
599
719
 
600
720
  def handle_response(response)
@@ -615,27 +735,24 @@ module Rollbar
615
735
  end
616
736
  end
617
737
 
618
- def write_item(item)
619
- if configuration.use_async
620
- @file_semaphore.synchronize do
621
- do_write_item(item)
622
- end
623
- else
624
- do_write_item(item)
625
- end
626
- end
627
-
628
738
  def do_write_item(item)
629
739
  log_info '[Rollbar] Writing item to file'
630
740
 
631
741
  body = item.dump
632
742
  return unless body
633
743
 
744
+ file_name = if configuration.files_with_pid_name_enabled
745
+ configuration.filepath.gsub(EXTENSION_REGEXP, "_#{Process.pid}\\0")
746
+ else
747
+ configuration.filepath
748
+ end
749
+
634
750
  begin
635
- @file ||= File.open(configuration.filepath, 'a')
751
+ @file ||= File.open(file_name, 'a')
636
752
 
637
753
  @file.puts(body)
638
754
  @file.flush
755
+ update_file(@file, file_name)
639
756
 
640
757
  log_info '[Rollbar] Success'
641
758
  rescue IOError => e
@@ -643,6 +760,18 @@ module Rollbar
643
760
  end
644
761
  end
645
762
 
763
+ def update_file(file, file_name)
764
+ return unless configuration.files_processed_enabled
765
+
766
+ time_now = Time.now
767
+ return if configuration.files_processed_duration > time_now - file.birthtime && file.size < configuration.files_processed_size
768
+
769
+ new_file_name = file_name.gsub(EXTENSION_REGEXP, "_processed_#{time_now.to_i}\\0")
770
+ File.rename(file, new_file_name)
771
+ file.close
772
+ @file = File.open(file_name, 'a')
773
+ end
774
+
646
775
  def failsafe_reason(message, exception)
647
776
  body = ''
648
777
 
@@ -653,17 +782,17 @@ module Rollbar
653
782
 
654
783
  exception_info = exception.class.name
655
784
  # #to_s and #message defaults to class.to_s. Add message only if add valuable info.
656
- exception_info += %(: "#{exception.message}") if exception.message != exception.class.to_s
785
+ exception_info += %[: "#{exception.message}"] if exception.message != exception.class.to_s
657
786
  exception_info += " in #{nearest_frame}" if nearest_frame
658
787
 
659
788
  body += "#{exception_info}: #{message}"
660
- rescue
789
+ rescue StandardError
661
790
  log_error('[Rollbar] Error building failsafe exception message')
662
791
  end
663
792
  else
664
793
  begin
665
794
  body += message.to_s
666
- rescue
795
+ rescue StandardError
667
796
  log_error('[Rollbar] Error building failsafe message')
668
797
  end
669
798
  end
@@ -694,9 +823,12 @@ module Rollbar
694
823
  end
695
824
 
696
825
  def process_async_item(item)
826
+ # Send async payloads as JSON string when async_json_payload is set.
827
+ payload = configuration.async_json_payload ? item.dump : item.payload
828
+
697
829
  configuration.async_handler ||= default_async_handler
698
- configuration.async_handler.call(item.payload)
699
- rescue
830
+ configuration.async_handler.call(payload)
831
+ rescue StandardError
700
832
  if configuration.failover_handlers.empty?
701
833
  log_error '[Rollbar] Async handler failed, and there are no failover handlers configured. See the docs for "failover_handlers"'
702
834
  return
@@ -713,7 +845,7 @@ module Rollbar
713
845
  failover_handlers.each do |handler|
714
846
  begin
715
847
  handler.call(item.payload)
716
- rescue
848
+ rescue StandardError
717
849
  next unless handler == failover_handlers.last
718
850
 
719
851
  log_error "[Rollbar] All failover handlers failed while processing item: #{Rollbar::JSON.dump(item.payload)}"
@@ -721,7 +853,7 @@ module Rollbar
721
853
  end
722
854
  end
723
855
 
724
- alias_method :log_warning, :log_warn
856
+ alias log_warning log_warn
725
857
 
726
858
  def log_instance_link(data)
727
859
  return unless data[:uuid]
@@ -729,5 +861,9 @@ module Rollbar
729
861
  uuid_url = Util.uuid_rollbar_url(data, configuration)
730
862
  log_info "[Rollbar] Details: #{uuid_url} (only available if report was successful)"
731
863
  end
864
+
865
+ def via_failsafe?(item)
866
+ item.payload.fetch('data', {}).fetch('failsafe', false)
867
+ end
732
868
  end
733
869
  end
@@ -7,6 +7,8 @@ module Rollbar
7
7
  attr_reader :name
8
8
  attr_reader :dependencies
9
9
  attr_reader :callables
10
+ attr_reader :revert_callables
11
+ attr_accessor :on_demand
10
12
  attr_accessor :loaded
11
13
 
12
14
  private :loaded=
@@ -15,31 +17,73 @@ module Rollbar
15
17
  @name = name
16
18
  @dependencies = []
17
19
  @callables = []
20
+ @revert_callables = []
18
21
  @loaded = false
22
+ @on_demand = false
23
+ end
24
+
25
+ def load_on_demand
26
+ @on_demand = true
19
27
  end
20
28
 
21
29
  def configuration
22
30
  Rollbar.configuration
23
31
  end
24
32
 
33
+ def load_scoped!(transparent = false)
34
+ if transparent
35
+ load! if load?
36
+
37
+ result = yield
38
+
39
+ unload! if loaded
40
+ else
41
+ return unless load?
42
+
43
+ load!
44
+
45
+ result = yield
46
+
47
+ unload!
48
+ end
49
+
50
+ result
51
+ end
52
+
25
53
  def load!
26
54
  return unless load?
27
55
 
28
56
  begin
29
57
  callables.each(&:call)
30
- rescue => e
58
+ rescue StandardError => e
31
59
  log_loading_error(e)
32
60
  ensure
33
61
  self.loaded = true
34
62
  end
35
63
  end
36
64
 
65
+ def unload!
66
+ return unless loaded
67
+
68
+ begin
69
+ revert_callables.each(&:call)
70
+ rescue StandardError => e
71
+ log_unloading_error(e)
72
+ ensure
73
+ self.loaded = false
74
+ end
75
+ end
76
+
37
77
  def execute(&block)
38
78
  callables << block
39
79
  end
40
80
 
41
- def execute!(&block)
42
- block.call if load?
81
+ def execute!
82
+ yield if load?
83
+ end
84
+
85
+ def revert(&block)
86
+ revert_callables << block
43
87
  end
44
88
 
45
89
  private
@@ -61,7 +105,7 @@ module Rollbar
61
105
 
62
106
  def load?
63
107
  !loaded && dependencies_satisfy?
64
- rescue => e
108
+ rescue StandardError => e
65
109
  log_loading_error(e)
66
110
 
67
111
  false
@@ -71,8 +115,12 @@ module Rollbar
71
115
  dependencies.all?(&:call)
72
116
  end
73
117
 
74
- def log_loading_error(e)
75
- Rollbar.log_error("Error trying to load plugin '#{name}': #{e.class}, #{e.message}")
118
+ def log_loading_error(error)
119
+ Rollbar.log_error("Error trying to load plugin '#{name}': #{error.class}, #{error.message}")
120
+ end
121
+
122
+ def log_unloading_error(error)
123
+ Rollbar.log_error("Error trying to unload plugin '#{name}': #{error.class}, #{error.message}")
76
124
  end
77
125
  end
78
126
  end