rollbar 2.19.2 → 2.19.3

Sign up to get free protection for your applications and to get access to all the features.
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
  {}