rollbar 2.23.2 → 3.3.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 +4 -4
- data/.github/pull_request_template.md +25 -0
- data/.github/workflows/ci.yml +118 -0
- data/.rubocop.yml +85 -34
- data/Gemfile +22 -22
- data/README.md +11 -9
- data/data/rollbar.snippet.js +1 -1
- data/docs/configuration.md +8 -0
- data/gemfiles/rails30.gemfile +18 -35
- data/gemfiles/rails31.gemfile +21 -37
- data/gemfiles/rails32.gemfile +14 -31
- data/gemfiles/rails40.gemfile +13 -32
- data/gemfiles/rails41.gemfile +12 -31
- data/gemfiles/rails42.gemfile +12 -35
- data/gemfiles/rails50.gemfile +17 -29
- data/gemfiles/rails51.gemfile +17 -29
- data/gemfiles/rails52.gemfile +7 -14
- data/gemfiles/rails60.gemfile +7 -20
- data/gemfiles/rails61.gemfile +54 -0
- data/lib/generators/rollbar/rollbar_generator.rb +18 -14
- data/lib/generators/rollbar/templates/{initializer.rb → initializer.erb} +0 -0
- data/lib/rails/rollbar_runner.rb +15 -6
- data/lib/rollbar/capistrano.rb +17 -9
- data/lib/rollbar/capistrano3.rb +8 -2
- data/lib/rollbar/capistrano_tasks.rb +44 -8
- data/lib/rollbar/configuration.rb +128 -84
- data/lib/rollbar/delay/shoryuken.rb +4 -3
- data/lib/rollbar/delay/sidekiq.rb +3 -1
- data/lib/rollbar/delay/sucker_punch.rb +1 -2
- data/lib/rollbar/delay/thread.rb +3 -2
- data/lib/rollbar/deploy.rb +8 -7
- data/lib/rollbar/encoding/encoder.rb +10 -3
- data/lib/rollbar/exception_reporter.rb +17 -8
- data/lib/rollbar/item/backtrace.rb +11 -9
- data/lib/rollbar/item/frame.rb +6 -5
- data/lib/rollbar/item/locals.rb +3 -2
- data/lib/rollbar/item.rb +68 -40
- data/lib/rollbar/json.rb +2 -1
- data/lib/rollbar/language_support.rb +0 -6
- data/lib/rollbar/lazy_store.rb +3 -7
- data/lib/rollbar/logger.rb +2 -0
- data/lib/rollbar/logger_proxy.rb +3 -1
- data/lib/rollbar/middleware/js.rb +64 -37
- data/lib/rollbar/middleware/rack/builder.rb +3 -3
- data/lib/rollbar/middleware/rack/test_session.rb +3 -3
- data/lib/rollbar/middleware/rack.rb +4 -4
- data/lib/rollbar/middleware/rails/rollbar.rb +9 -6
- data/lib/rollbar/middleware/rails/show_exceptions.rb +8 -4
- data/lib/rollbar/notifier/trace_with_bindings.rb +4 -2
- data/lib/rollbar/notifier.rb +272 -159
- data/lib/rollbar/plugin.rb +8 -8
- data/lib/rollbar/plugins/active_job.rb +11 -2
- data/lib/rollbar/plugins/delayed_job/plugin.rb +19 -2
- data/lib/rollbar/plugins/goalie.rb +27 -16
- data/lib/rollbar/plugins/rails/controller_methods.rb +18 -14
- data/lib/rollbar/plugins/rails/railtie30.rb +2 -1
- data/lib/rollbar/plugins/rails/railtie32.rb +2 -1
- data/lib/rollbar/plugins/rails/railtie_mixin.rb +2 -2
- data/lib/rollbar/plugins/rails.rb +5 -2
- data/lib/rollbar/plugins/rake.rb +2 -1
- data/lib/rollbar/plugins/sidekiq/plugin.rb +37 -20
- data/lib/rollbar/plugins/sidekiq.rb +1 -1
- data/lib/rollbar/plugins/thread.rb +8 -7
- data/lib/rollbar/plugins/validations.rb +3 -1
- data/lib/rollbar/rake_tasks.rb +1 -2
- data/lib/rollbar/request_data_extractor.rb +43 -16
- data/lib/rollbar/rollbar_test.rb +9 -118
- data/lib/rollbar/scrubbers/params.rb +13 -7
- data/lib/rollbar/scrubbers/url.rb +56 -17
- data/lib/rollbar/scrubbers.rb +1 -1
- data/lib/rollbar/truncation/remove_any_key_strategy.rb +4 -1
- data/lib/rollbar/truncation/remove_extra_strategy.rb +3 -1
- data/lib/rollbar/util/hash.rb +14 -7
- data/lib/rollbar/util/ip_anonymizer.rb +1 -1
- data/lib/rollbar/util.rb +19 -13
- data/lib/rollbar/version.rb +1 -1
- data/lib/rollbar.rb +12 -7
- data/lib/tasks/benchmark.rake +2 -1
- data/rollbar.gemspec +5 -2
- data/spec/support/rollbar_api.rb +67 -0
- metadata +9 -6
- data/.travis.yml +0 -284
data/lib/rollbar/rollbar_test.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
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
|
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
|
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
|
-
@
|
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
|
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
|
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 @
|
67
|
+
return params if @scrubbed_objects[params]
|
63
68
|
|
64
|
-
@
|
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) &&
|
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
|
-
|
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,
|
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,
|
44
|
-
|
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
|
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
|
-
|
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,
|
116
|
+
def filter_query_params(params, regex, randomize_scrub_length, scrub_all,
|
117
|
+
whitelist)
|
85
118
|
params.map do |key, value|
|
86
|
-
[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]
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
138
|
+
value.length
|
139
|
+
rescue StandardError
|
140
|
+
8
|
141
|
+
end)
|
103
142
|
end
|
104
143
|
end
|
105
144
|
|
data/lib/rollbar/scrubbers.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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)
|
data/lib/rollbar/util/hash.rb
CHANGED
@@ -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
|
-
|
5
|
+
seen.compare_by_identity
|
6
|
+
return if seen[hash]
|
6
7
|
|
7
|
-
seen[hash
|
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
|
23
|
+
if seen[thing]
|
23
24
|
thing
|
24
25
|
else
|
25
|
-
seen[thing
|
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
|
-
|
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
|
-
|
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(':')
|
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
@@ -7,9 +7,10 @@ module Rollbar
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.iterate_and_update(obj, block, seen = {})
|
10
|
-
|
10
|
+
seen.compare_by_identity
|
11
|
+
return if obj.frozen? || seen[obj]
|
11
12
|
|
12
|
-
seen[obj
|
13
|
+
seen[obj] = true
|
13
14
|
|
14
15
|
if obj.is_a?(Array)
|
15
16
|
iterate_and_update_array(obj, block, seen)
|
@@ -29,7 +30,7 @@ module Rollbar
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def self.iterate_and_update_hash(obj, block, seen)
|
32
|
-
obj.keys.each do |k|
|
33
|
+
obj.keys.each do |k| # rubocop:disable Style/HashEachMethods
|
33
34
|
v = obj[k]
|
34
35
|
new_key = block.call(k)
|
35
36
|
|
@@ -47,18 +48,21 @@ module Rollbar
|
|
47
48
|
end
|
48
49
|
|
49
50
|
def self.deep_copy(obj, copied = {})
|
51
|
+
copied.compare_by_identity
|
52
|
+
|
50
53
|
# if we've already made a copy, return it.
|
51
|
-
return copied[obj
|
54
|
+
return copied[obj] if copied[obj]
|
52
55
|
|
53
56
|
result = clone_obj(obj)
|
54
57
|
|
55
58
|
# Memoize the cloned object before recursive calls to #deep_copy below.
|
56
59
|
# This is the point of doing the work in two steps.
|
57
|
-
copied[obj
|
60
|
+
copied[obj] = result
|
58
61
|
|
59
|
-
|
62
|
+
case obj
|
63
|
+
when ::Hash
|
60
64
|
obj.each { |k, v| result[k] = deep_copy(v, copied) }
|
61
|
-
|
65
|
+
when Array
|
62
66
|
obj.each { |v| result << deep_copy(v, copied) }
|
63
67
|
end
|
64
68
|
|
@@ -66,9 +70,10 @@ module Rollbar
|
|
66
70
|
end
|
67
71
|
|
68
72
|
def self.clone_obj(obj)
|
69
|
-
|
73
|
+
case obj
|
74
|
+
when ::Hash
|
70
75
|
obj.dup
|
71
|
-
|
76
|
+
when Array
|
72
77
|
obj.dup.clear
|
73
78
|
else
|
74
79
|
obj
|
@@ -78,12 +83,13 @@ module Rollbar
|
|
78
83
|
def self.deep_merge(hash1, hash2, merged = {})
|
79
84
|
hash1 ||= {}
|
80
85
|
hash2 ||= {}
|
86
|
+
merged.compare_by_identity
|
81
87
|
|
82
88
|
# If we've already merged these two objects, return hash1 now.
|
83
|
-
return hash1 if merged[hash1
|
89
|
+
return hash1 if merged[hash1] && merged[hash1].include?(hash2.object_id)
|
84
90
|
|
85
|
-
merged[hash1
|
86
|
-
merged[hash1
|
91
|
+
merged[hash1] ||= []
|
92
|
+
merged[hash1] << hash2.object_id
|
87
93
|
|
88
94
|
perform_deep_merge(hash1, hash2, merged)
|
89
95
|
|
@@ -121,7 +127,7 @@ module Rollbar
|
|
121
127
|
end
|
122
128
|
|
123
129
|
def self.count_method_in_stack(method_symbol, file_path = '')
|
124
|
-
caller.grep(/#{file_path}.*#{method_symbol
|
130
|
+
caller.grep(/#{file_path}.*#{method_symbol}/).count
|
125
131
|
end
|
126
132
|
|
127
133
|
def self.method_in_stack(method_symbol, file_path = '')
|
data/lib/rollbar/version.rb
CHANGED
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,
|
164
|
-
|
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,
|
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,
|
182
|
-
|
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
|
data/lib/tasks/benchmark.rake
CHANGED
@@ -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,
|
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
@@ -12,10 +12,13 @@ Gem::Specification.new do |gem|
|
|
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
|
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 = '>=
|
21
|
+
gem.required_ruby_version = '>= 2.0.0'
|
19
22
|
gem.version = Rollbar::VERSION
|
20
23
|
|
21
24
|
if gem.respond_to?(:metadata)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rack/request'
|
2
|
+
|
3
|
+
class RollbarAPI
|
4
|
+
UNAUTHORIZED_ACCESS_TOKEN = 'unauthorized'.freeze
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
request = Rack::Request.new(env)
|
8
|
+
json = JSON.parse(request.body.read)
|
9
|
+
|
10
|
+
return unauthorized unless authorized?(json, request)
|
11
|
+
|
12
|
+
return bad_request(json) unless valid_data?(json, request)
|
13
|
+
|
14
|
+
success(json, request)
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def authorized?(_json, request)
|
20
|
+
request.env['HTTP_X_ROLLBAR_ACCESS_TOKEN'] != UNAUTHORIZED_ACCESS_TOKEN
|
21
|
+
end
|
22
|
+
|
23
|
+
def response_headers
|
24
|
+
{
|
25
|
+
'Content-Type' => 'application/json'
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def valid_data?(_json, request)
|
30
|
+
!!request.env['HTTP_X_ROLLBAR_ACCESS_TOKEN']
|
31
|
+
end
|
32
|
+
|
33
|
+
def unauthorized
|
34
|
+
[401, response_headers, [unauthorized_body]]
|
35
|
+
end
|
36
|
+
|
37
|
+
def bad_request(_json)
|
38
|
+
[400, response_headers, [bad_request_body]]
|
39
|
+
end
|
40
|
+
|
41
|
+
def success(json, request)
|
42
|
+
[200, response_headers, [success_body(json, request)]]
|
43
|
+
end
|
44
|
+
|
45
|
+
def unauthorized_body
|
46
|
+
result(1, nil, 'invalid access token')
|
47
|
+
end
|
48
|
+
|
49
|
+
def bad_request_body
|
50
|
+
result(1, nil, 'bad request')
|
51
|
+
end
|
52
|
+
|
53
|
+
def success_body(json, _request)
|
54
|
+
result(0, {
|
55
|
+
:id => rand(1_000_000),
|
56
|
+
:uuid => json['data']['uuid']
|
57
|
+
}, nil)
|
58
|
+
end
|
59
|
+
|
60
|
+
def result(err, body, message)
|
61
|
+
{
|
62
|
+
:err => err,
|
63
|
+
:result => body,
|
64
|
+
:message => message
|
65
|
+
}.to_json
|
66
|
+
end
|
67
|
+
end
|