rollbar 2.22.1 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,48 +1,16 @@
1
1
  require 'rollbar'
2
- begin
3
- require 'rack/mock'
4
- rescue LoadError
5
- puts 'Cannot load rack/mock'
6
- end
7
- require 'logger'
8
2
 
9
- # Module to inject into the Rails controllers or rack apps
10
3
  module RollbarTest # :nodoc:
11
- def test_rollbar
12
- puts 'Raising RollbarTestingException to simulate app failure.'
13
-
14
- raise RollbarTestingException.new, ::RollbarTest.success_message
15
- end
16
-
17
4
  def self.run
18
5
  return unless confirmed_token?
19
6
 
20
- configure_rails if defined?(Rails)
21
-
22
- puts 'Testing manual report...'
23
- Rollbar.error('Test error from rollbar:test')
24
-
25
- return unless defined?(Rack::MockRequest)
26
-
27
- protocol, app = setup_app
28
-
29
- puts 'Processing...'
30
- env = Rack::MockRequest.env_for("#{protocol}://www.example.com/verify", 'REMOTE_ADDR' => '127.0.0.1')
31
- status, = app.call(env)
32
-
33
- puts error_message unless status.to_i == 500
34
- end
35
-
36
- def self.configure_rails
37
- Rails.logger = if defined?(ActiveSupport::TaggedLogging)
38
- ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
39
- else
40
- Logger.new(STDOUT)
41
- end
7
+ puts 'Test sending to Rollbar...'
8
+ result = Rollbar.info('Test message from rollbar:test')
42
9
 
43
- Rails.logger.level = Logger::DEBUG
44
- Rollbar.preconfigure do |config|
45
- config.logger = Rails.logger
10
+ if result == 'error'
11
+ puts error_message
12
+ else
13
+ puts success_message
46
14
  end
47
15
  end
48
16
 
@@ -54,94 +22,17 @@ module RollbarTest # :nodoc:
54
22
  false
55
23
  end
56
24
 
57
- def self.authlogic_config
58
- # from http://stackoverflow.com/questions/5270835/authlogic-activation-problems
59
- return unless defined?(Authlogic)
60
-
61
- Authlogic::Session::Base.controller = Authlogic::ControllerAdapters::RailsAdapter.new(self)
62
- end
63
-
64
- def self.setup_app
65
- puts 'Setting up the test app.'
66
-
67
- if defined?(Rails)
68
- app = rails_app
69
-
70
- draw_rails_route(app)
71
-
72
- authlogic_config
73
-
74
- [rails_protocol(app), app]
75
- else
76
- ['http', rack_app]
77
- end
78
- end
79
-
80
- def self.rails_app
81
- # The setup below is needed for Rails 5.x, but not for Rails 4.x and below.
82
- # (And fails on Rails 4.x in various ways depending on the exact version.)
83
- return Rails.application if Rails.version < '5.0.0'
84
-
85
- # Spring now runs by default in development on all new Rails installs. This causes
86
- # the new `/verify` route to not get picked up if `config.cache_classes == false`
87
- # which is also a default in development env.
88
- #
89
- # `config.cache_classes` needs to be set, but the only possible time is at app load,
90
- # so here we clone the default app with an updated config.
91
- #
92
- config = Rails.application.config
93
- config.cache_classes = true
94
-
95
- # Make a copy of the app, so the config can be updated.
96
- Rails.application.class.name.constantize.new(:config => config)
97
- end
98
-
99
- def self.draw_rails_route(app)
100
- app.routes_reloader.execute_if_updated
101
- app.routes.draw do
102
- get 'verify' => 'rollbar_test#verify', :as => 'verify'
103
- end
104
- end
105
-
106
- def self.rails_protocol(app)
107
- defined?(app.config.force_ssl && app.config.force_ssl) ? 'https' : 'http'
108
- end
109
-
110
- def self.rack_app
111
- Class.new do
112
- include RollbarTest
113
-
114
- def self.call(_env)
115
- new.test_rollbar
116
- end
117
- end
118
- end
119
-
120
25
  def self.token_error_message
121
26
  'Rollbar needs an access token configured. Check the README for instructions.'
122
27
  end
123
28
 
124
29
  def self.error_message
125
- 'Test failed! You may have a configuration issue, or you could be using a gem that\'s blocking the test. Contact support@rollbar.com if you need help troubleshooting.'
30
+ 'Test failed! You may have a configuration issue, or you could be using a ' \
31
+ 'gem that\'s blocking the test. Contact support@rollbar.com if you need ' \
32
+ 'help troubleshooting.'
126
33
  end
127
34
 
128
35
  def self.success_message
129
36
  'Testing rollbar with "rake rollbar:test". If you can see this, it works.'
130
37
  end
131
38
  end
132
-
133
- class RollbarTestingException < RuntimeError; end
134
-
135
- if defined?(Rails)
136
- class RollbarTestController < ActionController::Base # :nodoc:
137
- include RollbarTest
138
-
139
- def verify
140
- test_rollbar
141
- end
142
-
143
- def logger
144
- nil
145
- end
146
- end
147
- end
@@ -10,7 +10,8 @@ module Rollbar
10
10
  # configuration array even if :scrub_all is true.
11
11
  class Params
12
12
  SKIPPED_CLASSES = [::Tempfile].freeze
13
- ATTACHMENT_CLASSES = %w[ActionDispatch::Http::UploadedFile Rack::Multipart::UploadedFile].freeze
13
+ ATTACHMENT_CLASSES = %w[ActionDispatch::Http::UploadedFile
14
+ Rack::Multipart::UploadedFile].freeze
14
15
  SCRUB_ALL = :scrub_all
15
16
 
16
17
  def self.call(*args)
@@ -21,7 +22,7 @@ module Rollbar
21
22
  params = options[:params]
22
23
  return {} unless params
23
24
 
24
- @scrubbed_object_ids = {}
25
+ @scrubbed_objects = {}.compare_by_identity
25
26
 
26
27
  config = options[:config]
27
28
  extra_fields = options[:extra_fields]
@@ -52,16 +53,20 @@ module Rollbar
52
53
  end
53
54
 
54
55
  def build_whitelist_regex(whitelist)
55
- fields = whitelist.find_all { |f| f.is_a?(String) || f.is_a?(Symbol) || f.is_a?(Regexp) }
56
+ fields = whitelist.find_all do |f|
57
+ f.is_a?(String) || f.is_a?(Symbol) || f.is_a?(Regexp)
58
+ end
56
59
  return unless fields.any?
57
60
 
58
- Regexp.new(fields.map { |val| val.is_a?(Regexp) ? val : /\A#{Regexp.escape(val.to_s)}\z/ }.join('|'))
61
+ Regexp.new(fields.map do |val|
62
+ val.is_a?(Regexp) ? val : /\A#{Regexp.escape(val.to_s)}\z/
63
+ end.join('|'))
59
64
  end
60
65
 
61
66
  def scrub(params, options)
62
- return params if @scrubbed_object_ids[params.object_id]
67
+ return params if @scrubbed_objects[params]
63
68
 
64
- @scrubbed_object_ids[params.object_id] = true
69
+ @scrubbed_objects[params] = true
65
70
 
66
71
  fields_regex = options[:fields_regex]
67
72
  scrub_all = options[:scrub_all]
@@ -71,7 +76,8 @@ module Rollbar
71
76
 
72
77
  params.to_hash.inject({}) do |result, (key, value)|
73
78
  encoded_key = Rollbar::Encoding.encode(key).to_s
74
- result[key] = if (fields_regex === encoded_key) && !(whitelist_regex === encoded_key)
79
+ result[key] = if (fields_regex === encoded_key) &&
80
+ !(whitelist_regex === encoded_key)
75
81
  scrub_value(value)
76
82
  elsif value.is_a?(Hash)
77
83
  scrub(value, options)
@@ -13,7 +13,7 @@ module Rollbar
13
13
  end
14
14
 
15
15
  def call(options = {})
16
- url = options[:url]
16
+ url = ascii_encode(options[:url])
17
17
 
18
18
  filter(url,
19
19
  build_regex(options[:scrub_fields]),
@@ -23,12 +23,29 @@ module Rollbar
23
23
  options[:scrub_fields].include?(SCRUB_ALL),
24
24
  build_whitelist_regex(options[:whitelist] || []))
25
25
  rescue StandardError => e
26
- Rollbar.logger.error("[Rollbar] There was an error scrubbing the url: #{e}, options: #{options.inspect}")
26
+ message = '[Rollbar] There was an error scrubbing the url: ' \
27
+ "#{e}, options: #{options.inspect}"
28
+ Rollbar.logger.error(message)
27
29
  url
28
30
  end
29
31
 
30
32
  private
31
33
 
34
+ def ascii_encode(url)
35
+ # In some cases non-ascii characters won't be properly encoded, so we do it here.
36
+ #
37
+ # The standard encoders (the CGI and URI methods) are not reliable when
38
+ # the query string is already embedded in the full URL, but the inconsistencies
39
+ # are limited to issues with characters in the ascii range. (For example,
40
+ # the '#' if it appears in an unexpected place.) For escaping non-ascii,
41
+ # they are all OK, so we'll take care to skip the ascii chars.
42
+
43
+ return url if url.ascii_only?
44
+
45
+ # Iterate each char and only escape non-ascii characters.
46
+ url.each_char.map { |c| c.ascii_only? ? c : CGI.escape(c) }.join
47
+ end
48
+
32
49
  def build_whitelist_regex(whitelist)
33
50
  fields = whitelist.find_all { |f| f.is_a?(String) || f.is_a?(Symbol) }
34
51
  return unless fields.any?
@@ -36,12 +53,15 @@ module Rollbar
36
53
  Regexp.new(fields.map { |val| /\A#{Regexp.escape(val.to_s)}\z/ }.join('|'))
37
54
  end
38
55
 
39
- def filter(url, regex, scrub_user, scrub_password, randomize_scrub_length, scrub_all, whitelist)
56
+ def filter(url, regex, scrub_user, scrub_password, randomize_scrub_length,
57
+ scrub_all, whitelist)
40
58
  uri = URI.parse(url)
41
59
 
42
60
  uri.user = filter_user(uri.user, scrub_user, randomize_scrub_length)
43
- uri.password = filter_password(uri.password, scrub_password, randomize_scrub_length)
44
- uri.query = filter_query(uri.query, regex, randomize_scrub_length, scrub_all, whitelist)
61
+ uri.password = filter_password(uri.password, scrub_password,
62
+ randomize_scrub_length)
63
+ uri.query = filter_query(uri.query, regex, randomize_scrub_length, scrub_all,
64
+ whitelist)
45
65
 
46
66
  uri.to_s
47
67
  end
@@ -59,7 +79,12 @@ module Rollbar
59
79
  end
60
80
 
61
81
  def filter_password(password, scrub_password, randomize_scrub_length)
62
- scrub_password && password ? filtered_value(password, randomize_scrub_length) : password
82
+ if scrub_password && password
83
+ filtered_value(password,
84
+ randomize_scrub_length)
85
+ else
86
+ password
87
+ end
63
88
  end
64
89
 
65
90
  def filter_query(query, regex, randomize_scrub_length, scrub_all, whitelist)
@@ -67,10 +92,8 @@ module Rollbar
67
92
 
68
93
  params = decode_www_form(query)
69
94
 
70
- encoded_query = encode_www_form(filter_query_params(params, regex, randomize_scrub_length, scrub_all, whitelist))
71
-
72
- # We want this to rebuild array params like foo[]=1&foo[]=2
73
- URI.escape(CGI.unescape(encoded_query))
95
+ encode_www_form(filter_query_params(params, regex, randomize_scrub_length,
96
+ scrub_all, whitelist))
74
97
  end
75
98
 
76
99
  def decode_www_form(query)
@@ -78,12 +101,28 @@ module Rollbar
78
101
  end
79
102
 
80
103
  def encode_www_form(params)
81
- URI.encode_www_form(params)
104
+ restore_square_brackets(URI.encode_www_form(params))
105
+ end
106
+
107
+ def restore_square_brackets(query)
108
+ # We want this to rebuild array params like foo[]=1&foo[]=2
109
+ #
110
+ # URI.encode_www_form follows the spec at
111
+ # https://url.spec.whatwg.org/#concept-urlencoded-serializer
112
+ # and percent encodes square brackets. Here we change them back.
113
+ query.gsub('%5B', '[').gsub('%5D', ']')
82
114
  end
83
115
 
84
- def filter_query_params(params, regex, randomize_scrub_length, scrub_all, whitelist)
116
+ def filter_query_params(params, regex, randomize_scrub_length, scrub_all,
117
+ whitelist)
85
118
  params.map do |key, value|
86
- [key, filter_key?(key, regex, scrub_all, whitelist) ? filtered_value(value, randomize_scrub_length) : value]
119
+ [key,
120
+ if filter_key?(key, regex, scrub_all,
121
+ whitelist)
122
+ filtered_value(value, randomize_scrub_length)
123
+ else
124
+ value
125
+ end]
87
126
  end
88
127
  end
89
128
 
@@ -96,10 +135,10 @@ module Rollbar
96
135
  random_filtered_value
97
136
  else
98
137
  '*' * (begin
99
- value.length
100
- rescue StandardError
101
- 8
102
- end)
138
+ value.length
139
+ rescue StandardError
140
+ 8
141
+ end)
103
142
  end
104
143
  end
105
144
 
@@ -2,15 +2,11 @@ module Rollbar
2
2
  module Scrubbers
3
3
  module_function
4
4
 
5
- def scrub_value(value)
5
+ def scrub_value(_value)
6
6
  if Rollbar.configuration.randomize_scrub_length
7
7
  random_filtered_value
8
8
  else
9
- '*' * (begin
10
- value.length
11
- rescue StandardError
12
- 8
13
- end)
9
+ '*' * 6
14
10
  end
15
11
  end
16
12
 
@@ -11,7 +11,7 @@ module Rollbar
11
11
  end
12
12
 
13
13
  def call(payload)
14
- new_payload = Rollbar::Util.deep_copy(payload)
14
+ new_payload = payload
15
15
  body = new_payload['data']['body']
16
16
 
17
17
  if body['trace_chain']
@@ -9,7 +9,7 @@ module Rollbar
9
9
  result.bytesize > MAX_PAYLOAD_SIZE
10
10
  end
11
11
 
12
- def select_frames(frames, range = 150)
12
+ def select_frames(frames, range = 50)
13
13
  return frames unless frames.count > range * 2
14
14
 
15
15
  frames[0, range] + frames[-range, range]
@@ -91,7 +91,10 @@ module Rollbar
91
91
  def extract_title(body)
92
92
  return body['message']['body'] if body['message'] && body['message']['body']
93
93
  return extract_title_from_trace(body['trace']) if body['trace']
94
- return extract_title_from_trace(body['trace_chain'][0]) if body['trace_chain'] && body['trace_chain'][0]
94
+
95
+ return unless body['trace_chain'] && body['trace_chain'][0]
96
+
97
+ extract_title_from_trace(body['trace_chain'][0])
95
98
  end
96
99
 
97
100
  def extract_title_from_trace(trace)
@@ -24,7 +24,9 @@ module Rollbar
24
24
  end
25
25
 
26
26
  def delete_trace_chain_extra(body)
27
- body['trace_chain'][0].delete('extra') if body['trace_chain'] && body['trace_chain'][0]['extra']
27
+ return unless body['trace_chain'] && body['trace_chain'][0]['extra']
28
+
29
+ body['trace_chain'][0].delete('extra')
28
30
  end
29
31
 
30
32
  def delete_trace_extra(body)
@@ -6,7 +6,7 @@ module Rollbar
6
6
  class StringsStrategy
7
7
  include ::Rollbar::Truncation::Mixin
8
8
 
9
- STRING_THRESHOLDS = [1024, 512, 256].freeze
9
+ STRING_THRESHOLDS = [1024, 512, 256, 128].freeze
10
10
 
11
11
  def self.call(payload)
12
12
  new.call(payload)
@@ -29,7 +29,9 @@ module Rollbar
29
29
 
30
30
  def truncate_strings_proc(threshold)
31
31
  proc do |value|
32
- if value.is_a?(String) && value.bytesize > threshold
32
+ # Rollbar::Util.truncate will operate on characters, not bytes,
33
+ # so use value.length, not bytesize.
34
+ if value.is_a?(String) && value.length > threshold
33
35
  Rollbar::Util.truncate(value, threshold)
34
36
  else
35
37
  value
@@ -2,9 +2,10 @@ module Rollbar
2
2
  module Util
3
3
  module Hash # :nodoc:
4
4
  def self.deep_stringify_keys(hash, seen = {})
5
- return if seen[hash.object_id]
5
+ seen.compare_by_identity
6
+ return if seen[hash]
6
7
 
7
- seen[hash.object_id] = true
8
+ seen[hash] = true
8
9
  replace_seen_children(hash, seen)
9
10
 
10
11
  hash.reduce({}) do |h, (key, value)|
@@ -19,10 +20,10 @@ module Rollbar
19
20
  when ::Hash
20
21
  send(meth, thing, seen)
21
22
  when Array
22
- if seen[thing.object_id]
23
+ if seen[thing]
23
24
  thing
24
25
  else
25
- seen[thing.object_id] = true
26
+ seen[thing] = true
26
27
  replace_seen_children(thing, seen)
27
28
  thing.map { |v| map_value(v, meth, seen) }
28
29
  end
@@ -34,12 +35,18 @@ module Rollbar
34
35
  def self.replace_seen_children(thing, seen)
35
36
  case thing
36
37
  when ::Hash
37
- thing.keys.each do |key|
38
- thing[key] = "removed circular reference: #{thing[key]}" if seen[thing[key].object_id]
38
+ thing.keys.each do |key| # rubocop:disable Style/HashEachMethods
39
+ if seen[thing[key]]
40
+ thing[key] =
41
+ "removed circular reference: #{thing[key]}"
42
+ end
39
43
  end
40
44
  when Array
41
45
  thing.each_with_index do |_, i|
42
- thing[i] = "removed circular reference: #{thing[i]}" if seen[thing[i].object_id]
46
+ if seen[thing[i]]
47
+ thing[i] =
48
+ "removed circular reference: #{thing[i]}"
49
+ end
43
50
  end
44
51
  end
45
52
  end
@@ -24,7 +24,7 @@ module Rollbar
24
24
  def self.anonymize_ipv6(ip)
25
25
  ip_parts = ip.to_s.split ':'
26
26
 
27
- ip_string = ip_parts[0..2].join(':') + ':0000:0000:0000:0000:0000'
27
+ ip_string = "#{ip_parts[0..2].join(':')}:0000:0000:0000:0000:0000"
28
28
 
29
29
  IPAddr.new(ip_string).to_s
30
30
  end
data/lib/rollbar/util.rb CHANGED
@@ -2,10 +2,15 @@ require 'rollbar/util/hash'
2
2
 
3
3
  module Rollbar
4
4
  module Util # :nodoc:
5
+ def self.iterate_and_update_with_block(obj, &block)
6
+ iterate_and_update(obj, block)
7
+ end
8
+
5
9
  def self.iterate_and_update(obj, block, seen = {})
6
- return if obj.frozen? || seen[obj.object_id]
10
+ seen.compare_by_identity
11
+ return if obj.frozen? || seen[obj]
7
12
 
8
- seen[obj.object_id] = true
13
+ seen[obj] = true
9
14
 
10
15
  if obj.is_a?(Array)
11
16
  iterate_and_update_array(obj, block, seen)
@@ -25,7 +30,7 @@ module Rollbar
25
30
  end
26
31
 
27
32
  def self.iterate_and_update_hash(obj, block, seen)
28
- obj.keys.each do |k|
33
+ obj.keys.each do |k| # rubocop:disable Style/HashEachMethods
29
34
  v = obj[k]
30
35
  new_key = block.call(k)
31
36
 
@@ -43,18 +48,21 @@ module Rollbar
43
48
  end
44
49
 
45
50
  def self.deep_copy(obj, copied = {})
51
+ copied.compare_by_identity
52
+
46
53
  # if we've already made a copy, return it.
47
- return copied[obj.object_id] if copied[obj.object_id]
54
+ return copied[obj] if copied[obj]
48
55
 
49
56
  result = clone_obj(obj)
50
57
 
51
58
  # Memoize the cloned object before recursive calls to #deep_copy below.
52
59
  # This is the point of doing the work in two steps.
53
- copied[obj.object_id] = result
60
+ copied[obj] = result
54
61
 
55
- if obj.is_a?(::Hash)
62
+ case obj
63
+ when ::Hash
56
64
  obj.each { |k, v| result[k] = deep_copy(v, copied) }
57
- elsif obj.is_a?(Array)
65
+ when Array
58
66
  obj.each { |v| result << deep_copy(v, copied) }
59
67
  end
60
68
 
@@ -62,9 +70,10 @@ module Rollbar
62
70
  end
63
71
 
64
72
  def self.clone_obj(obj)
65
- if obj.is_a?(::Hash)
73
+ case obj
74
+ when ::Hash
66
75
  obj.dup
67
- elsif obj.is_a?(Array)
76
+ when Array
68
77
  obj.dup.clear
69
78
  else
70
79
  obj
@@ -74,12 +83,13 @@ module Rollbar
74
83
  def self.deep_merge(hash1, hash2, merged = {})
75
84
  hash1 ||= {}
76
85
  hash2 ||= {}
86
+ merged.compare_by_identity
77
87
 
78
88
  # If we've already merged these two objects, return hash1 now.
79
- return hash1 if merged[hash1.object_id] && merged[hash1.object_id].include?(hash2.object_id)
89
+ return hash1 if merged[hash1] && merged[hash1].include?(hash2.object_id)
80
90
 
81
- merged[hash1.object_id] ||= []
82
- merged[hash1.object_id] << hash2.object_id
91
+ merged[hash1] ||= []
92
+ merged[hash1] << hash2.object_id
83
93
 
84
94
  perform_deep_merge(hash1, hash2, merged)
85
95
 
@@ -117,7 +127,7 @@ module Rollbar
117
127
  end
118
128
 
119
129
  def self.count_method_in_stack(method_symbol, file_path = '')
120
- caller.grep(/#{file_path}.*#{method_symbol.to_s}/).count
130
+ caller.grep(/#{file_path}.*#{method_symbol}/).count
121
131
  end
122
132
 
123
133
  def self.method_in_stack(method_symbol, file_path = '')
@@ -1,3 +1,3 @@
1
1
  module Rollbar
2
- VERSION = '2.22.1'.freeze
2
+ VERSION = '3.4.0'.freeze
3
3
  end
data/lib/rollbar.rb CHANGED
@@ -8,6 +8,7 @@ require 'forwardable'
8
8
  begin
9
9
  require 'securerandom'
10
10
  rescue LoadError
11
+ # Skip loading
11
12
  end
12
13
 
13
14
  require 'rollbar/version'
@@ -31,8 +32,7 @@ module Rollbar
31
32
 
32
33
  def_delegators :notifier, *PUBLIC_NOTIFIER_METHODS
33
34
 
34
- attr_writer :plugins
35
- attr_writer :root_notifier
35
+ attr_writer :plugins, :root_notifier
36
36
 
37
37
  def notifier
38
38
  # Use the global instance @root_notifier so we don't fall
@@ -160,8 +160,10 @@ module Rollbar
160
160
 
161
161
  # Backwards compatibility methods
162
162
 
163
- def report_exception(exception, request_data = nil, person_data = nil, level = 'error')
164
- Kernel.warn('[DEPRECATION] Rollbar.report_exception has been deprecated, please use log() or one of the level functions')
163
+ def report_exception(exception, request_data = nil, person_data = nil,
164
+ level = 'error')
165
+ Kernel.warn('[DEPRECATION] Rollbar.report_exception has been deprecated, ' \
166
+ 'please use log() or one of the level functions')
165
167
 
166
168
  scope = {}
167
169
  scope[:request] = request_data if request_data
@@ -173,13 +175,16 @@ module Rollbar
173
175
  end
174
176
 
175
177
  def report_message(message, level = 'info', extra_data = nil)
176
- Kernel.warn('[DEPRECATION] Rollbar.report_message has been deprecated, please use log() or one of the level functions')
178
+ Kernel.warn('[DEPRECATION] Rollbar.report_message has been deprecated, ' \
179
+ 'please use log() or one of the level functions')
177
180
 
178
181
  Rollbar.notifier.log(level, message, extra_data)
179
182
  end
180
183
 
181
- def report_message_with_request(message, level = 'info', request_data = nil, person_data = nil, extra_data = nil)
182
- Kernel.warn('[DEPRECATION] Rollbar.report_message_with_request has been deprecated, please use log() or one of the level functions')
184
+ def report_message_with_request(message, level = 'info', request_data = nil,
185
+ person_data = nil, extra_data = nil)
186
+ Kernel.warn('[DEPRECATION] Rollbar.report_message_with_request has been ' \
187
+ 'deprecated, please use log() or one of the level functions')
183
188
 
184
189
  scope = {}
185
190
  scope[:request] = request_data if request_data
@@ -77,7 +77,8 @@ class BenchmarkTraceWithBindings # :nodoc:
77
77
  def trace_point # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
78
78
  return unless defined?(TracePoint)
79
79
 
80
- @trace_point ||= TracePoint.new(:call, :return, :b_call, :b_return, :c_call, :c_return, :raise) do |tp|
80
+ @trace_point ||= TracePoint.new(:call, :return, :b_call, :b_return, :c_call,
81
+ :c_return, :raise) do |tp|
81
82
  next if options['hook_only']
82
83
 
83
84
  case tp.event
data/rollbar.gemspec CHANGED
@@ -7,15 +7,18 @@ Gem::Specification.new do |gem|
7
7
 
8
8
  gem.authors = ['Rollbar, Inc.']
9
9
  gem.email = ['support@rollbar.com']
10
- gem.description = 'Easy and powerful exception tracking for Ruby'
10
+ gem.description = "Track and debug errors in your Ruby applications with ease using Rollbar. With this gem, you can easily monitor and report on exceptions and other errors in your code, helping you identify and fix issues more quickly. Rollbar's intuitive interface and advanced error tracking features make it the perfect tool for ensuring the stability and reliability of your Ruby applications."
11
11
  gem.executables = ['rollbar-rails-runner']
12
12
  gem.summary = 'Reports exceptions to Rollbar'
13
13
  gem.homepage = 'https://rollbar.com'
14
14
  gem.license = 'MIT'
15
- gem.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
15
+ gem.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+ gem.files += ['spec/support/rollbar_api.rb'] # useful helper for app spec/tests.
16
19
  gem.name = 'rollbar'
17
20
  gem.require_paths = ['lib']
18
- gem.required_ruby_version = '>= 1.9.3'
21
+ gem.required_ruby_version = '>= 2.0.0'
19
22
  gem.version = Rollbar::VERSION
20
23
 
21
24
  if gem.respond_to?(:metadata)