rollbar 2.22.1 → 3.4.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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/pull_request_template.md +34 -0
  3. data/.github/workflows/ci.yml +104 -0
  4. data/.rubocop.yml +185 -33
  5. data/Gemfile +26 -28
  6. data/README.md +32 -8
  7. data/data/rollbar.snippet.js +1 -1
  8. data/docs/configuration.md +8 -0
  9. data/gemfiles/rails30.gemfile +17 -35
  10. data/gemfiles/rails31.gemfile +20 -37
  11. data/gemfiles/rails32.gemfile +13 -31
  12. data/gemfiles/rails40.gemfile +12 -32
  13. data/gemfiles/rails41.gemfile +11 -31
  14. data/gemfiles/rails42.gemfile +12 -32
  15. data/gemfiles/rails50.gemfile +16 -30
  16. data/gemfiles/rails51.gemfile +16 -30
  17. data/gemfiles/rails52.gemfile +10 -19
  18. data/gemfiles/rails60.gemfile +10 -25
  19. data/gemfiles/rails61.gemfile +52 -0
  20. data/gemfiles/rails70.gemfile +52 -0
  21. data/lib/generators/rollbar/rollbar_generator.rb +18 -14
  22. data/lib/rails/rollbar_runner.rb +11 -20
  23. data/lib/rollbar/capistrano.rb +17 -9
  24. data/lib/rollbar/capistrano3.rb +8 -2
  25. data/lib/rollbar/capistrano_tasks.rb +44 -8
  26. data/lib/rollbar/configuration.rb +138 -84
  27. data/lib/rollbar/delay/girl_friday.rb +3 -7
  28. data/lib/rollbar/delay/resque.rb +2 -3
  29. data/lib/rollbar/delay/shoryuken.rb +4 -3
  30. data/lib/rollbar/delay/sidekiq.rb +5 -5
  31. data/lib/rollbar/delay/sucker_punch.rb +4 -6
  32. data/lib/rollbar/delay/thread.rb +17 -2
  33. data/lib/rollbar/deploy.rb +8 -7
  34. data/lib/rollbar/encoding/encoder.rb +17 -6
  35. data/lib/rollbar/encoding.rb +2 -7
  36. data/lib/rollbar/exception_reporter.rb +17 -8
  37. data/lib/rollbar/item/backtrace.rb +22 -10
  38. data/lib/rollbar/item/frame.rb +8 -5
  39. data/lib/rollbar/item/locals.rb +49 -2
  40. data/lib/rollbar/item.rb +80 -50
  41. data/lib/rollbar/json.rb +2 -1
  42. data/lib/rollbar/language_support.rb +0 -6
  43. data/lib/rollbar/lazy_store.rb +3 -7
  44. data/lib/rollbar/logger.rb +2 -0
  45. data/lib/rollbar/logger_proxy.rb +3 -1
  46. data/lib/rollbar/middleware/js/json_value.rb +15 -5
  47. data/lib/rollbar/middleware/js.rb +70 -38
  48. data/lib/rollbar/middleware/rack/builder.rb +3 -3
  49. data/lib/rollbar/middleware/rack/test_session.rb +3 -3
  50. data/lib/rollbar/middleware/rack.rb +4 -4
  51. data/lib/rollbar/middleware/rails/rollbar.rb +9 -6
  52. data/lib/rollbar/middleware/rails/show_exceptions.rb +8 -4
  53. data/lib/rollbar/notifier/trace_with_bindings.rb +13 -3
  54. data/lib/rollbar/notifier.rb +309 -172
  55. data/lib/rollbar/plugin.rb +8 -8
  56. data/lib/rollbar/plugins/active_job.rb +20 -3
  57. data/lib/rollbar/plugins/delayed_job/plugin.rb +19 -2
  58. data/lib/rollbar/plugins/error_context.rb +11 -0
  59. data/lib/rollbar/plugins/goalie.rb +27 -16
  60. data/lib/rollbar/plugins/rails/controller_methods.rb +18 -14
  61. data/lib/rollbar/plugins/rails/railtie30.rb +2 -1
  62. data/lib/rollbar/plugins/rails/railtie32.rb +2 -1
  63. data/lib/rollbar/plugins/rails/railtie_mixin.rb +2 -2
  64. data/lib/rollbar/plugins/rails.rb +5 -2
  65. data/lib/rollbar/plugins/rake.rb +2 -1
  66. data/lib/rollbar/plugins/sidekiq/plugin.rb +39 -21
  67. data/lib/rollbar/plugins/sidekiq.rb +1 -1
  68. data/lib/rollbar/plugins/thread.rb +8 -7
  69. data/lib/rollbar/plugins/validations.rb +3 -1
  70. data/lib/rollbar/rake_tasks.rb +1 -2
  71. data/lib/rollbar/request_data_extractor.rb +53 -19
  72. data/lib/rollbar/rollbar_test.rb +9 -118
  73. data/lib/rollbar/scrubbers/params.rb +13 -7
  74. data/lib/rollbar/scrubbers/url.rb +56 -17
  75. data/lib/rollbar/scrubbers.rb +2 -6
  76. data/lib/rollbar/truncation/frames_strategy.rb +1 -1
  77. data/lib/rollbar/truncation/mixin.rb +1 -1
  78. data/lib/rollbar/truncation/remove_any_key_strategy.rb +4 -1
  79. data/lib/rollbar/truncation/remove_extra_strategy.rb +3 -1
  80. data/lib/rollbar/truncation/strings_strategy.rb +4 -2
  81. data/lib/rollbar/util/hash.rb +14 -7
  82. data/lib/rollbar/util/ip_anonymizer.rb +1 -1
  83. data/lib/rollbar/util.rb +23 -13
  84. data/lib/rollbar/version.rb +1 -1
  85. data/lib/rollbar.rb +12 -7
  86. data/lib/tasks/benchmark.rake +2 -1
  87. data/rollbar.gemspec +6 -3
  88. data/spec/support/rollbar_api.rb +67 -0
  89. metadata +19 -12
  90. data/.travis.yml +0 -281
  91. data/lib/rollbar/encoding/legacy_encoder.rb +0 -20
  92. /data/lib/generators/rollbar/templates/{initializer.rb → initializer.erb} +0 -0
@@ -15,11 +15,11 @@ module Rollbar
15
15
  # The notifier class. It has the core functionality
16
16
  # for sending reports to the API.
17
17
  class Notifier
18
- attr_accessor :configuration
19
- attr_accessor :last_report
20
- attr_accessor :scope_object
18
+ attr_accessor :configuration, :last_report, :scope_object
21
19
 
22
- @file_semaphore = Mutex.new
20
+ MUTEX = Mutex.new
21
+ EXTENSION_REGEXP = /.rollbar\z/.freeze
22
+ FAILSAFE_STRING_LENGTH = 10_000
23
23
 
24
24
  def initialize(parent_notifier = nil, payload_options = nil, scope = nil)
25
25
  if parent_notifier
@@ -32,7 +32,9 @@ module Rollbar
32
32
  self.scope_object = ::Rollbar::LazyStore.new(scope)
33
33
  end
34
34
 
35
- Rollbar::Util.deep_merge(configuration.payload_options, payload_options) if payload_options
35
+ return unless payload_options
36
+
37
+ Rollbar::Util.deep_merge(configuration.payload_options, payload_options)
36
38
  end
37
39
 
38
40
  def reset!
@@ -103,10 +105,10 @@ module Rollbar
103
105
 
104
106
  # Sends a report to Rollbar.
105
107
  #
106
- # Accepts any number of arguments. The last String argument will become
107
- # the message or description of the report. The last Exception argument
108
- # will become the associated exception for the report. The last hash
109
- # 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.
110
112
  #
111
113
  # If the extra hash contains a symbol key :custom_data_method_context
112
114
  # the value of the key will be used as the context for
@@ -117,14 +119,14 @@ module Rollbar
117
119
  # begin
118
120
  # foo = bar
119
121
  # rescue => e
120
- # Rollbar.log(e)
122
+ # Rollbar.log('error', e)
121
123
  # end
122
124
  #
123
125
  # @example
124
- # Rollbar.log('This is a simple log message')
126
+ # Rollbar.log('info', 'This is a simple log message')
125
127
  #
126
128
  # @example
127
- # Rollbar.log(e, 'This is a description of the exception')
129
+ # Rollbar.log('error', e, 'This is a description of the exception')
128
130
  #
129
131
  def log(level, *args)
130
132
  return 'disabled' unless enabled?
@@ -132,17 +134,8 @@ module Rollbar
132
134
  message, exception, extra, context = extract_arguments(args)
133
135
  use_exception_level_filters = use_exception_level_filters?(extra)
134
136
 
135
- return 'ignored' if ignored?(exception, use_exception_level_filters)
136
-
137
- begin
138
- status = call_before_process(:level => level,
139
- :exception => exception,
140
- :message => message,
141
- :extra => extra)
142
- return 'ignored' if status == 'ignored'
143
- rescue Rollbar::Ignore
144
- return 'ignored'
145
- end
137
+ return 'ignored' if ignored?(exception, use_exception_level_filters) ||
138
+ ignore_before_process?(level, exception, message, extra)
146
139
 
147
140
  level = lookup_exception_level(level, exception,
148
141
  use_exception_level_filters)
@@ -154,10 +147,27 @@ module Rollbar
154
147
  ret
155
148
  end
156
149
 
150
+ def ignore_before_process?(level, exception, message, extra)
151
+ status = call_before_process(:level => level,
152
+ :exception => exception,
153
+ :message => message,
154
+ :extra => extra)
155
+
156
+ status == 'ignored'
157
+ rescue Rollbar::Ignore
158
+ true
159
+ end
160
+
157
161
  def report_with_rescue(level, message, exception, extra, context)
158
162
  report(level, message, exception, extra, context)
159
163
  rescue StandardError, SystemStackError => e
160
- report_internal_error(e)
164
+ original_error = {
165
+ :message => message,
166
+ :exception => exception,
167
+ :configuration => configuration
168
+ }
169
+
170
+ report_internal_error(e, original_error)
161
171
 
162
172
  'error'
163
173
  end
@@ -194,24 +204,23 @@ module Rollbar
194
204
 
195
205
  def enabled?
196
206
  # Require access_token so we don't try to send events when unconfigured.
197
- configuration.enabled && configuration.access_token && !configuration.access_token.empty?
207
+ configuration.enabled &&
208
+ configuration.access_token &&
209
+ !configuration.access_token.empty?
198
210
  end
199
211
 
200
212
  def process_item(item)
201
- if configuration.write_to_file
202
- if configuration.use_async
203
- @file_semaphore.synchronize do
204
- write_item(item)
205
- end
206
- else
207
- write_item(item)
208
- end
209
- else
210
- send_item(item)
211
- end
213
+ return send_item(item) unless configuration.write_to_file
214
+
215
+ return do_write_item(item) unless configuration.use_async
216
+
217
+ MUTEX.synchronize { do_write_item(item) }
212
218
  rescue StandardError => e
213
- log_error("[Rollbar] Error processing the item: #{e.class}, #{e.message}. Item: #{item.payload.inspect}")
214
- raise e
219
+ log_error '[Rollbar] Error processing the item: ' \
220
+ "#{e.class}, #{e.message}. Item: #{item.payload.inspect}"
221
+ raise e unless via_failsafe?(item)
222
+
223
+ log_error('[Rollbar] Item has already failed. Not re-raising')
215
224
  end
216
225
 
217
226
  # We will reraise exceptions in this method so async queues
@@ -238,16 +247,16 @@ module Rollbar
238
247
  # Using Rollbar.silenced we avoid the above behavior but Sidekiq
239
248
  # will have a chance to retry the original job.
240
249
  def process_from_async_handler(payload)
241
- payload = Rollbar::JSON.load(payload) if payload.is_a?(String)
242
-
243
- item = Item.build_with(payload,
244
- :notifier => self,
245
- :configuration => configuration,
246
- :logger => logger)
247
-
248
250
  Rollbar.silenced do
249
251
  begin
250
- process_item(item)
252
+ if payload.is_a?(String)
253
+ # The final payload has already been built.
254
+ send_body(payload)
255
+ else
256
+ item = build_item_with_payload(payload)
257
+
258
+ process_item(item)
259
+ end
251
260
  rescue StandardError => e
252
261
  report_internal_error(e)
253
262
 
@@ -256,51 +265,108 @@ module Rollbar
256
265
  end
257
266
  end
258
267
 
259
- def send_failsafe(message, exception, uuid = nil, host = nil)
260
- exception_reason = failsafe_reason(message, exception)
261
-
262
- log_error "[Rollbar] Sending failsafe response due to #{exception_reason}"
263
-
264
- body = failsafe_body(exception_reason)
268
+ def build_item_with_payload(payload)
269
+ Item.build_with(payload, :notifier => self,
270
+ :configuration => configuration,
271
+ :logger => logger)
272
+ end
265
273
 
266
- failsafe_data = {
274
+ def failsafe_initial_data(exception_reason)
275
+ {
267
276
  :level => 'error',
268
277
  :environment => configuration.environment.to_s,
269
278
  :body => {
270
279
  :message => {
271
- :body => body
280
+ :body => failsafe_body(exception_reason)
272
281
  }
273
282
  },
274
283
  :notifier => {
275
284
  :name => 'rollbar-gem',
276
285
  :version => VERSION
277
286
  },
278
- :custom => {
279
- :orig_uuid => uuid,
280
- :orig_host => host
281
- },
282
287
  :internal => true,
283
- :failsafe => true
288
+ 'failsafe' => true
284
289
  }
290
+ end
291
+
292
+ def send_failsafe(message, exception, original_error = nil)
293
+ exception_reason = failsafe_reason(message, exception)
294
+
295
+ log_error "[Rollbar] Sending failsafe response due to #{exception_reason}"
296
+
297
+ failsafe_data = failsafe_initial_data(exception_reason)
298
+
299
+ failsafe_add_original_error_data(failsafe_data[:notifier], original_error)
285
300
 
286
301
  failsafe_payload = {
287
- 'access_token' => configuration.access_token,
288
302
  'data' => failsafe_data
289
303
  }
290
304
 
291
- begin
292
- item = Item.build_with(failsafe_payload,
293
- :notifier => self,
294
- :configuration => configuration,
295
- :logger => logger)
296
- schedule_item(item)
297
- rescue StandardError => e
298
- log_error "[Rollbar] Error sending failsafe : #{e}"
299
- end
305
+ process_failsafe_item(failsafe_payload)
300
306
 
301
307
  failsafe_payload
302
308
  end
303
309
 
310
+ def process_failsafe_item(failsafe_payload)
311
+ item = build_item_with_payload(failsafe_payload)
312
+ process_item(item)
313
+ log_and_return_item_data(item)
314
+ rescue StandardError => e
315
+ log_error "[Rollbar] Error sending failsafe : #{e}"
316
+ end
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
+ if original_error[:message]
332
+ diagnostic[:original_message] =
333
+ original_error[:message].truncate(FAILSAFE_STRING_LENGTH)
334
+ end
335
+ rescue StandardError => e
336
+ diagnostic[:original_message] = "Failed: #{e.message}"
337
+ end
338
+
339
+ def add_original_error(diagnostic, original_error)
340
+ if original_error[:exception]
341
+ backtrace = original_error[:exception].backtrace
342
+ message = original_error[:exception].message
343
+ diagnostic[:original_error] = {
344
+ :message => message && message.truncate(FAILSAFE_STRING_LENGTH),
345
+ :stack => backtrace && backtrace.join(', ').truncate(FAILSAFE_STRING_LENGTH)
346
+ }
347
+ end
348
+ rescue StandardError => e
349
+ diagnostic[:original_error] = "Failed: #{e.message}"
350
+ end
351
+
352
+ def add_configured_options(payload_notifier, original_error)
353
+ if original_error[:configuration]
354
+ configured = original_error[:configuration].configured_options.configured
355
+ payload_notifier[:configured_options] =
356
+ ::JSON.generate(configured).truncate(FAILSAFE_STRING_LENGTH)
357
+ end
358
+ rescue StandardError => e
359
+ payload_notifier[:configured_options] = "Failed: #{e.message}"
360
+ end
361
+
362
+ def add_original_host(diagnostic, original_error)
363
+ diagnostic[:original_host] = original_error[:host] if original_error[:host]
364
+ end
365
+
366
+ def add_original_uuid(diagnostic, original_error)
367
+ diagnostic[:original_uuid] = original_error[:uuid] if original_error[:uuid]
368
+ end
369
+
304
370
  ## Logging
305
371
  %w[debug info warn error].each do |level|
306
372
  define_method(:"log_#{level}") do |message|
@@ -325,7 +391,8 @@ module Rollbar
325
391
  end
326
392
 
327
393
  def enable_locals?
328
- configuration.locals[:enabled] && [:app, :all].include?(configuration.send_extra_frame_data)
394
+ configuration.locals[:enabled] &&
395
+ [:app, :all].include?(configuration.send_extra_frame_data)
329
396
  end
330
397
 
331
398
  def enable_locals
@@ -347,13 +414,7 @@ module Rollbar
347
414
  end
348
415
 
349
416
  def call_before_process(options)
350
- options = {
351
- :level => options[:level],
352
- :scope => scope_object,
353
- :exception => options[:exception],
354
- :message => options[:message],
355
- :extra => options[:extra]
356
- }
417
+ options = options_for_handler(options)
357
418
  handlers = configuration.before_process
358
419
 
359
420
  handlers.each do |handler|
@@ -370,24 +431,30 @@ module Rollbar
370
431
  end
371
432
  end
372
433
 
434
+ def options_for_handler(options)
435
+ {
436
+ :level => options[:level],
437
+ :scope => scope_object,
438
+ :exception => options[:exception],
439
+ :message => options[:message],
440
+ :extra => options[:extra]
441
+ }
442
+ end
443
+
373
444
  def extract_arguments(args)
374
- message = nil
375
- exception = nil
376
- extra = nil
377
- context = nil
445
+ message = exception = extra = context = nil
378
446
 
379
447
  args.each do |arg|
380
448
  if arg.is_a?(String)
381
449
  message = arg
382
450
  elsif arg.is_a?(Exception)
383
451
  exception = arg
384
- elsif RUBY_PLATFORM == 'java' && arg.is_a?(java.lang.Throwable)
452
+ elsif java_exception?(arg)
385
453
  exception = arg
386
454
  elsif arg.is_a?(Hash)
387
455
  extra = arg
388
456
 
389
- context = extra[:custom_data_method_context]
390
- extra.delete :custom_data_method_context
457
+ context = extra.delete :custom_data_method_context
391
458
 
392
459
  extra = nil if extra.empty?
393
460
  end
@@ -396,6 +463,10 @@ module Rollbar
396
463
  [message, exception, extra, context]
397
464
  end
398
465
 
466
+ def java_exception?(obj)
467
+ RUBY_PLATFORM == 'java' && obj.is_a?(java.lang.Throwable)
468
+ end
469
+
399
470
  def lookup_exception_level(orig_level, exception, use_exception_level_filters)
400
471
  return orig_level unless use_exception_level_filters
401
472
 
@@ -426,7 +497,9 @@ module Rollbar
426
497
 
427
498
  def report(level, message, exception, extra, context)
428
499
  unless message || exception || extra
429
- log_error '[Rollbar] Tried to send a report with no message, exception or extra data.'
500
+ log_error(
501
+ '[Rollbar] Tried to send a report with no message, exception or extra data.'
502
+ )
430
503
 
431
504
  return 'error'
432
505
  end
@@ -453,37 +526,48 @@ module Rollbar
453
526
  log_info "[Rollbar] Data: #{data}"
454
527
  end
455
528
 
456
- # Reports an internal error in the Rollbar library. This will be reported within the configured
457
- # Rollbar project. We'll first attempt to provide a report including the exception traceback.
458
- # If that fails, we'll fall back to a more static failsafe response.
459
- def report_internal_error(exception)
460
- log_error '[Rollbar] Reporting internal error encountered while sending data to Rollbar.'
529
+ # Reports an internal error in the Rollbar library. This will be reported
530
+ # within the configured Rollbar project. We'll first attempt to provide a
531
+ # report including the exception traceback. If that fails, we'll fall back
532
+ # to a more static failsafe response.
533
+ def report_internal_error(exception, original_error = nil)
534
+ return if skip_reporting_internal_error(exception)
535
+
536
+ failsafe_message = ''
537
+ log_error(
538
+ '[Rollbar] Reporting internal error encountered while sending data to Rollbar.'
539
+ )
461
540
 
462
541
  configuration.execute_hook(:on_report_internal_error, exception)
463
542
 
464
- begin
465
- item = build_item('error', nil, exception, { :internal => true }, nil)
466
- rescue StandardError => e
467
- send_failsafe('build_item in exception_data', e)
468
- log_error "[Rollbar] Exception: #{exception}"
469
- return
470
- end
543
+ failsafe_message = 'build_item in exception_data'
544
+ item = build_item('error', nil, exception, { :internal => true }, nil)
471
545
 
472
- begin
473
- process_item(item)
474
- rescue StandardError => e
475
- send_failsafe('error in process_item', e)
476
- log_error "[Rollbar] Item: #{item}"
477
- return
478
- end
546
+ failsafe_message = 'error in process_item'
547
+ process_item(item)
479
548
 
480
- begin
481
- log_instance_link(item['data'])
482
- rescue StandardError => e
483
- send_failsafe('error logging instance link', e)
484
- log_error "[Rollbar] Item: #{item}"
485
- return
549
+ failsafe_message = 'error logging instance link'
550
+ log_instance_link(item['data'])
551
+ rescue StandardError => e
552
+ send_failsafe(failsafe_message, e, original_error)
553
+ log_error(item ? "[Rollbar] Item: #{item}" : "[Rollbar] Exception: #{exception}")
554
+ end
555
+
556
+ def skip_reporting_internal_error(exception)
557
+ return true if configuration.ignore_internal_errors == true
558
+
559
+ configuration.ignore_internal_errors.each do |error_name|
560
+ begin
561
+ error_cls = error_name.split('::').reduce(Module, :const_get)
562
+ return true if exception.class <= error_cls
563
+ rescue NameError
564
+ # Ignore errors and continue matching.
565
+ # It's possible for a class name in the list to not be resolvable,
566
+ # and this is ok.
567
+ end
486
568
  end
569
+
570
+ false
487
571
  end
488
572
 
489
573
  ## Payload building functions
@@ -509,25 +593,35 @@ module Rollbar
509
593
 
510
594
  ## Delivery functions
511
595
 
512
- def send_item_using_eventmachine(item, uri)
513
- body = item.dump
514
- return unless body
596
+ def send_using_eventmachine(body)
597
+ uri = URI.parse(configuration.endpoint)
515
598
 
516
- headers = { 'X-Rollbar-Access-Token' => item['access_token'] }
599
+ headers = { 'X-Rollbar-Access-Token' => configuration.access_token }
517
600
  options = http_proxy_for_em(uri)
518
- req = EventMachine::HttpRequest.new(uri.to_s, options).post(:body => body, :head => headers)
601
+ req = EventMachine::HttpRequest.new(uri.to_s, options).post(:body => body,
602
+ :head => headers)
603
+
604
+ eventmachine_callback(req)
605
+ eventmachine_errback(req)
606
+ end
519
607
 
608
+ def eventmachine_callback(req)
520
609
  req.callback do
521
610
  if req.response_header.status == 200
522
611
  log_info '[Rollbar] Success'
523
612
  else
524
- log_warning "[Rollbar] Got unexpected status code from Rollbar.io api: #{req.response_header.status}"
613
+ log_warning '[Rollbar] Got unexpected status code from Rollbar.io api: ' \
614
+ "#{req.response_header.status}"
525
615
  log_info "[Rollbar] Response: #{req.response}"
526
616
  end
527
617
  end
618
+ end
528
619
 
620
+ def eventmachine_errback(req)
529
621
  req.errback do
530
- log_warning "[Rollbar] Call to API failed, status code: #{req.response_header.status}"
622
+ log_warning(
623
+ "[Rollbar] Call to API failed, status code: #{req.response_header.status}"
624
+ )
531
625
  log_info "[Rollbar] Error's response: #{req.response}"
532
626
  end
533
627
  end
@@ -538,40 +632,61 @@ module Rollbar
538
632
  body = item.dump
539
633
  return unless body
540
634
 
541
- uri = URI.parse(configuration.endpoint)
542
-
543
635
  if configuration.use_eventmachine
544
- send_item_using_eventmachine(item, uri)
636
+ send_using_eventmachine(body)
545
637
  return
546
638
  end
547
639
 
548
- handle_response(do_post(uri, body, item['access_token']))
640
+ send_body(body)
641
+ end
642
+
643
+ def send_body(body)
644
+ log_info '[Rollbar] Sending json'
645
+
646
+ uri = URI.parse(configuration.endpoint)
647
+
648
+ handle_response(do_post(uri, body, configuration.access_token))
549
649
  end
550
650
 
551
651
  def do_post(uri, body, access_token)
652
+ http = init_http(uri)
653
+
654
+ request = Net::HTTP::Post.new(uri.request_uri)
655
+
656
+ request.body = pack_ruby260_bytes(body)
657
+
658
+ # Ensure the payload token will be used if the option is set.
659
+ unless configuration.use_payload_access_token
660
+ request.add_field('X-Rollbar-Access-Token', access_token)
661
+ end
662
+
663
+ handle_net_retries { http.request(request) }
664
+ end
665
+
666
+ def init_http(uri)
552
667
  proxy = http_proxy(uri)
553
- http = Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port, proxy.user, proxy.password)
668
+ http = Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port, proxy.user,
669
+ proxy.password)
554
670
 
555
- http.open_timeout = configuration.open_timeout
556
- http.read_timeout = configuration.request_timeout
671
+ init_http_timeouts(http)
557
672
 
558
673
  if uri.scheme == 'https'
559
674
  http.use_ssl = true
560
675
  http.verify_mode = ssl_verify_mode
561
676
  end
562
677
 
563
- request = Net::HTTP::Post.new(uri.request_uri)
564
-
565
- request.body = pack_ruby260_bytes(body)
566
- request.add_field('X-Rollbar-Access-Token', access_token)
678
+ http
679
+ end
567
680
 
568
- handle_net_retries { http.request(request) }
681
+ def init_http_timeouts(http)
682
+ http.open_timeout = configuration.open_timeout
683
+ http.read_timeout = configuration.request_timeout
569
684
  end
570
685
 
571
686
  def pack_ruby260_bytes(body)
572
687
  # Ruby 2.6.0 shipped with a bug affecting multi-byte body for Net::HTTP.
573
688
  # Fix (committed one day after 2.6.0p0 shipped) is here:
574
- # https://github.com/ruby/ruby/commit/1680a13a926b17661329beec1ded6b32aad16c1b#diff-00a99d8c71daaf5fc60a050da41f7261
689
+ # ruby/ruby/commit/1680a13a926b17661329beec1ded6b32aad16c1b
575
690
  #
576
691
  # We work around this by repacking the body as single byte chars if needed.
577
692
  if RUBY_VERSION == '2.6.0' && multibyte?(body)
@@ -621,8 +736,6 @@ module Rollbar
621
736
  end
622
737
 
623
738
  def handle_net_retries
624
- return yield if skip_retries?
625
-
626
739
  retries = configuration.net_retries - 1
627
740
 
628
741
  begin
@@ -636,15 +749,13 @@ module Rollbar
636
749
  end
637
750
  end
638
751
 
639
- def skip_retries?
640
- Rollbar::LanguageSupport.ruby_19?
641
- end
642
-
643
752
  def handle_response(response)
644
753
  if response.code == '200'
645
754
  log_info '[Rollbar] Success'
646
755
  else
647
- log_warning "[Rollbar] Got unexpected status code from Rollbar api: #{response.code}"
756
+ log_warning(
757
+ "[Rollbar] Got unexpected status code from Rollbar api: #{response.code}"
758
+ )
648
759
  log_info "[Rollbar] Response: #{response.body}"
649
760
  configuration.execute_hook(:on_error_response, response)
650
761
  end
@@ -658,27 +769,20 @@ module Rollbar
658
769
  end
659
770
  end
660
771
 
661
- def write_item(item)
662
- if configuration.use_async
663
- @file_semaphore.synchronize do
664
- do_write_item(item)
665
- end
666
- else
667
- do_write_item(item)
668
- end
669
- end
670
-
671
772
  def do_write_item(item)
672
773
  log_info '[Rollbar] Writing item to file'
673
774
 
674
775
  body = item.dump
675
776
  return unless body
676
777
 
778
+ file_name = file_name_with_pid(configuration)
779
+
677
780
  begin
678
- @file ||= File.open(configuration.filepath, 'a')
781
+ @file ||= File.open(file_name, 'a')
679
782
 
680
783
  @file.puts(body)
681
784
  @file.flush
785
+ update_file(@file, file_name)
682
786
 
683
787
  log_info '[Rollbar] Success'
684
788
  rescue IOError => e
@@ -686,32 +790,54 @@ module Rollbar
686
790
  end
687
791
  end
688
792
 
793
+ def file_name_with_pid(configuration)
794
+ if configuration.files_with_pid_name_enabled
795
+ configuration.filepath.gsub(EXTENSION_REGEXP, "_#{Process.pid}\\0")
796
+ else
797
+ configuration.filepath
798
+ end
799
+ end
800
+
801
+ def update_file(file, file_name)
802
+ return unless configuration.files_processed_enabled
803
+
804
+ time_now = Time.now
805
+ if configuration.files_processed_duration > time_now - file.birthtime &&
806
+ file.size < configuration.files_processed_size
807
+ return
808
+ end
809
+
810
+ new_file_name = file_name.gsub(EXTENSION_REGEXP, "_processed_#{time_now.to_i}\\0")
811
+ File.rename(file, new_file_name)
812
+ file.close
813
+ @file = File.open(file_name, 'a')
814
+ end
815
+
689
816
  def failsafe_reason(message, exception)
690
- body = ''
817
+ return failsafe_exception_reason(message, exception) if exception
691
818
 
692
- if exception
693
- begin
694
- backtrace = exception.backtrace || []
695
- nearest_frame = backtrace[0]
819
+ message.to_s
820
+ rescue StandardError
821
+ log_error('[Rollbar] Error building failsafe message')
822
+ ''
823
+ end
696
824
 
697
- exception_info = exception.class.name
698
- # #to_s and #message defaults to class.to_s. Add message only if add valuable info.
699
- exception_info += %[: "#{exception.message}"] if exception.message != exception.class.to_s
700
- exception_info += " in #{nearest_frame}" if nearest_frame
825
+ def failsafe_exception_reason(message, exception)
826
+ backtrace = exception.backtrace || []
827
+ nearest_frame = backtrace[0]
701
828
 
702
- body += "#{exception_info}: #{message}"
703
- rescue StandardError
704
- log_error('[Rollbar] Error building failsafe exception message')
705
- end
706
- else
707
- begin
708
- body += message.to_s
709
- rescue StandardError
710
- log_error('[Rollbar] Error building failsafe message')
711
- end
829
+ exception_info = exception.class.name
830
+ # #to_s and #message defaults to class.to_s.
831
+ # Add message only if add valuable info.
832
+ if exception.message != exception.class.to_s
833
+ exception_info += %[: "#{exception.message}"]
712
834
  end
835
+ exception_info += " in #{nearest_frame}" if nearest_frame
713
836
 
714
- body
837
+ "#{exception_info}: #{message}"
838
+ rescue StandardError
839
+ log_error('[Rollbar] Error building failsafe exception message')
840
+ ''
715
841
  end
716
842
 
717
843
  def failsafe_body(reason)
@@ -737,11 +863,15 @@ module Rollbar
737
863
  end
738
864
 
739
865
  def process_async_item(item)
866
+ # Send async payloads as JSON string when async_json_payload is set.
867
+ payload = configuration.async_json_payload ? item.dump : item.payload
868
+
740
869
  configuration.async_handler ||= default_async_handler
741
- configuration.async_handler.call(item.payload)
870
+ configuration.async_handler.call(payload)
742
871
  rescue StandardError
743
872
  if configuration.failover_handlers.empty?
744
- log_error '[Rollbar] Async handler failed, and there are no failover handlers configured. See the docs for "failover_handlers"'
873
+ log_error '[Rollbar] Async handler failed, and there are no failover ' \
874
+ 'handlers configured. See the docs for "failover_handlers"'
745
875
  return
746
876
  end
747
877
 
@@ -759,7 +889,8 @@ module Rollbar
759
889
  rescue StandardError
760
890
  next unless handler == failover_handlers.last
761
891
 
762
- log_error "[Rollbar] All failover handlers failed while processing item: #{Rollbar::JSON.dump(item.payload)}"
892
+ log_error '[Rollbar] All failover handlers failed while processing ' \
893
+ "item: #{Rollbar::JSON.dump(item.payload)}"
763
894
  end
764
895
  end
765
896
  end
@@ -770,7 +901,13 @@ module Rollbar
770
901
  return unless data[:uuid]
771
902
 
772
903
  uuid_url = Util.uuid_rollbar_url(data, configuration)
773
- log_info "[Rollbar] Details: #{uuid_url} (only available if report was successful)"
904
+ log_info(
905
+ "[Rollbar] Details: #{uuid_url} (only available if report was successful)"
906
+ )
907
+ end
908
+
909
+ def via_failsafe?(item)
910
+ item.payload.fetch('data', {}).fetch('failsafe', false)
774
911
  end
775
912
  end
776
913
  end