rollbar 2.20.0 → 2.22.1

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