rollbar 2.20.0 → 2.22.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -0
  3. data/.travis.yml +42 -16
  4. data/Gemfile +19 -13
  5. data/data/rollbar.snippet.js +1 -1
  6. data/gemfiles/rails30.gemfile +1 -10
  7. data/gemfiles/rails31.gemfile +1 -9
  8. data/gemfiles/rails32.gemfile +1 -9
  9. data/gemfiles/rails40.gemfile +1 -9
  10. data/gemfiles/rails41.gemfile +1 -9
  11. data/gemfiles/rails42.gemfile +1 -11
  12. data/gemfiles/rails50.gemfile +1 -11
  13. data/gemfiles/rails51.gemfile +1 -11
  14. data/gemfiles/rails52.gemfile +1 -11
  15. data/gemfiles/rails60.gemfile +67 -0
  16. data/lib/rollbar/configuration.rb +35 -1
  17. data/lib/rollbar/item.rb +25 -7
  18. data/lib/rollbar/json.rb +2 -51
  19. data/lib/rollbar/language_support.rb +3 -19
  20. data/lib/rollbar/notifier.rb +4 -6
  21. data/lib/rollbar/plugins/basic_socket.rb +1 -1
  22. data/lib/rollbar/rake_tasks.rb +3 -147
  23. data/lib/rollbar/request_data_extractor.rb +1 -2
  24. data/lib/rollbar/rollbar_test.rb +147 -0
  25. data/lib/rollbar/scrubbers/url.rb +0 -1
  26. data/lib/rollbar/truncation.rb +7 -1
  27. data/lib/rollbar/truncation/min_body_strategy.rb +2 -3
  28. data/lib/rollbar/truncation/remove_any_key_strategy.rb +123 -0
  29. data/lib/rollbar/truncation/remove_extra_strategy.rb +35 -0
  30. data/lib/rollbar/truncation/remove_request_strategy.rb +21 -0
  31. data/lib/rollbar/truncation/strings_strategy.rb +3 -4
  32. data/lib/rollbar/util.rb +2 -2
  33. data/lib/rollbar/util/hash.rb +15 -0
  34. data/lib/rollbar/version.rb +1 -1
  35. data/rollbar.gemspec +0 -2
  36. metadata +8 -20
  37. data/gemfiles/ruby_1_8_and_1_9_2.gemfile +0 -51
  38. data/lib/rollbar/json/default.rb +0 -11
  39. data/lib/rollbar/json/oj.rb +0 -16
@@ -210,8 +210,7 @@ module Rollbar
210
210
  def json_request?(rack_req)
211
211
  json_regex = /\bjson\b/
212
212
 
213
- !!(rack_req.env['CONTENT_TYPE'] =~ json_regex ||
214
- rack_req.env['HTTP_ACCEPT'] =~ json_regex)
213
+ !!(rack_req.env['CONTENT_TYPE'] =~ json_regex)
215
214
  end
216
215
 
217
216
  def rollbar_route_params(env)
@@ -0,0 +1,147 @@
1
+ require 'rollbar'
2
+ begin
3
+ require 'rack/mock'
4
+ rescue LoadError
5
+ puts 'Cannot load rack/mock'
6
+ end
7
+ require 'logger'
8
+
9
+ # Module to inject into the Rails controllers or rack apps
10
+ 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
+ def self.run
18
+ return unless confirmed_token?
19
+
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
42
+
43
+ Rails.logger.level = Logger::DEBUG
44
+ Rollbar.preconfigure do |config|
45
+ config.logger = Rails.logger
46
+ end
47
+ end
48
+
49
+ def self.confirmed_token?
50
+ return true if Rollbar.configuration.access_token
51
+
52
+ puts token_error_message
53
+
54
+ false
55
+ end
56
+
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
+ def self.token_error_message
121
+ 'Rollbar needs an access token configured. Check the README for instructions.'
122
+ end
123
+
124
+ 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.'
126
+ end
127
+
128
+ def self.success_message
129
+ 'Testing rollbar with "rake rollbar:test". If you can see this, it works.'
130
+ end
131
+ 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
@@ -14,7 +14,6 @@ module Rollbar
14
14
 
15
15
  def call(options = {})
16
16
  url = options[:url]
17
- return url unless Rollbar::LanguageSupport.can_scrub_url?
18
17
 
19
18
  filter(url,
20
19
  build_regex(options[:scrub_fields]),
@@ -4,6 +4,9 @@ require 'rollbar/truncation/raw_strategy'
4
4
  require 'rollbar/truncation/frames_strategy'
5
5
  require 'rollbar/truncation/strings_strategy'
6
6
  require 'rollbar/truncation/min_body_strategy'
7
+ require 'rollbar/truncation/remove_request_strategy'
8
+ require 'rollbar/truncation/remove_extra_strategy'
9
+ require 'rollbar/truncation/remove_any_key_strategy'
7
10
 
8
11
  module Rollbar
9
12
  module Truncation
@@ -13,7 +16,10 @@ module Rollbar
13
16
  STRATEGIES = [RawStrategy,
14
17
  FramesStrategy,
15
18
  StringsStrategy,
16
- MinBodyStrategy].freeze
19
+ MinBodyStrategy,
20
+ RemoveRequestStrategy,
21
+ RemoveExtraStrategy,
22
+ RemoveAnyKeyStrategy].freeze
17
23
 
18
24
  def self.truncate(payload, attempts = [])
19
25
  result = nil
@@ -11,8 +11,7 @@ module Rollbar
11
11
  end
12
12
 
13
13
  def call(payload)
14
- new_payload = Rollbar::Util.deep_copy(payload)
15
- body = new_payload['data']['body']
14
+ body = payload['data']['body']
16
15
 
17
16
  if body['trace_chain']
18
17
  body['trace_chain'] = body['trace_chain'].map do |trace_data|
@@ -22,7 +21,7 @@ module Rollbar
22
21
  body['trace'] = truncate_trace_data(body['trace'])
23
22
  end
24
23
 
25
- dump(new_payload)
24
+ dump(payload)
26
25
  end
27
26
 
28
27
  def truncate_trace_data(trace_data)
@@ -0,0 +1,123 @@
1
+ require 'rollbar/util'
2
+
3
+ module Rollbar
4
+ module Truncation
5
+ class RemoveAnyKeyStrategy
6
+ include ::Rollbar::Truncation::Mixin
7
+
8
+ attr_accessor :payload, :data, :sizes, :extracted_title
9
+
10
+ def self.call(payload)
11
+ new(payload).call
12
+ end
13
+
14
+ def initialize(payload)
15
+ @payload = payload
16
+ @data = payload['data']
17
+ @extracted_title = extract_title(data['body']) if data['body']
18
+ end
19
+
20
+ def call
21
+ remove_unknown_root_keys
22
+
23
+ json_payload = remove_oversized_data_keys
24
+
25
+ return json_payload if json_payload
26
+
27
+ dump(payload)
28
+ end
29
+
30
+ def remove_unknown_root_keys
31
+ payload.keys.reject { |key| root_keys.include?(key) }.each do |key|
32
+ truncation_key['root'] ||= {}
33
+ size = dump(payload.delete(key)).bytesize
34
+ truncation_key['root'][key] = "unknown root key removed, size: #{size} bytes"
35
+ end
36
+ end
37
+
38
+ def remove_oversized_data_keys
39
+ data_keys.keys.sort { |a, b| data_keys[b] <=> data_keys[a] }.each do |key|
40
+ json_payload = remove_key_and_return_payload(key)
41
+
42
+ return json_payload unless truncate?(json_payload)
43
+ end
44
+
45
+ false
46
+ end
47
+
48
+ def remove_key_and_return_payload(key)
49
+ size = data_keys[key]
50
+
51
+ data.delete(key)
52
+
53
+ replace_message_body if key == 'body'
54
+
55
+ truncation_key[key] = "key removed, size: #{size} bytes"
56
+
57
+ dump(payload)
58
+ end
59
+
60
+ def replace_message_body
61
+ data['body'] = message_key
62
+ data['title'] ||= extracted_title if extracted_title
63
+ end
64
+
65
+ def truncation_key
66
+ @truncation_key ||=
67
+ # initialize the diagnostic key for truncation
68
+ (data['notifier']['diagnostic'] ||= {}) &&
69
+ (data['notifier']['diagnostic']['truncation'] ||= {})
70
+ end
71
+
72
+ def root_keys
73
+ # Valid keys in root of payload
74
+ %w[access_token data]
75
+ end
76
+
77
+ def skip_keys
78
+ # Don't try to truncate these data keys
79
+ %w[notifier uuid title platform language framework level]
80
+ end
81
+
82
+ def message_key
83
+ # use this message if data.body gets removed
84
+ {
85
+ 'message' => {
86
+ 'body' => 'Payload keys removed due to oversized payload. See diagnostic key'
87
+ }
88
+ }
89
+ end
90
+
91
+ def extract_title(body)
92
+ return body['message']['body'] if body['message'] && body['message']['body']
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]
95
+ end
96
+
97
+ def extract_title_from_trace(trace)
98
+ exception = trace['exception']
99
+
100
+ "#{exception['class']}: #{exception['message']}"
101
+ end
102
+
103
+ def data_keys
104
+ @data_keys ||= {}.tap do |hash|
105
+ data.keys.reject { |key| skip_keys.include?(key) }.each do |key|
106
+ set_key_size(key, hash)
107
+ end
108
+ end
109
+ end
110
+
111
+ def set_key_size(key, hash)
112
+ size = dump(data[key]).bytesize
113
+ hash[key] = size
114
+ rescue ::JSON::GeneratorError
115
+ hash[key] = 0 # don't try to truncate non JSON object
116
+
117
+ # Log it
118
+ truncation_key['non_json_keys'] ||= {}
119
+ truncation_key['non_json_keys'][key] = data[key].class
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,35 @@
1
+ require 'rollbar/util'
2
+
3
+ module Rollbar
4
+ module Truncation
5
+ class RemoveExtraStrategy
6
+ include ::Rollbar::Truncation::Mixin
7
+
8
+ def self.call(payload)
9
+ new.call(payload)
10
+ end
11
+
12
+ def call(payload)
13
+ body = payload['data']['body']
14
+
15
+ delete_message_extra(body)
16
+ delete_trace_chain_extra(body)
17
+ delete_trace_extra(body)
18
+
19
+ dump(payload)
20
+ end
21
+
22
+ def delete_message_extra(body)
23
+ body['message'].delete('extra') if body['message'] && body['message']['extra']
24
+ end
25
+
26
+ def delete_trace_chain_extra(body)
27
+ body['trace_chain'][0].delete('extra') if body['trace_chain'] && body['trace_chain'][0]['extra']
28
+ end
29
+
30
+ def delete_trace_extra(body)
31
+ body['trace'].delete('extra') if body['trace'] && body['trace']['extra']
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ require 'rollbar/util'
2
+
3
+ module Rollbar
4
+ module Truncation
5
+ class RemoveRequestStrategy
6
+ include ::Rollbar::Truncation::Mixin
7
+
8
+ def self.call(payload)
9
+ new.call(payload)
10
+ end
11
+
12
+ def call(payload)
13
+ data = payload['data']
14
+
15
+ data.delete('request') if data['request']
16
+
17
+ dump(payload)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -6,7 +6,7 @@ module Rollbar
6
6
  class StringsStrategy
7
7
  include ::Rollbar::Truncation::Mixin
8
8
 
9
- STRING_THRESHOLDS = [1024, 512, 256, 128, 64].freeze
9
+ STRING_THRESHOLDS = [1024, 512, 256].freeze
10
10
 
11
11
  def self.call(payload)
12
12
  new.call(payload)
@@ -14,13 +14,12 @@ module Rollbar
14
14
 
15
15
  def call(payload)
16
16
  result = nil
17
- new_payload = Rollbar::Util.deep_copy(payload)
18
17
 
19
18
  STRING_THRESHOLDS.each do |threshold|
20
19
  truncate_proc = truncate_strings_proc(threshold)
21
20
 
22
- ::Rollbar::Util.iterate_and_update(new_payload, truncate_proc)
23
- result = dump(new_payload)
21
+ ::Rollbar::Util.iterate_and_update(payload, truncate_proc)
22
+ result = dump(payload)
24
23
 
25
24
  break unless truncate?(result)
26
25
  end
data/lib/rollbar/util.rb CHANGED
@@ -63,9 +63,9 @@ module Rollbar
63
63
 
64
64
  def self.clone_obj(obj)
65
65
  if obj.is_a?(::Hash)
66
- obj.clone
66
+ obj.dup
67
67
  elsif obj.is_a?(Array)
68
- obj.clone.clear
68
+ obj.dup.clear
69
69
  else
70
70
  obj
71
71
  end
@@ -5,6 +5,7 @@ module Rollbar
5
5
  return if seen[hash.object_id]
6
6
 
7
7
  seen[hash.object_id] = true
8
+ replace_seen_children(hash, seen)
8
9
 
9
10
  hash.reduce({}) do |h, (key, value)|
10
11
  h[key.to_s] = map_value(value, :deep_stringify_keys, seen)
@@ -22,12 +23,26 @@ module Rollbar
22
23
  thing
23
24
  else
24
25
  seen[thing.object_id] = true
26
+ replace_seen_children(thing, seen)
25
27
  thing.map { |v| map_value(v, meth, seen) }
26
28
  end
27
29
  else
28
30
  thing
29
31
  end
30
32
  end
33
+
34
+ def self.replace_seen_children(thing, seen)
35
+ case thing
36
+ when ::Hash
37
+ thing.keys.each do |key|
38
+ thing[key] = "removed circular reference: #{thing[key]}" if seen[thing[key].object_id]
39
+ end
40
+ when Array
41
+ thing.each_with_index do |_, i|
42
+ thing[i] = "removed circular reference: #{thing[i]}" if seen[thing[i].object_id]
43
+ end
44
+ end
45
+ end
31
46
  end
32
47
  end
33
48
  end