rollbar 2.19.2 → 2.19.3

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 (68) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +27 -0
  3. data/Appraisals +10 -10
  4. data/Gemfile +2 -0
  5. data/README.md +4 -1
  6. data/Rakefile +0 -0
  7. data/data/rollbar.snippet.js +1 -1
  8. data/gemfiles/rails30.gemfile +2 -0
  9. data/gemfiles/rails31.gemfile +2 -0
  10. data/gemfiles/rails32.gemfile +2 -0
  11. data/gemfiles/rails40.gemfile +2 -0
  12. data/gemfiles/rails41.gemfile +2 -0
  13. data/gemfiles/rails42.gemfile +2 -0
  14. data/gemfiles/rails50.gemfile +2 -0
  15. data/gemfiles/rails51.gemfile +2 -0
  16. data/gemfiles/rails52.gemfile +2 -0
  17. data/gemfiles/ruby_1_8_and_1_9_2.gemfile +2 -0
  18. data/lib/generators/rollbar/rollbar_generator.rb +1 -1
  19. data/lib/rails/rollbar_runner.rb +1 -1
  20. data/lib/rollbar.rb +2 -3
  21. data/lib/rollbar/capistrano3.rb +6 -3
  22. data/lib/rollbar/capistrano_tasks.rb +13 -15
  23. data/lib/rollbar/configuration.rb +10 -8
  24. data/lib/rollbar/delay/girl_friday.rb +2 -2
  25. data/lib/rollbar/delay/resque.rb +4 -6
  26. data/lib/rollbar/delay/sidekiq.rb +6 -10
  27. data/lib/rollbar/delay/sucker_punch.rb +17 -19
  28. data/lib/rollbar/delay/thread.rb +2 -2
  29. data/lib/rollbar/deploy.rb +47 -30
  30. data/lib/rollbar/encoding/encoder.rb +9 -9
  31. data/lib/rollbar/item.rb +7 -7
  32. data/lib/rollbar/item/backtrace.rb +4 -4
  33. data/lib/rollbar/item/frame.rb +7 -1
  34. data/lib/rollbar/item/locals.rb +56 -0
  35. data/lib/rollbar/json.rb +5 -2
  36. data/lib/rollbar/json/default.rb +1 -1
  37. data/lib/rollbar/json/oj.rb +1 -1
  38. data/lib/rollbar/language_support.rb +1 -1
  39. data/lib/rollbar/lazy_store.rb +5 -5
  40. data/lib/rollbar/logger.rb +1 -0
  41. data/lib/rollbar/logger_proxy.rb +1 -1
  42. data/lib/rollbar/middleware/js.rb +15 -15
  43. data/lib/rollbar/middleware/rack.rb +4 -1
  44. data/lib/rollbar/middleware/rails/rollbar.rb +10 -1
  45. data/lib/rollbar/notifier.rb +40 -15
  46. data/lib/rollbar/notifier/trace_with_bindings.rb +65 -0
  47. data/lib/rollbar/plugin.rb +54 -6
  48. data/lib/rollbar/plugins.rb +7 -1
  49. data/lib/rollbar/plugins/basic_socket.rb +21 -6
  50. data/lib/rollbar/plugins/delayed_job/job_data.rb +3 -3
  51. data/lib/rollbar/plugins/delayed_job/plugin.rb +2 -2
  52. data/lib/rollbar/plugins/goalie.rb +11 -3
  53. data/lib/rollbar/plugins/rails/controller_methods.rb +15 -3
  54. data/lib/rollbar/plugins/rake.rb +2 -2
  55. data/lib/rollbar/plugins/sidekiq/plugin.rb +5 -4
  56. data/lib/rollbar/rake_tasks.rb +2 -2
  57. data/lib/rollbar/request_data_extractor.rb +21 -18
  58. data/lib/rollbar/scrubbers.rb +7 -3
  59. data/lib/rollbar/scrubbers/params.rb +17 -16
  60. data/lib/rollbar/scrubbers/url.rb +8 -3
  61. data/lib/rollbar/truncation.rb +1 -1
  62. data/lib/rollbar/truncation/strings_strategy.rb +1 -1
  63. data/lib/rollbar/util/ip_anonymizer.rb +8 -7
  64. data/lib/rollbar/util/ip_obfuscator.rb +1 -1
  65. data/lib/rollbar/version.rb +1 -1
  66. data/lib/tasks/benchmark.rake +103 -0
  67. data/rollbar.gemspec +13 -4
  68. metadata +12 -5
@@ -23,12 +23,10 @@ module Rollbar
23
23
  end
24
24
 
25
25
  def perform(payload)
26
- begin
27
- Rollbar.process_from_async_handler(payload)
28
- rescue
29
- # Raise the exception so Resque can track the errored job
30
- raise
31
- end
26
+ Rollbar.process_from_async_handler(payload)
27
+ rescue StandardError
28
+ # Raise the exception so Resque can track the errored job
29
+ raise
32
30
  end
33
31
  end
34
32
  end
@@ -10,21 +10,17 @@ module Rollbar
10
10
  end
11
11
 
12
12
  def call(payload)
13
- if ::Sidekiq::Client.push(@options.merge('args' => [payload])) == nil
14
- raise StandardError.new "Unable to push the job to Sidekiq"
15
- end
13
+ raise StandardError, 'Unable to push the job to Sidekiq' if ::Sidekiq::Client.push(@options.merge('args' => [payload])).nil?
16
14
  end
17
15
 
18
16
  include ::Sidekiq::Worker
19
17
 
20
18
  def perform(*args)
21
- begin
22
- Rollbar.process_from_async_handler(*args)
23
- rescue
24
- # Raise the exception so Sidekiq can track the errored job
25
- # and retry it
26
- raise
27
- end
19
+ Rollbar.process_from_async_handler(*args)
20
+ rescue StandardError
21
+ # Raise the exception so Sidekiq can track the errored job
22
+ # and retry it
23
+ raise
28
24
  end
29
25
  end
30
26
  end
@@ -16,11 +16,11 @@ module Rollbar
16
16
  def self.setup
17
17
  major_version = ::SuckerPunch::VERSION.split.first.to_i
18
18
 
19
- if major_version > 1
20
- self.perform_proc = proc { |payload| perform_async(payload) }
21
- else
22
- self.perform_proc = proc { |payload| new.async.perform(payload) }
23
- end
19
+ self.perform_proc = if major_version > 1
20
+ proc { |payload| perform_async(payload) }
21
+ else
22
+ proc { |payload| new.async.perform(payload) }
23
+ end
24
24
 
25
25
  self.ready = true
26
26
  end
@@ -32,20 +32,18 @@ module Rollbar
32
32
  end
33
33
 
34
34
  def perform(*args)
35
- begin
36
- Rollbar.process_from_async_handler(*args)
37
- rescue
38
- # SuckerPunch can configure an exception handler with:
39
- #
40
- # SuckerPunch.exception_handler { # do something here }
41
- #
42
- # This is just passed to Celluloid.exception_handler which will
43
- # push the reiceved block to an array of handlers, by default empty, [].
44
- #
45
- # We reraise the exception here casue it's safe and users could have defined
46
- # their own exception handler for SuckerPunch
47
- raise
48
- end
35
+ Rollbar.process_from_async_handler(*args)
36
+ rescue StandardError
37
+ # SuckerPunch can configure an exception handler with:
38
+ #
39
+ # SuckerPunch.exception_handler { # do something here }
40
+ #
41
+ # This is just passed to Celluloid.exception_handler which will
42
+ # push the reiceved block to an array of handlers, by default empty, [].
43
+ #
44
+ # We reraise the exception here casue it's safe and users could have defined
45
+ # their own exception handler for SuckerPunch
46
+ raise
49
47
  end
50
48
  end
51
49
  end
@@ -1,4 +1,3 @@
1
- require 'thread'
2
1
  require 'timeout'
3
2
 
4
3
  module Rollbar
@@ -29,6 +28,7 @@ module Rollbar
29
28
 
30
29
  def spawn_threads_reaper
31
30
  return if @spawned
31
+
32
32
  @spawned = true
33
33
 
34
34
  @reaper ||= build_reaper_thread
@@ -65,7 +65,7 @@ module Rollbar
65
65
  ::Thread.new do
66
66
  begin
67
67
  Rollbar.process_from_async_handler(payload)
68
- rescue
68
+ rescue StandardError
69
69
  # Here we swallow the exception:
70
70
  # 1. The original report wasn't sent.
71
71
  # 2. An internal error was sent and logged
@@ -1,72 +1,89 @@
1
- require 'capistrano'
2
-
3
1
  module Rollbar
4
2
  # Deploy Tracking API wrapper module
5
3
  module Deploy
6
4
  ENDPOINT = 'https://api.rollbar.com/api/1/deploy/'.freeze
7
5
 
8
- def self.report(opts = {}, access_token:, environment:, revision:)
6
+ def self.report(opts, access_token, environment, revision)
9
7
  return {} unless access_token && !access_token.empty?
10
8
 
11
9
  opts[:status] ||= :started
12
10
 
13
- uri = URI.parse(::Rollbar::Deploy::ENDPOINT)
11
+ uri = ::URI.parse(::Rollbar::Deploy::ENDPOINT)
14
12
 
15
- request = Net::HTTP::Post.new(uri.request_uri)
16
- request.body = ::JSON.dump({
13
+ request_data = {
17
14
  :access_token => access_token,
18
15
  :environment => environment,
19
16
  :revision => revision
20
- }.merge(opts))
17
+ }.merge(opts)
18
+ request_data.delete(:proxy)
19
+ request_data.delete(:dry_run)
20
+
21
+ request = ::Net::HTTP::Post.new(uri.request_uri)
22
+ request.body = ::JSON.dump(request_data)
21
23
 
22
- send_request(opts, :uri => uri, :request => request)
24
+ send_request(opts, uri, request)
23
25
  end
24
26
 
25
- def self.update(opts = {}, deploy_id:, access_token:, status:)
27
+ def self.update(opts, access_token, deploy_id, status)
26
28
  return {} unless access_token && !access_token.empty?
27
29
 
28
- uri = URI.parse(
30
+ uri = ::URI.parse(
29
31
  ::Rollbar::Deploy::ENDPOINT +
30
32
  deploy_id.to_s +
31
33
  '?access_token=' + access_token
32
34
  )
33
35
 
34
- request = Net::HTTP::Patch.new(uri.request_uri)
36
+ request = ::Net::HTTP::Patch.new(uri.request_uri)
35
37
  request.body = ::JSON.dump(:status => status.to_s, :comment => opts[:comment])
36
38
 
37
- send_request(opts, :uri => uri, :request => request)
39
+ send_request(opts, uri, request)
38
40
  end
39
41
 
40
42
  class << self
41
43
  private
42
44
 
43
- def send_request(opts = {}, uri:, request:)
44
- Net::HTTP.start(uri.host, uri.port, opts[:proxy], :use_ssl => true) do |http|
45
+ def send_request(opts, uri, request)
46
+ ::Net::HTTP.start(uri.host, uri.port, opts[:proxy], :use_ssl => true) do |http|
45
47
  build_result(
46
- :uri => uri,
47
- :request => request,
48
- :response => opts[:dry_run] ? nil : http.request(request)
48
+ uri,
49
+ request,
50
+ opts[:dry_run] ? nil : http.request(request),
51
+ opts[:dry_run]
49
52
  )
50
53
  end
51
54
  end
52
55
 
53
- def build_result(uri:, request:, response: nil)
54
- result = {
55
- :request_info => uri.inspect + ': ' + request.body,
56
- :request => request,
57
- :response => response
58
- }
56
+ def build_result(uri, request, response = nil, dry_run = false)
57
+ result = {}
58
+ result.merge!(request_result(uri, request))
59
+ result.merge!(response_result(response)) unless response.nil?
60
+ result[:success] = success?(result, dry_run)
61
+ result
62
+ end
59
63
 
60
- unless result[:response].nil?
61
- result.merge!(JSON.parse(result[:response].body, :symbolize_names => true))
62
- result[:response_info] = build_response_info(result[:response])
63
- end
64
+ def success?(result, dry_run = false)
65
+ return true if dry_run
64
66
 
65
- result
67
+ result[:response] &&
68
+ result[:response].is_a?(::Net::HTTPSuccess) &&
69
+ result[:response].code == '200' &&
70
+ (result.key?('err') ? result['err'].to_i.zero? : true)
71
+ end
72
+
73
+ def request_result(uri, request)
74
+ {
75
+ :request_info => uri.inspect + ': ' + request.body,
76
+ :request => request
77
+ }
66
78
  end
67
79
 
68
- def build_response_info(response)
69
- response.code + '; ' + response.message + '; ' + response.body.delete!("\n")
80
+ def response_result(response)
81
+ {
82
+ :response => response,
83
+ :response_info => response.code + '; ' +
84
+ response.message + '; ' +
85
+ response.body.delete("\n")
86
+ }.merge(::JSON.parse(response.body, :symbolize_names => true))
70
87
  end
71
88
  end
72
89
  end
@@ -1,9 +1,9 @@
1
1
  module Rollbar
2
2
  module Encoding
3
3
  class Encoder
4
- ALL_ENCODINGS = [::Encoding::UTF_8, ::Encoding::ISO_8859_1, ::Encoding::ASCII_8BIT, ::Encoding::US_ASCII]
5
- ASCII_ENCODINGS = [::Encoding::US_ASCII, ::Encoding::ASCII_8BIT, ::Encoding::ISO_8859_1]
6
- ENCODING_OPTIONS = { :invalid => :replace, :undef => :replace, :replace => '' }
4
+ ALL_ENCODINGS = [::Encoding::UTF_8, ::Encoding::ISO_8859_1, ::Encoding::ASCII_8BIT, ::Encoding::US_ASCII].freeze
5
+ ASCII_ENCODINGS = [::Encoding::US_ASCII, ::Encoding::ASCII_8BIT, ::Encoding::ISO_8859_1].freeze
6
+ ENCODING_OPTIONS = { :invalid => :replace, :undef => :replace, :replace => '' }.freeze
7
7
  UTF8 = 'UTF-8'.freeze
8
8
  BINARY = 'binary'.freeze
9
9
 
@@ -18,11 +18,11 @@ module Rollbar
18
18
  encoding = value.encoding
19
19
 
20
20
  # This will be most of cases so avoid force anything for them
21
- if encoding == ::Encoding::UTF_8 && value.valid_encoding?
22
- encoded_value = value
23
- else
24
- encoded_value = force_encoding(value).encode(*encoding_args(value))
25
- end
21
+ encoded_value = if encoding == ::Encoding::UTF_8 && value.valid_encoding?
22
+ value
23
+ else
24
+ force_encoding(value).encode(*encoding_args(value))
25
+ end
26
26
 
27
27
  object.is_a?(Symbol) ? encoded_value.to_sym : encoded_value
28
28
  end
@@ -45,7 +45,7 @@ module Rollbar
45
45
  # Seems #codepoints is faster than #valid_encoding?
46
46
  value.force_encoding(encoding).encode(::Encoding::UTF_8).codepoints
47
47
  true
48
- rescue
48
+ rescue StandardError
49
49
  false
50
50
  end
51
51
  end
@@ -180,14 +180,14 @@ module Rollbar
180
180
  end
181
181
 
182
182
  def custom_data
183
- if configuration.custom_data_method.arity == 3
184
- data = configuration.custom_data_method.call(message, exception, context)
185
- else
186
- data = configuration.custom_data_method.call
187
- end
183
+ data = if configuration.custom_data_method.arity == 3
184
+ configuration.custom_data_method.call(message, exception, context)
185
+ else
186
+ configuration.custom_data_method.call
187
+ end
188
188
 
189
189
  Rollbar::Util.deep_copy(data)
190
- rescue => e
190
+ rescue StandardError => e
191
191
  return {} if configuration.safely?
192
192
 
193
193
  report_custom_data_error(e)
@@ -232,7 +232,7 @@ module Rollbar
232
232
  handlers.each do |handler|
233
233
  begin
234
234
  handler.call(transform_options)
235
- rescue => e
235
+ rescue StandardError => e
236
236
  logger.error("[Rollbar] Error calling the `transform` hook: #{e}")
237
237
 
238
238
  break
@@ -32,7 +32,7 @@ module Rollbar
32
32
  end
33
33
  end
34
34
 
35
- alias_method :build, :to_h
35
+ alias build to_h
36
36
 
37
37
  def get_file_lines(filename)
38
38
  files[filename] ||= read_file(filename)
@@ -44,7 +44,7 @@ module Rollbar
44
44
  return unless File.exist?(filename)
45
45
 
46
46
  File.read(filename).split("\n")
47
- rescue
47
+ rescue StandardError
48
48
  nil
49
49
  end
50
50
 
@@ -74,10 +74,10 @@ module Rollbar
74
74
  end
75
75
 
76
76
  def map_frames(current_exception)
77
- exception_backtrace(current_exception).reverse.map do |frame|
77
+ exception_backtrace(current_exception).map do |frame|
78
78
  Rollbar::Item::Frame.new(self, frame,
79
79
  :configuration => configuration).to_h
80
- end
80
+ end.reverse
81
81
  end
82
82
 
83
83
  # Returns the backtrace to be sent to our API. There are 3 options:
@@ -1,5 +1,6 @@
1
1
  # We want to use Gem.path
2
2
  require 'rubygems'
3
+ require 'rollbar/item/locals'
3
4
 
4
5
  module Rollbar
5
6
  class Item
@@ -47,7 +48,8 @@ module Rollbar
47
48
 
48
49
  {
49
50
  :code => code_data(file_lines, lineno),
50
- :context => context_data(file_lines, lineno)
51
+ :context => context_data(file_lines, lineno),
52
+ :locals => locals_data(filename, lineno)
51
53
  }
52
54
  end
53
55
 
@@ -94,6 +96,10 @@ module Rollbar
94
96
  }
95
97
  end
96
98
 
99
+ def locals_data(filename, lineno)
100
+ ::Rollbar::Item::Locals.locals_for_location(filename, lineno)
101
+ end
102
+
97
103
  def post_data(file_lines, lineno)
98
104
  from_line = lineno
99
105
  number_of_lines = [from_line + MAX_CONTEXT_LENGTH, file_lines.size].min - from_line
@@ -0,0 +1,56 @@
1
+ require 'rollbar/notifier'
2
+ require 'rollbar/scrubbers/params'
3
+
4
+ module Rollbar
5
+ class Item
6
+ class Locals # :nodoc:
7
+ class << self
8
+ def exception_frames
9
+ Rollbar.notifier.exception_bindings
10
+ end
11
+
12
+ def locals_for_location(filename, lineno)
13
+ if (frame = frame_for_location(filename, lineno))
14
+ scrub(locals_for(frame[:binding]))
15
+ else
16
+ {}
17
+ end
18
+ end
19
+
20
+ def frame_for_location(filename, lineno)
21
+ while (frame = exception_frames.pop)
22
+ return nil unless frame
23
+ return frame if matching_frame?(frame, filename, lineno)
24
+ end
25
+ nil
26
+ end
27
+
28
+ private
29
+
30
+ def matching_frame?(frame, filename, lineno)
31
+ frame[:path] == filename && frame[:lineno].to_i <= lineno.to_i
32
+ end
33
+
34
+ def locals_for(frame)
35
+ {}.tap do |hash|
36
+ frame.local_variables.map do |var|
37
+ hash[var] = prepare_value(frame.local_variable_get(var))
38
+ end
39
+ end
40
+ end
41
+
42
+ def prepare_value(value)
43
+ value.to_s
44
+ end
45
+
46
+ def scrub(hash)
47
+ Rollbar::Scrubbers::Params.call(
48
+ :params => hash,
49
+ :config => Rollbar.configuration.scrub_fields,
50
+ :whitelist => Rollbar.configuration.scrub_whitelist
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -9,13 +9,16 @@ rescue LoadError
9
9
  end
10
10
 
11
11
  module Rollbar
12
- module JSON
12
+ module JSON # :nodoc:
13
13
  extend self
14
14
 
15
15
  attr_writer :options_module
16
16
 
17
17
  def dump(object)
18
- with_adapter { MultiJson.dump(object, adapter_options) }
18
+ # `basic_socket` plugin addresses the following issue: https://github.com/rollbar/rollbar-gem/issues/845
19
+ Rollbar.plugins.get('basic_socket').load_scoped!(true) do
20
+ with_adapter { MultiJson.dump(object, adapter_options) }
21
+ end
19
22
  end
20
23
 
21
24
  def load(string)
@@ -1,7 +1,7 @@
1
1
  module Rollbar
2
2
  module JSON
3
3
  module Default
4
- extend self
4
+ module_function
5
5
 
6
6
  def options
7
7
  {}