rollbar 2.8.3 → 3.6.0
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.
- checksums.yaml +5 -5
- data/.codeclimate.yml +18 -0
- data/.github/pull_request_template.md +34 -0
- data/.github/workflows/ci.yml +67 -0
- data/.gitignore +3 -1
- data/.rubocop.yml +206 -7
- data/Appraisals +10 -10
- data/CHANGELOG.md +257 -3
- data/Gemfile +74 -13
- data/README.md +38 -833
- data/Rakefile +0 -0
- data/THANKS.md +1 -0
- data/data/rollbar.snippet.js +1 -1
- data/docs/configuration.md +64 -3
- data/docs/plugins.md +46 -0
- data/gemfiles/rails50.gemfile +56 -0
- data/gemfiles/rails51.gemfile +57 -0
- data/gemfiles/rails52.gemfile +56 -0
- data/gemfiles/rails60.gemfile +52 -0
- data/gemfiles/rails61.gemfile +52 -0
- data/gemfiles/rails70.gemfile +52 -0
- data/gemfiles/rails71.gemfile +52 -0
- data/lib/generators/rollbar/rollbar_generator.rb +24 -20
- data/lib/generators/rollbar/templates/{initializer.rb → initializer.erb} +19 -5
- data/lib/rails/rollbar_runner.rb +26 -22
- data/lib/rollbar/capistrano.rb +78 -38
- data/lib/rollbar/capistrano3.rb +62 -1
- data/lib/rollbar/capistrano_tasks.rb +166 -0
- data/lib/rollbar/configuration.rb +291 -71
- data/lib/rollbar/delay/active_job.rb +17 -0
- data/lib/rollbar/delay/delayed_job.rb +23 -0
- data/lib/rollbar/delay/girl_friday.rb +4 -9
- data/lib/rollbar/delay/resque.rb +3 -6
- data/lib/rollbar/delay/shoryuken.rb +36 -0
- data/lib/rollbar/delay/sidekiq.rb +6 -8
- data/lib/rollbar/delay/sucker_punch.rb +17 -22
- data/lib/rollbar/delay/thread.rb +74 -3
- data/lib/rollbar/deploy.rb +91 -0
- data/lib/rollbar/encoding/encoder.rb +22 -11
- data/lib/rollbar/encoding.rb +2 -7
- data/lib/rollbar/exception_reporter.rb +36 -12
- data/lib/rollbar/item/backtrace.rb +118 -0
- data/lib/rollbar/item/frame.rb +121 -0
- data/lib/rollbar/item/locals.rb +103 -0
- data/lib/rollbar/item.rb +314 -0
- data/lib/rollbar/js.rb +0 -28
- data/lib/rollbar/json.rb +7 -55
- data/lib/rollbar/language_support.rb +7 -19
- data/lib/rollbar/lazy_store.rb +8 -12
- data/lib/rollbar/logger.rb +71 -0
- data/lib/rollbar/logger_proxy.rb +18 -1
- data/lib/rollbar/middleware/js/json_value.rb +36 -0
- data/lib/rollbar/middleware/js.rb +297 -0
- data/lib/rollbar/middleware/rack/builder.rb +4 -4
- data/lib/rollbar/middleware/rack/test_session.rb +4 -4
- data/lib/rollbar/middleware/rack.rb +52 -0
- data/lib/rollbar/middleware/rails/rollbar.rb +19 -7
- data/lib/rollbar/middleware/rails/show_exceptions.rb +21 -9
- data/lib/rollbar/middleware/sinatra.rb +2 -40
- data/lib/rollbar/notifier/trace_with_bindings.rb +75 -0
- data/lib/rollbar/notifier.rb +913 -0
- data/lib/rollbar/plugin.rb +126 -0
- data/lib/rollbar/plugins/active_job.rb +54 -0
- data/lib/rollbar/plugins/basic_socket.rb +31 -0
- data/lib/rollbar/plugins/delayed_job/job_data.rb +50 -0
- data/lib/rollbar/plugins/delayed_job/plugin.rb +88 -0
- data/lib/rollbar/plugins/delayed_job.rb +12 -0
- data/lib/rollbar/plugins/error_context.rb +11 -0
- data/lib/rollbar/plugins/goalie.rb +65 -0
- data/lib/rollbar/plugins/rack.rb +18 -0
- data/lib/rollbar/plugins/rails/controller_methods.rb +56 -0
- data/lib/rollbar/plugins/rails/error_subscriber.rb +12 -0
- data/lib/rollbar/plugins/rails/railtie30.rb +18 -0
- data/lib/rollbar/plugins/rails/railtie32.rb +18 -0
- data/lib/rollbar/plugins/rails/railtie_mixin.rb +37 -0
- data/lib/rollbar/plugins/rails.rb +89 -0
- data/lib/rollbar/plugins/rake.rb +73 -0
- data/lib/rollbar/plugins/resque/failure.rb +39 -0
- data/lib/rollbar/plugins/resque.rb +11 -0
- data/lib/rollbar/plugins/sidekiq/plugin.rb +77 -0
- data/lib/rollbar/plugins/sidekiq.rb +37 -0
- data/lib/rollbar/plugins/thread.rb +14 -0
- data/lib/rollbar/plugins/validations.rb +45 -0
- data/lib/rollbar/plugins.rb +47 -0
- data/lib/rollbar/rails.rb +0 -1
- data/lib/rollbar/rake_tasks.rb +4 -66
- data/lib/rollbar/request_data_extractor.rb +157 -117
- data/lib/rollbar/rollbar_test.rb +38 -0
- data/lib/rollbar/scrubbers/params.rb +133 -0
- data/lib/rollbar/scrubbers/url.rb +90 -35
- data/lib/rollbar/scrubbers.rb +13 -0
- data/lib/rollbar/truncation/frames_strategy.rb +2 -1
- data/lib/rollbar/truncation/min_body_strategy.rb +3 -4
- data/lib/rollbar/truncation/mixin.rb +1 -1
- data/lib/rollbar/truncation/remove_any_key_strategy.rb +126 -0
- data/lib/rollbar/truncation/remove_extra_strategy.rb +37 -0
- data/lib/rollbar/truncation/remove_request_strategy.rb +21 -0
- data/lib/rollbar/truncation/strings_strategy.rb +6 -5
- data/lib/rollbar/truncation.rb +10 -4
- data/lib/rollbar/util/hash.rb +37 -6
- data/lib/rollbar/util/ip_anonymizer.rb +33 -0
- data/lib/rollbar/util/ip_obfuscator.rb +1 -1
- data/lib/rollbar/util.rb +101 -55
- data/lib/rollbar/version.rb +1 -1
- data/lib/rollbar.rb +91 -879
- data/lib/tasks/benchmark.rake +104 -0
- data/lib/tasks/tasks.rake +3 -3
- data/rollbar.gemspec +21 -32
- data/spec/support/rollbar_api.rb +67 -0
- metadata +78 -439
- data/.travis.yml +0 -155
- data/gemfiles/rails30.gemfile +0 -20
- data/gemfiles/rails31.gemfile +0 -16
- data/gemfiles/rails32.gemfile +0 -17
- data/gemfiles/rails40.gemfile +0 -17
- data/gemfiles/rails41.gemfile +0 -15
- data/gemfiles/rails42.gemfile +0 -15
- data/lib/rollbar/active_job.rb +0 -11
- data/lib/rollbar/active_record_extension.rb +0 -14
- data/lib/rollbar/core_ext/basic_socket.rb +0 -7
- data/lib/rollbar/core_ext/thread.rb +0 -9
- data/lib/rollbar/delayed_job.rb +0 -78
- data/lib/rollbar/encoding/legacy_encoder.rb +0 -20
- data/lib/rollbar/goalie.rb +0 -33
- data/lib/rollbar/js/frameworks/rails.rb +0 -29
- data/lib/rollbar/js/frameworks.rb +0 -6
- data/lib/rollbar/js/middleware.rb +0 -129
- data/lib/rollbar/js/version.rb +0 -5
- data/lib/rollbar/json/default.rb +0 -11
- data/lib/rollbar/json/oj.rb +0 -15
- data/lib/rollbar/rack.rb +0 -9
- data/lib/rollbar/rails/controller_methods.rb +0 -40
- data/lib/rollbar/railtie.rb +0 -46
- data/lib/rollbar/rake.rb +0 -38
- data/lib/rollbar/sidekiq.rb +0 -40
- data/lib/rollbar/tasks/rollbar.cap +0 -45
- data/spec/cacert.pem +0 -3988
- data/spec/controllers/home_controller_spec.rb +0 -455
- data/spec/delay/sidekiq_spec.rb +0 -61
- data/spec/delay/sucker_punch_spec.rb +0 -25
- data/spec/delayed/backend/test.rb +0 -139
- data/spec/delayed/serialization/test.rb +0 -0
- data/spec/dummyapp/.gitignore +0 -73
- data/spec/dummyapp/Rakefile +0 -7
- data/spec/dummyapp/app/assets/javascripts/application.js +0 -3
- data/spec/dummyapp/app/assets/stylesheets/application.css.scss +0 -37
- data/spec/dummyapp/app/controllers/application_controller.rb +0 -3
- data/spec/dummyapp/app/controllers/home_controller.rb +0 -60
- data/spec/dummyapp/app/controllers/users_controller.rb +0 -17
- data/spec/dummyapp/app/helpers/.gitkeep +0 -0
- data/spec/dummyapp/app/mailers/.gitkeep +0 -0
- data/spec/dummyapp/app/models/.gitkeep +0 -0
- data/spec/dummyapp/app/models/user.rb +0 -7
- data/spec/dummyapp/app/views/devise/registrations/edit.html.erb +0 -27
- data/spec/dummyapp/app/views/devise/registrations/new.html.erb +0 -20
- data/spec/dummyapp/app/views/devise/shared/_links.html.erb +0 -25
- data/spec/dummyapp/app/views/home/cause_exception.html.erb +0 -1
- data/spec/dummyapp/app/views/home/index.html.erb +0 -4
- data/spec/dummyapp/app/views/home/report_exception.html.erb +0 -1
- data/spec/dummyapp/app/views/js/test.html.erb +0 -1
- data/spec/dummyapp/app/views/layouts/_messages.html.erb +0 -5
- data/spec/dummyapp/app/views/layouts/_navigation.html.erb +0 -21
- data/spec/dummyapp/app/views/layouts/application.html.erb +0 -25
- data/spec/dummyapp/app/views/layouts/simple.html.erb +0 -18
- data/spec/dummyapp/app/views/users/index.html.erb +0 -8
- data/spec/dummyapp/app/views/users/show.html.erb +0 -3
- data/spec/dummyapp/config/application.rb +0 -59
- data/spec/dummyapp/config/boot.rb +0 -10
- data/spec/dummyapp/config/database.yml +0 -25
- data/spec/dummyapp/config/environment.rb +0 -5
- data/spec/dummyapp/config/environments/development.rb +0 -37
- data/spec/dummyapp/config/environments/production.rb +0 -67
- data/spec/dummyapp/config/environments/test.rb +0 -37
- data/spec/dummyapp/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummyapp/config/initializers/inflections.rb +0 -15
- data/spec/dummyapp/config/initializers/mime_types.rb +0 -5
- data/spec/dummyapp/config/initializers/rollbar.rb +0 -23
- data/spec/dummyapp/config/initializers/secret_token.rb +0 -7
- data/spec/dummyapp/config/initializers/session_store.rb +0 -8
- data/spec/dummyapp/config/initializers/wrap_parameters.rb +0 -16
- data/spec/dummyapp/config/locales/devise.en.yml +0 -58
- data/spec/dummyapp/config/locales/en.yml +0 -5
- data/spec/dummyapp/config/routes.rb +0 -17
- data/spec/dummyapp/config.ru +0 -4
- data/spec/dummyapp/db/migrate/20121121184652_devise_create_users.rb +0 -46
- data/spec/dummyapp/db/migrate/20121121184654_add_name_to_users.rb +0 -5
- data/spec/dummyapp/db/schema.rb +0 -35
- data/spec/dummyapp/db/seeds.rb +0 -12
- data/spec/dummyapp/lib/assets/.gitkeep +0 -0
- data/spec/dummyapp/public/404.html +0 -26
- data/spec/dummyapp/public/422.html +0 -26
- data/spec/dummyapp/public/500.html +0 -25
- data/spec/dummyapp/public/favicon.ico +0 -0
- data/spec/dummyapp/script/rails +0 -6
- data/spec/fixtures/file1 +0 -1
- data/spec/fixtures/file2 +0 -1
- data/spec/fixtures/payloads/message.json +0 -25
- data/spec/fixtures/payloads/sample.trace.json +0 -275
- data/spec/fixtures/payloads/sample.trace_chain.json +0 -530
- data/spec/generators/rollbar/rollbar_generator_spec.rb +0 -24
- data/spec/requests/home_spec.rb +0 -49
- data/spec/rollbar/active_job_spec.rb +0 -33
- data/spec/rollbar/configuration_spec.rb +0 -24
- data/spec/rollbar/delay/girl_friday_spec.rb +0 -41
- data/spec/rollbar/delay/resque_spec.rb +0 -37
- data/spec/rollbar/delay/thread_spec.rb +0 -27
- data/spec/rollbar/delayed_job/job_data.rb +0 -35
- data/spec/rollbar/delayed_job_spec.rb +0 -90
- data/spec/rollbar/encoding/encoder_spec.rb +0 -63
- data/spec/rollbar/js/frameworks/rails_spec.rb +0 -19
- data/spec/rollbar/js/middleware_spec.rb +0 -162
- data/spec/rollbar/json/oj_spec.rb +0 -18
- data/spec/rollbar/json_spec.rb +0 -110
- data/spec/rollbar/lazy_store_spec.rb +0 -99
- data/spec/rollbar/logger_proxy_spec.rb +0 -34
- data/spec/rollbar/middleware/rack/builder_spec.rb +0 -151
- data/spec/rollbar/middleware/sinatra_spec.rb +0 -197
- data/spec/rollbar/rake_spec.rb +0 -34
- data/spec/rollbar/request_data_extractor_spec.rb +0 -82
- data/spec/rollbar/scrubbers/url_spec.rb +0 -111
- data/spec/rollbar/sidekiq_spec.rb +0 -90
- data/spec/rollbar/truncation/frames_strategy_spec.rb +0 -70
- data/spec/rollbar/truncation/min_body_strategy_spec.rb +0 -57
- data/spec/rollbar/truncation/strings_strategy_spec.rb +0 -89
- data/spec/rollbar/truncation_spec.rb +0 -27
- data/spec/rollbar/util/hash_spec.rb +0 -22
- data/spec/rollbar/util_spec.rb +0 -19
- data/spec/rollbar_bc_spec.rb +0 -380
- data/spec/rollbar_spec.rb +0 -2067
- data/spec/spec_helper.rb +0 -49
- data/spec/support/cause_exception.rb +0 -1
- data/spec/support/encoding_helpers.rb +0 -8
- data/spec/support/encodings/iso_8859_9 +0 -1
- data/spec/support/fixture_helpers.rb +0 -10
- data/spec/support/get_ip_raising.rb +0 -7
- data/spec/support/helpers.rb +0 -5
- data/spec/support/notifier_helpers.rb +0 -36
- data/spec/support/shared_contexts.rb +0 -12
@@ -6,34 +6,66 @@ require 'rollbar/language_support'
|
|
6
6
|
module Rollbar
|
7
7
|
module Scrubbers
|
8
8
|
class URL
|
9
|
-
|
10
|
-
attr_reader :scrub_user
|
11
|
-
attr_reader :scrub_password
|
12
|
-
attr_reader :randomize_scrub_length
|
9
|
+
SCRUB_ALL = :scrub_all
|
13
10
|
|
14
|
-
def
|
15
|
-
|
16
|
-
@scrub_user = options[:scrub_user]
|
17
|
-
@scrub_password = options[:scrub_password]
|
18
|
-
@randomize_scrub_length = options.fetch(:randomize_scrub_length, true)
|
11
|
+
def self.call(*args)
|
12
|
+
new.call(*args)
|
19
13
|
end
|
20
14
|
|
21
|
-
def call(
|
22
|
-
|
15
|
+
def call(options = {})
|
16
|
+
url = ascii_encode(options[:url])
|
17
|
+
|
18
|
+
filter(url,
|
19
|
+
build_regex(options[:scrub_fields]),
|
20
|
+
options[:scrub_user],
|
21
|
+
options[:scrub_password],
|
22
|
+
options.fetch(:randomize_scrub_length, true),
|
23
|
+
options[:scrub_fields].include?(SCRUB_ALL),
|
24
|
+
build_whitelist_regex(options[:whitelist] || []))
|
25
|
+
rescue StandardError => e
|
26
|
+
message = '[Rollbar] There was an error scrubbing the url: ' \
|
27
|
+
"#{e}, options: #{options.inspect}"
|
28
|
+
Rollbar.logger.error(message)
|
29
|
+
url
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
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
|
+
|
49
|
+
def build_whitelist_regex(whitelist)
|
50
|
+
fields = whitelist.find_all { |f| f.is_a?(String) || f.is_a?(Symbol) }
|
51
|
+
return unless fields.any?
|
52
|
+
|
53
|
+
Regexp.new(fields.map { |val| /\A#{Regexp.escape(val.to_s)}\z/ }.join('|'))
|
54
|
+
end
|
23
55
|
|
56
|
+
def filter(url, regex, scrub_user, scrub_password, randomize_scrub_length,
|
57
|
+
scrub_all, whitelist)
|
24
58
|
uri = URI.parse(url)
|
25
59
|
|
26
|
-
uri.user = filter_user(uri.user)
|
27
|
-
uri.password = filter_password(uri.password
|
28
|
-
|
60
|
+
uri.user = filter_user(uri.user, scrub_user, randomize_scrub_length)
|
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)
|
29
65
|
|
30
66
|
uri.to_s
|
31
|
-
rescue
|
32
|
-
url
|
33
67
|
end
|
34
68
|
|
35
|
-
private
|
36
|
-
|
37
69
|
# Builds a regex to match with any of the received fields.
|
38
70
|
# The built regex will also match array params like 'user_ids[]'.
|
39
71
|
def build_regex(fields)
|
@@ -42,23 +74,26 @@ module Rollbar
|
|
42
74
|
Regexp.new("^#{fields_or}$")
|
43
75
|
end
|
44
76
|
|
45
|
-
def filter_user(user)
|
46
|
-
scrub_user && user ? filtered_value(user) : user
|
77
|
+
def filter_user(user, scrub_user, randomize_scrub_length)
|
78
|
+
scrub_user && user ? filtered_value(user, randomize_scrub_length) : user
|
47
79
|
end
|
48
80
|
|
49
|
-
def filter_password(password)
|
50
|
-
scrub_password && password
|
81
|
+
def filter_password(password, scrub_password, randomize_scrub_length)
|
82
|
+
if scrub_password && password
|
83
|
+
filtered_value(password,
|
84
|
+
randomize_scrub_length)
|
85
|
+
else
|
86
|
+
password
|
87
|
+
end
|
51
88
|
end
|
52
89
|
|
53
|
-
def filter_query(query)
|
90
|
+
def filter_query(query, regex, randomize_scrub_length, scrub_all, whitelist)
|
54
91
|
return query unless query
|
55
92
|
|
56
93
|
params = decode_www_form(query)
|
57
94
|
|
58
|
-
|
59
|
-
|
60
|
-
# We want this to rebuild array params like foo[]=1&foo[]=2
|
61
|
-
CGI.unescape(encoded_query)
|
95
|
+
encode_www_form(filter_query_params(params, regex, randomize_scrub_length,
|
96
|
+
scrub_all, whitelist))
|
62
97
|
end
|
63
98
|
|
64
99
|
def decode_www_form(query)
|
@@ -66,29 +101,49 @@ module Rollbar
|
|
66
101
|
end
|
67
102
|
|
68
103
|
def encode_www_form(params)
|
69
|
-
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', ']')
|
70
114
|
end
|
71
115
|
|
72
|
-
def filter_query_params(params
|
116
|
+
def filter_query_params(params, regex, randomize_scrub_length, scrub_all,
|
117
|
+
whitelist)
|
73
118
|
params.map do |key, value|
|
74
|
-
[key,
|
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]
|
75
126
|
end
|
76
127
|
end
|
77
128
|
|
78
|
-
def filter_key?(key)
|
79
|
-
|
129
|
+
def filter_key?(key, regex, scrub_all, whitelist)
|
130
|
+
!(whitelist === key) && (scrub_all || regex === key)
|
80
131
|
end
|
81
132
|
|
82
|
-
def filtered_value(value)
|
133
|
+
def filtered_value(value, randomize_scrub_length)
|
83
134
|
if randomize_scrub_length
|
84
135
|
random_filtered_value
|
85
136
|
else
|
86
|
-
'*' * (
|
137
|
+
'*' * (begin
|
138
|
+
value.length
|
139
|
+
rescue StandardError
|
140
|
+
8
|
141
|
+
end)
|
87
142
|
end
|
88
143
|
end
|
89
144
|
|
90
145
|
def random_filtered_value
|
91
|
-
'*' *
|
146
|
+
'*' * rand(3..7)
|
92
147
|
end
|
93
148
|
end
|
94
149
|
end
|
data/lib/rollbar/scrubbers.rb
CHANGED
@@ -1,4 +1,17 @@
|
|
1
1
|
module Rollbar
|
2
2
|
module Scrubbers
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def scrub_value(_value)
|
6
|
+
if Rollbar.configuration.randomize_scrub_length
|
7
|
+
random_filtered_value
|
8
|
+
else
|
9
|
+
'*' * 6
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def random_filtered_value
|
14
|
+
'*' * rand(3..7)
|
15
|
+
end
|
3
16
|
end
|
4
17
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rollbar/truncation/mixin'
|
2
|
+
require 'rollbar/util'
|
2
3
|
|
3
4
|
module Rollbar
|
4
5
|
module Truncation
|
@@ -10,7 +11,7 @@ module Rollbar
|
|
10
11
|
end
|
11
12
|
|
12
13
|
def call(payload)
|
13
|
-
new_payload = payload
|
14
|
+
new_payload = payload
|
14
15
|
body = new_payload['data']['body']
|
15
16
|
|
16
17
|
if body['trace_chain']
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rollbar/truncation/mixin'
|
2
|
+
require 'rollbar/util'
|
2
3
|
|
3
4
|
module Rollbar
|
4
5
|
module Truncation
|
@@ -10,8 +11,7 @@ module Rollbar
|
|
10
11
|
end
|
11
12
|
|
12
13
|
def call(payload)
|
13
|
-
|
14
|
-
body = new_payload['data']['body']
|
14
|
+
body = payload['data']['body']
|
15
15
|
|
16
16
|
if body['trace_chain']
|
17
17
|
body['trace_chain'] = body['trace_chain'].map do |trace_data|
|
@@ -21,8 +21,7 @@ module Rollbar
|
|
21
21
|
body['trace'] = truncate_trace_data(body['trace'])
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
dump(new_payload)
|
24
|
+
dump(payload)
|
26
25
|
end
|
27
26
|
|
28
27
|
def truncate_trace_data(trace_data)
|
@@ -0,0 +1,126 @@
|
|
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
|
+
|
95
|
+
return unless body['trace_chain'] && body['trace_chain'][0]
|
96
|
+
|
97
|
+
extract_title_from_trace(body['trace_chain'][0])
|
98
|
+
end
|
99
|
+
|
100
|
+
def extract_title_from_trace(trace)
|
101
|
+
exception = trace['exception']
|
102
|
+
|
103
|
+
"#{exception['class']}: #{exception['message']}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def data_keys
|
107
|
+
@data_keys ||= {}.tap do |hash|
|
108
|
+
data.keys.reject { |key| skip_keys.include?(key) }.each do |key|
|
109
|
+
set_key_size(key, hash)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def set_key_size(key, hash)
|
115
|
+
size = dump(data[key]).bytesize
|
116
|
+
hash[key] = size
|
117
|
+
rescue ::JSON::GeneratorError
|
118
|
+
hash[key] = 0 # don't try to truncate non JSON object
|
119
|
+
|
120
|
+
# Log it
|
121
|
+
truncation_key['non_json_keys'] ||= {}
|
122
|
+
truncation_key['non_json_keys'][key] = data[key].class
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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
|
+
return unless body['trace_chain'] && body['trace_chain'][0]['extra']
|
28
|
+
|
29
|
+
body['trace_chain'][0].delete('extra')
|
30
|
+
end
|
31
|
+
|
32
|
+
def delete_trace_extra(body)
|
33
|
+
body['trace'].delete('extra') if body['trace'] && body['trace']['extra']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
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]
|
9
|
+
STRING_THRESHOLDS = [1024, 512, 256, 128].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 = payload.clone
|
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(
|
23
|
-
result = dump(
|
21
|
+
::Rollbar::Util.iterate_and_update(payload, truncate_proc)
|
22
|
+
result = dump(payload)
|
24
23
|
|
25
24
|
break unless truncate?(result)
|
26
25
|
end
|
@@ -30,7 +29,9 @@ module Rollbar
|
|
30
29
|
|
31
30
|
def truncate_strings_proc(threshold)
|
32
31
|
proc do |value|
|
33
|
-
|
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
|
34
35
|
Rollbar::Util.truncate(value, threshold)
|
35
36
|
else
|
36
37
|
value
|
data/lib/rollbar/truncation.rb
CHANGED
@@ -4,23 +4,29 @@ 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
|
10
13
|
extend ::Rollbar::Truncation::Mixin
|
11
14
|
|
12
|
-
MAX_PAYLOAD_SIZE =
|
15
|
+
MAX_PAYLOAD_SIZE = 512 * 1024 # 512kb
|
13
16
|
STRATEGIES = [RawStrategy,
|
14
17
|
FramesStrategy,
|
15
18
|
StringsStrategy,
|
16
|
-
MinBodyStrategy
|
17
|
-
|
19
|
+
MinBodyStrategy,
|
20
|
+
RemoveRequestStrategy,
|
21
|
+
RemoveExtraStrategy,
|
22
|
+
RemoveAnyKeyStrategy].freeze
|
18
23
|
|
19
|
-
def self.truncate(payload)
|
24
|
+
def self.truncate(payload, attempts = [])
|
20
25
|
result = nil
|
21
26
|
|
22
27
|
STRATEGIES.each do |strategy|
|
23
28
|
result = strategy.call(payload)
|
29
|
+
attempts << result.bytesize
|
24
30
|
break unless truncate?(result)
|
25
31
|
end
|
26
32
|
|
data/lib/rollbar/util/hash.rb
CHANGED
@@ -1,24 +1,55 @@
|
|
1
1
|
module Rollbar
|
2
2
|
module Util
|
3
|
-
module Hash
|
4
|
-
def self.deep_stringify_keys(hash)
|
3
|
+
module Hash # :nodoc:
|
4
|
+
def self.deep_stringify_keys(hash, seen = {})
|
5
|
+
seen.compare_by_identity
|
6
|
+
return if seen[hash]
|
7
|
+
|
8
|
+
seen[hash] = true
|
9
|
+
replace_seen_children(hash, seen)
|
10
|
+
|
5
11
|
hash.reduce({}) do |h, (key, value)|
|
6
|
-
h[key.to_s] = map_value(value, :deep_stringify_keys)
|
12
|
+
h[key.to_s] = map_value(value, :deep_stringify_keys, seen)
|
7
13
|
|
8
14
|
h
|
9
15
|
end
|
10
16
|
end
|
11
17
|
|
12
|
-
def self.map_value(thing,
|
18
|
+
def self.map_value(thing, meth, seen)
|
13
19
|
case thing
|
14
20
|
when ::Hash
|
15
|
-
send(
|
21
|
+
send(meth, thing, seen)
|
16
22
|
when Array
|
17
|
-
thing
|
23
|
+
if seen[thing]
|
24
|
+
thing
|
25
|
+
else
|
26
|
+
seen[thing] = true
|
27
|
+
replace_seen_children(thing, seen)
|
28
|
+
thing.map { |v| map_value(v, meth, seen) }
|
29
|
+
end
|
18
30
|
else
|
19
31
|
thing
|
20
32
|
end
|
21
33
|
end
|
34
|
+
|
35
|
+
def self.replace_seen_children(thing, seen)
|
36
|
+
case thing
|
37
|
+
when ::Hash
|
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
|
43
|
+
end
|
44
|
+
when Array
|
45
|
+
thing.each_with_index do |_, i|
|
46
|
+
if seen[thing[i]]
|
47
|
+
thing[i] =
|
48
|
+
"removed circular reference: #{thing[i]}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
22
53
|
end
|
23
54
|
end
|
24
55
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Rollbar
|
2
|
+
module Util
|
3
|
+
module IPAnonymizer
|
4
|
+
require 'ipaddr'
|
5
|
+
|
6
|
+
def self.anonymize_ip(ip_string)
|
7
|
+
return ip_string unless Rollbar.configuration.anonymize_user_ip
|
8
|
+
|
9
|
+
ip = IPAddr.new(ip_string)
|
10
|
+
return anonymize_ipv6 ip if ip.ipv6?
|
11
|
+
return anonymize_ipv4 ip if ip.ipv4?
|
12
|
+
rescue StandardError
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.anonymize_ipv4(ip)
|
17
|
+
ip_parts = ip.to_s.split '.'
|
18
|
+
|
19
|
+
ip_parts[ip_parts.count - 1] = '0'
|
20
|
+
|
21
|
+
IPAddr.new(ip_parts.join('.')).to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.anonymize_ipv6(ip)
|
25
|
+
ip_parts = ip.to_s.split ':'
|
26
|
+
|
27
|
+
ip_string = "#{ip_parts[0..2].join(':')}:0000:0000:0000:0000:0000"
|
28
|
+
|
29
|
+
IPAddr.new(ip_string).to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|