rollbar 2.12.0 → 2.13.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/CHANGELOG.md +33 -6
- data/README.md +58 -8
- data/docs/configuration.md +12 -0
- data/gemfiles/rails30.gemfile +1 -0
- data/gemfiles/rails31.gemfile +1 -0
- data/gemfiles/rails32.gemfile +1 -0
- data/gemfiles/rails40.gemfile +3 -0
- data/gemfiles/rails41.gemfile +1 -0
- data/gemfiles/rails42.gemfile +7 -1
- data/gemfiles/rails50.gemfile +2 -1
- data/gemfiles/ruby_1_8_and_1_9_2.gemfile +3 -1
- data/lib/rollbar.rb +70 -654
- data/lib/rollbar/configuration.rb +32 -0
- data/lib/rollbar/item.rb +16 -6
- data/lib/rollbar/item/backtrace.rb +26 -17
- data/lib/rollbar/item/frame.rb +112 -0
- data/lib/rollbar/middleware/js.rb +39 -35
- data/lib/rollbar/middleware/rails/rollbar.rb +3 -3
- data/lib/rollbar/notifier.rb +645 -0
- data/lib/rollbar/plugins/delayed_job/job_data.rb +40 -21
- data/lib/rollbar/plugins/rails.rb +2 -2
- data/lib/rollbar/plugins/rake.rb +32 -6
- data/lib/rollbar/plugins/resque.rb +11 -0
- data/lib/rollbar/plugins/resque/failure.rb +39 -0
- data/lib/rollbar/plugins/validations.rb +10 -0
- data/lib/rollbar/request_data_extractor.rb +36 -18
- data/lib/rollbar/scrubbers/params.rb +2 -1
- data/lib/rollbar/truncation.rb +1 -1
- data/lib/rollbar/truncation/frames_strategy.rb +2 -1
- data/lib/rollbar/truncation/min_body_strategy.rb +2 -1
- data/lib/rollbar/truncation/strings_strategy.rb +1 -1
- data/lib/rollbar/version.rb +1 -1
- data/spec/controllers/home_controller_spec.rb +13 -24
- data/spec/delayed/backend/test.rb +1 -0
- data/spec/requests/home_spec.rb +1 -1
- data/spec/rollbar/configuration_spec.rb +22 -0
- data/spec/rollbar/item/backtrace_spec.rb +26 -0
- data/spec/rollbar/item/frame_spec.rb +267 -0
- data/spec/rollbar/item_spec.rb +27 -2
- data/spec/rollbar/middleware/js_spec.rb +23 -0
- data/spec/rollbar/middleware/sinatra_spec.rb +7 -7
- data/spec/rollbar/notifier_spec.rb +43 -0
- data/spec/rollbar/plugins/delayed_job/{job_data.rb → job_data_spec.rb} +15 -2
- data/spec/rollbar/plugins/rack_spec.rb +7 -7
- data/spec/rollbar/plugins/rake_spec.rb +1 -2
- data/spec/rollbar/plugins/resque/failure_spec.rb +36 -0
- data/spec/rollbar/request_data_extractor_spec.rb +103 -1
- data/spec/rollbar/truncation/min_body_strategy_spec.rb +1 -1
- data/spec/rollbar/truncation/strings_strategy_spec.rb +2 -2
- data/spec/rollbar_bc_spec.rb +4 -4
- data/spec/rollbar_spec.rb +99 -37
- data/spec/spec_helper.rb +2 -2
- data/spec/support/notifier_helpers.rb +2 -0
- metadata +16 -4
data/spec/requests/home_spec.rb
CHANGED
@@ -32,7 +32,7 @@ describe HomeController do
|
|
32
32
|
ActionDispatch::Cookies::CookieJar.send(:define_method, cookie_method_name, broken_cookie_method)
|
33
33
|
end
|
34
34
|
|
35
|
-
after
|
35
|
+
after do
|
36
36
|
ActionDispatch::Cookies::CookieJar.send(:define_method, cookie_method_name, original_cookie_method)
|
37
37
|
end
|
38
38
|
|
@@ -21,4 +21,26 @@ describe Rollbar::Configuration do
|
|
21
21
|
expect(subject.async_handler).to be_eql(Rollbar::Delay::Resque)
|
22
22
|
end
|
23
23
|
end
|
24
|
+
|
25
|
+
describe '#merge' do
|
26
|
+
it 'returns a new object with overrided values' do
|
27
|
+
subject.environment = 'foo'
|
28
|
+
|
29
|
+
new_config = subject.merge(:environment => 'bar')
|
30
|
+
|
31
|
+
expect(new_config).not_to be(subject)
|
32
|
+
expect(new_config.environment).to be_eql('bar')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#merge!' do
|
37
|
+
it 'returns the same object with overrided values' do
|
38
|
+
subject.environment = 'foo'
|
39
|
+
|
40
|
+
new_config = subject.merge!(:environment => 'bar')
|
41
|
+
|
42
|
+
expect(new_config).to be(subject)
|
43
|
+
expect(new_config.environment).to be_eql('bar')
|
44
|
+
end
|
45
|
+
end
|
24
46
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'rollbar/item/backtrace'
|
4
|
+
|
5
|
+
describe Rollbar::Item::Backtrace do
|
6
|
+
describe '#get_file_lines' do
|
7
|
+
subject { described_class.new(exception) }
|
8
|
+
|
9
|
+
let(:exception) { Exception.new }
|
10
|
+
let(:file) { Tempfile.new('foo') }
|
11
|
+
|
12
|
+
before do
|
13
|
+
File.open(file.path, 'w') do |f|
|
14
|
+
f << "foo\nbar"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns the lines of the file' do
|
19
|
+
lines = subject.get_file_lines(file.path)
|
20
|
+
|
21
|
+
expect(lines.size).to be_eql(2)
|
22
|
+
expect(lines[0]).to be_eql('foo')
|
23
|
+
expect(lines[1]).to be_eql('bar')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'rollbar/item/backtrace'
|
4
|
+
require 'rollbar/item/frame'
|
5
|
+
|
6
|
+
describe Rollbar::Item::Frame do
|
7
|
+
subject { described_class.new(backtrace, frame, options) }
|
8
|
+
|
9
|
+
let(:backtrace) { double('backtrace') }
|
10
|
+
let(:options) { {} }
|
11
|
+
|
12
|
+
describe '#to_h' do
|
13
|
+
context 'with a frame that is not a valid frame' do
|
14
|
+
let(:frame) { 'this frame is not valid' }
|
15
|
+
|
16
|
+
it 'return an unknown frame value' do
|
17
|
+
expected_result = {
|
18
|
+
:filename => '<unknown>',
|
19
|
+
:lineno => 0,
|
20
|
+
:method => frame
|
21
|
+
}
|
22
|
+
|
23
|
+
result = subject.to_h
|
24
|
+
expect(result).to be_eql(expected_result)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with valid frame' do
|
29
|
+
let(:file) do
|
30
|
+
<<-END
|
31
|
+
foo1
|
32
|
+
foo2
|
33
|
+
foo3
|
34
|
+
foo4
|
35
|
+
foo5
|
36
|
+
foo6
|
37
|
+
foo7
|
38
|
+
foo8
|
39
|
+
foo9
|
40
|
+
foo10
|
41
|
+
foo11
|
42
|
+
foo12
|
43
|
+
foo13
|
44
|
+
END
|
45
|
+
end
|
46
|
+
let(:filepath) do
|
47
|
+
'/var/www/rollbar/playground/rails4.2/vendor/bundle/gems/actionpack-4.2.0/lib/action_controller/metal/implicit_render.rb'
|
48
|
+
end
|
49
|
+
let(:frame) do
|
50
|
+
"#{filepath}:7:in `send_action'"
|
51
|
+
end
|
52
|
+
let(:options) do
|
53
|
+
{ :configuration => configuration }
|
54
|
+
end
|
55
|
+
|
56
|
+
before do
|
57
|
+
allow(backtrace).to receive(:get_file_lines).with(filepath).and_return(file.split("\n"))
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'with send_extra_frame_data = :none' do
|
61
|
+
let(:configuration) do
|
62
|
+
double('configuration',
|
63
|
+
:send_extra_frame_data => :none,
|
64
|
+
:root => '/var/www')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'just return the filename, lineno and method' do
|
68
|
+
expected_result = {
|
69
|
+
:filename => filepath,
|
70
|
+
:lineno => 7,
|
71
|
+
:method => 'send_action'
|
72
|
+
}
|
73
|
+
|
74
|
+
expect(subject.to_h).to be_eql(expected_result)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'with send_extra_frame_data = :all' do
|
79
|
+
let(:configuration) do
|
80
|
+
double('configuration',
|
81
|
+
:send_extra_frame_data => :all,
|
82
|
+
:root => '/var/www')
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'returns also code and context' do
|
86
|
+
expected_result = {
|
87
|
+
:filename => filepath,
|
88
|
+
:lineno => 7,
|
89
|
+
:method => 'send_action',
|
90
|
+
:code => 'foo7',
|
91
|
+
:context => {
|
92
|
+
:pre => %w(foo3 foo4 foo5 foo6),
|
93
|
+
:post => %w(foo8 foo9 foo10 foo11)
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
expect(subject.to_h).to be_eql(expected_result)
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'if there is not lines in the file' do
|
101
|
+
let(:file) do
|
102
|
+
''
|
103
|
+
end
|
104
|
+
it 'just returns the basic data' do
|
105
|
+
expected_result = {
|
106
|
+
:filename => filepath,
|
107
|
+
:lineno => 7,
|
108
|
+
:method => 'send_action'
|
109
|
+
}
|
110
|
+
|
111
|
+
expect(subject.to_h).to be_eql(expected_result)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'if the file couldnt be read' do
|
116
|
+
before do
|
117
|
+
allow(backtrace).to receive(:get_file_lines).with(filepath).and_return(nil)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'just returns the basic data' do
|
121
|
+
expected_result = {
|
122
|
+
:filename => filepath,
|
123
|
+
:lineno => 7,
|
124
|
+
:method => 'send_action'
|
125
|
+
}
|
126
|
+
|
127
|
+
expect(subject.to_h).to be_eql(expected_result)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'with send_extra_frame_data = :app' do
|
133
|
+
context 'with frame outside the root' do
|
134
|
+
let(:configuration) do
|
135
|
+
double('configuration',
|
136
|
+
:send_extra_frame_data => :app,
|
137
|
+
:root => '/outside/project',
|
138
|
+
:project_gem_paths => [])
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'just returns the basic frame data' do
|
142
|
+
expected_result = {
|
143
|
+
:filename => filepath,
|
144
|
+
:lineno => 7,
|
145
|
+
:method => 'send_action'
|
146
|
+
}
|
147
|
+
|
148
|
+
expect(subject.to_h).to be_eql(expected_result)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'with frame inside project_gem_paths' do
|
153
|
+
let(:configuration) do
|
154
|
+
double('configuration',
|
155
|
+
:send_extra_frame_data => :app,
|
156
|
+
:root => '/var/outside/',
|
157
|
+
:project_gem_paths => ['/var/www/'])
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'returns also context and code data' do
|
161
|
+
expected_result = {
|
162
|
+
:filename => filepath,
|
163
|
+
:lineno => 7,
|
164
|
+
:method => 'send_action',
|
165
|
+
:code => 'foo7',
|
166
|
+
:context => {
|
167
|
+
:pre => %w(foo3 foo4 foo5 foo6),
|
168
|
+
:post => %w(foo8 foo9 foo10 foo11)
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
expect(subject.to_h).to be_eql(expected_result)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'and frame inside app root' do
|
177
|
+
let(:configuration) do
|
178
|
+
double('configuration',
|
179
|
+
:send_extra_frame_data => :app,
|
180
|
+
:root => '/var/www',
|
181
|
+
:project_gem_paths => [])
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'returns also the context and code data' do
|
185
|
+
expected_result = {
|
186
|
+
:filename => filepath,
|
187
|
+
:lineno => 7,
|
188
|
+
:method => 'send_action',
|
189
|
+
:code => 'foo7',
|
190
|
+
:context => {
|
191
|
+
:pre => %w(foo3 foo4 foo5 foo6),
|
192
|
+
:post => %w(foo8 foo9 foo10 foo11)
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
expect(subject.to_h).to be_eql(expected_result)
|
197
|
+
end
|
198
|
+
|
199
|
+
context 'but inside Gem.path' do
|
200
|
+
let(:configuration) do
|
201
|
+
double('configuration',
|
202
|
+
:send_extra_frame_data => :app,
|
203
|
+
:root => '/var/www/',
|
204
|
+
:project_gem_paths => [])
|
205
|
+
end
|
206
|
+
|
207
|
+
before do
|
208
|
+
allow(Gem).to receive(:path).and_return(['/var/www/rollbar'])
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'just returns also the basic data' do
|
212
|
+
expected_result = {
|
213
|
+
:filename => filepath,
|
214
|
+
:lineno => 7,
|
215
|
+
:method => 'send_action'
|
216
|
+
}
|
217
|
+
|
218
|
+
expect(subject.to_h).to be_eql(expected_result)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context 'having less pre lines than maximum' do
|
223
|
+
let(:frame) do
|
224
|
+
"#{filepath}:3:in `send_action'"
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'returns up to 2 pre lines' do
|
228
|
+
expected_result = {
|
229
|
+
:filename => filepath,
|
230
|
+
:lineno => 3,
|
231
|
+
:method => 'send_action',
|
232
|
+
:code => 'foo3',
|
233
|
+
:context => {
|
234
|
+
:pre => %w(foo1 foo2),
|
235
|
+
:post => %w(foo4 foo5 foo6 foo7)
|
236
|
+
}
|
237
|
+
}
|
238
|
+
|
239
|
+
expect(subject.to_h).to be_eql(expected_result)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
context 'having less post lines than maximum' do
|
244
|
+
let(:frame) do
|
245
|
+
"#{filepath}:11:in `send_action'"
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'returns up to 2 post lines' do
|
249
|
+
expected_result = {
|
250
|
+
:filename => filepath,
|
251
|
+
:lineno => 11,
|
252
|
+
:method => 'send_action',
|
253
|
+
:code => 'foo11',
|
254
|
+
:context => {
|
255
|
+
:pre => %w(foo7 foo8 foo9 foo10),
|
256
|
+
:post => %w(foo12 foo13)
|
257
|
+
}
|
258
|
+
}
|
259
|
+
|
260
|
+
expect(subject.to_h).to be_eql(expected_result)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
data/spec/rollbar/item_spec.rb
CHANGED
@@ -646,11 +646,36 @@ describe Rollbar::Item do
|
|
646
646
|
end
|
647
647
|
|
648
648
|
it 'calls Notifier#send_failsafe and logs the error' do
|
649
|
-
|
650
|
-
|
649
|
+
original_size = Rollbar::JSON.dump(payload).bytesize
|
650
|
+
final_size = Rollbar::Truncation.truncate(payload.clone).bytesize
|
651
|
+
# final_size = original_size
|
652
|
+
rollbar_message = "Could not send payload due to it being too large after truncating attempts. Original size: #{original_size} Final size: #{final_size}"
|
653
|
+
uuid = payload['data']['uuid']
|
654
|
+
host = payload['data']['server']['host']
|
655
|
+
log_message = "[Rollbar] Payload too large to be sent for UUID #{uuid}: #{Rollbar::JSON.dump(payload)}"
|
656
|
+
|
657
|
+
expect(notifier).to receive(:send_failsafe).with(rollbar_message, nil, uuid, host)
|
658
|
+
expect(logger).to receive(:error).with(log_message)
|
651
659
|
|
652
660
|
item.dump
|
653
661
|
end
|
662
|
+
|
663
|
+
context 'with missing server data' do
|
664
|
+
it 'calls Notifier#send_failsafe and logs the error' do
|
665
|
+
payload['data'].delete('server')
|
666
|
+
original_size = Rollbar::JSON.dump(payload).bytesize
|
667
|
+
final_size = Rollbar::Truncation.truncate(payload.clone).bytesize
|
668
|
+
# final_size = original_size
|
669
|
+
rollbar_message = "Could not send payload due to it being too large after truncating attempts. Original size: #{original_size} Final size: #{final_size}"
|
670
|
+
uuid = payload['data']['uuid']
|
671
|
+
log_message = "[Rollbar] Payload too large to be sent for UUID #{uuid}: #{Rollbar::JSON.dump(payload)}"
|
672
|
+
|
673
|
+
expect(notifier).to receive(:send_failsafe).with(rollbar_message, nil, uuid, nil)
|
674
|
+
expect(logger).to receive(:error).with(log_message)
|
675
|
+
|
676
|
+
item.dump
|
677
|
+
end
|
678
|
+
end
|
654
679
|
end
|
655
680
|
end
|
656
681
|
end
|
@@ -107,6 +107,10 @@ END
|
|
107
107
|
before do
|
108
108
|
Object.const_set('SecureHeaders', Module.new)
|
109
109
|
SecureHeaders.const_set('VERSION', '3.0.0')
|
110
|
+
SecureHeaders.const_set('Configuration', Module.new {
|
111
|
+
def self.get
|
112
|
+
end
|
113
|
+
})
|
110
114
|
allow(SecureHeaders).to receive(:content_security_policy_script_nonce) { 'lorem-ipsum-nonce' }
|
111
115
|
end
|
112
116
|
|
@@ -115,13 +119,32 @@ END
|
|
115
119
|
end
|
116
120
|
|
117
121
|
it 'renders the snippet and config in the response with nonce in script tag when SecureHeaders installed' do
|
122
|
+
secure_headers_config = double(:configuration, :current_csp => {})
|
123
|
+
allow(SecureHeaders::Configuration).to receive(:get).and_return(secure_headers_config)
|
118
124
|
res_status, res_headers, response = subject.call(env)
|
125
|
+
|
119
126
|
new_body = response.body.join
|
120
127
|
|
121
128
|
expect(new_body).to include('<script type="text/javascript" nonce="lorem-ipsum-nonce">')
|
122
129
|
expect(new_body).to include("var _rollbarConfig = #{config[:options].to_json};")
|
123
130
|
expect(new_body).to include(snippet)
|
124
131
|
end
|
132
|
+
|
133
|
+
it 'renders the snippet in the response without nonce if SecureHeaders script_src includes \'unsafe-inline\'' do
|
134
|
+
secure_headers_config = double(:configuration, :current_csp => {
|
135
|
+
:script_src => %w('unsafe-inline')
|
136
|
+
})
|
137
|
+
allow(SecureHeaders::Configuration).to receive(:get).and_return(secure_headers_config)
|
138
|
+
|
139
|
+
res_status, res_headers, response = subject.call(env)
|
140
|
+
new_body = response.body.join
|
141
|
+
|
142
|
+
expect(new_body).to include('<script type="text/javascript">')
|
143
|
+
expect(new_body).to include("var _rollbarConfig = #{config[:options].to_json};")
|
144
|
+
expect(new_body).to include(snippet)
|
145
|
+
|
146
|
+
SecureHeaders.send(:remove_const, 'Configuration')
|
147
|
+
end
|
125
148
|
end
|
126
149
|
|
127
150
|
context 'having a html 200 response and SecureHeaders < 3.0.0 defined' do
|
@@ -115,7 +115,7 @@ describe Rollbar::Middleware::Sinatra, :reconfigure_notifier => true do
|
|
115
115
|
get '/foo', params
|
116
116
|
end.to raise_error(exception)
|
117
117
|
|
118
|
-
expect(Rollbar.last_report[:request][:
|
118
|
+
expect(Rollbar.last_report[:request][:GET]).to be_eql(params)
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
@@ -132,7 +132,7 @@ describe Rollbar::Middleware::Sinatra, :reconfigure_notifier => true do
|
|
132
132
|
post '/crash_post', params
|
133
133
|
end.to raise_error(exception)
|
134
134
|
|
135
|
-
expect(Rollbar.last_report[:request][:
|
135
|
+
expect(Rollbar.last_report[:request][:POST]).to be_eql(params)
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
@@ -149,7 +149,7 @@ describe Rollbar::Middleware::Sinatra, :reconfigure_notifier => true do
|
|
149
149
|
post '/crash_post', params.to_json, { 'CONTENT_TYPE' => 'application/json' }
|
150
150
|
end.to raise_error(exception)
|
151
151
|
|
152
|
-
expect(Rollbar.last_report[:request][:
|
152
|
+
expect(Rollbar.last_report[:request][:body]).to be_eql(params.to_json)
|
153
153
|
end
|
154
154
|
|
155
155
|
it 'appears in the sent payload when the accepts header contains json' do
|
@@ -157,16 +157,16 @@ describe Rollbar::Middleware::Sinatra, :reconfigure_notifier => true do
|
|
157
157
|
post '/crash_post', params, { 'ACCEPT' => 'application/vnd.github.v3+json' }
|
158
158
|
end.to raise_error(exception)
|
159
159
|
|
160
|
-
expect(Rollbar.last_report[:request][:
|
160
|
+
expect(Rollbar.last_report[:request][:POST]).to be_eql(params)
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
164
|
-
it 'resets the notifier in every request' do
|
164
|
+
it 'resets the notifier scope in every request' do
|
165
165
|
get '/bar'
|
166
|
-
id1 = Rollbar.
|
166
|
+
id1 = Rollbar.scope_object.object_id
|
167
167
|
|
168
168
|
get '/bar'
|
169
|
-
id2 = Rollbar.
|
169
|
+
id2 = Rollbar.scope_object.object_id
|
170
170
|
|
171
171
|
expect(id1).not_to be_eql(id2)
|
172
172
|
end
|