airbrake-ruby 2.5.0.rc.2 → 2.5.0.rc.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/airbrake-ruby/backtrace.rb +34 -21
- data/lib/airbrake-ruby/version.rb +1 -1
- data/spec/backtrace_spec.rb +89 -20
- data/spec/code_hunk_spec.rb +10 -10
- data/spec/fixtures/notroot.txt +7 -0
- data/spec/fixtures/{code.rb → project_root/code.rb} +0 -0
- data/spec/fixtures/{empty_file.rb → project_root/empty_file.rb} +0 -0
- data/spec/fixtures/{long_line.txt → project_root/long_line.txt} +0 -0
- data/spec/fixtures/{short_file.rb → project_root/short_file.rb} +0 -0
- data/spec/helpers.rb +4 -0
- metadata +12 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 313672bde1f31342c0fce790b1f6285c9b125b4e
|
4
|
+
data.tar.gz: 505361aa89c2f456b91ae53c76a73b61cb180838
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65b85420d818a1ab8a4149ca642710c316626d7b283a24a2bb78712f8aa731dfd5946f88da6ab674d69037c50390b726fcc183007156189b3d9bb26c3143b2fb
|
7
|
+
data.tar.gz: 8fcbf41b9f55a93ec262525d39d282f08a8dd2b73a4d96f87e084b440d349b8cf4347e3a48181419906af93ee2bda6b3ff34997af5aa62f8065aed4e90777da9
|
@@ -96,6 +96,10 @@ module Airbrake
|
|
96
96
|
EXECJS_SIMPLIFIED = /\A.+ \(.+:\d+:\d+\)\z/
|
97
97
|
end
|
98
98
|
|
99
|
+
##
|
100
|
+
# @return [Integer] how many first frames should include code hunks
|
101
|
+
CODE_FRAME_LIMIT = 10
|
102
|
+
|
99
103
|
##
|
100
104
|
# Parses an exception's backtrace.
|
101
105
|
#
|
@@ -104,22 +108,7 @@ module Airbrake
|
|
104
108
|
# @return [Array<Hash{Symbol=>String,Integer}>] the parsed backtrace
|
105
109
|
def self.parse(config, exception)
|
106
110
|
return [] if exception.backtrace.nil? || exception.backtrace.none?
|
107
|
-
|
108
|
-
regexp = best_regexp_for(exception)
|
109
|
-
|
110
|
-
exception.backtrace.map do |stackframe|
|
111
|
-
frame = match_frame(regexp, stackframe)
|
112
|
-
|
113
|
-
unless frame
|
114
|
-
config.logger.error(
|
115
|
-
"can't parse '#{stackframe}' (please file an issue so we can fix " \
|
116
|
-
"it: https://github.com/airbrake/airbrake-ruby/issues/new)"
|
117
|
-
)
|
118
|
-
frame = { file: nil, line: nil, function: stackframe }
|
119
|
-
end
|
120
|
-
|
121
|
-
stack_frame(config, frame)
|
122
|
-
end
|
111
|
+
parse_backtrace(config, exception)
|
123
112
|
end
|
124
113
|
|
125
114
|
##
|
@@ -176,15 +165,12 @@ module Airbrake
|
|
176
165
|
end
|
177
166
|
# rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
178
167
|
|
179
|
-
def stack_frame(
|
180
|
-
|
168
|
+
def stack_frame(match)
|
169
|
+
{
|
181
170
|
file: match[:file],
|
182
171
|
line: (Integer(match[:line]) if match[:line]),
|
183
172
|
function: match[:function]
|
184
173
|
}
|
185
|
-
|
186
|
-
populate_code(config, frame) if config.code_hunks
|
187
|
-
frame
|
188
174
|
end
|
189
175
|
|
190
176
|
def match_frame(regexp, stackframe)
|
@@ -194,6 +180,33 @@ module Airbrake
|
|
194
180
|
Patterns::GENERIC.match(stackframe)
|
195
181
|
end
|
196
182
|
|
183
|
+
def parse_backtrace(config, exception)
|
184
|
+
regexp = best_regexp_for(exception)
|
185
|
+
|
186
|
+
exception.backtrace.map.with_index do |stackframe, i|
|
187
|
+
unless (match = match_frame(regexp, stackframe))
|
188
|
+
config.logger.error(
|
189
|
+
"can't parse '#{stackframe}' (please file an issue so we can fix " \
|
190
|
+
"it: https://github.com/airbrake/airbrake-ruby/issues/new)"
|
191
|
+
)
|
192
|
+
match = { file: nil, line: nil, function: stackframe }
|
193
|
+
end
|
194
|
+
|
195
|
+
frame = stack_frame(match)
|
196
|
+
next(frame) unless config.code_hunks
|
197
|
+
|
198
|
+
if config.root_directory
|
199
|
+
if frame[:file].start_with?(config.root_directory)
|
200
|
+
populate_code(config, frame)
|
201
|
+
end
|
202
|
+
elsif i < CODE_FRAME_LIMIT
|
203
|
+
populate_code(config, frame)
|
204
|
+
end
|
205
|
+
|
206
|
+
frame
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
197
210
|
def populate_code(config, frame)
|
198
211
|
code = Airbrake::CodeHunk.new(config).get(frame[:file], frame[:line])
|
199
212
|
frame[:code] = code if code
|
data/spec/backtrace_spec.rb
CHANGED
@@ -297,29 +297,98 @@ RSpec.describe Airbrake::Backtrace do
|
|
297
297
|
config
|
298
298
|
end
|
299
299
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
300
|
+
context "and when root_directory is configured" do
|
301
|
+
before { config.root_directory = project_root_path('') }
|
302
|
+
|
303
|
+
let(:parsed_backtrace) do
|
304
|
+
[
|
305
|
+
{
|
306
|
+
file: project_root_path('code.rb'),
|
307
|
+
line: 94,
|
308
|
+
function: 'to_json',
|
309
|
+
code: {
|
310
|
+
92 => ' loop do',
|
311
|
+
93 => ' begin',
|
312
|
+
94 => ' json = @payload.to_json',
|
313
|
+
95 => ' rescue *JSON_EXCEPTIONS => ex',
|
314
|
+
# rubocop:disable Metrics/LineLength,Lint/InterpolationCheck
|
315
|
+
96 => ' @config.logger.debug("#{LOG_LABEL} `notice.to_json` failed: #{ex.class}: #{ex}")',
|
316
|
+
# rubocop:enable Metrics/LineLength,Lint/InterpolationCheck
|
317
|
+
}
|
318
|
+
},
|
319
|
+
{
|
320
|
+
file: fixture_path('notroot.txt'),
|
321
|
+
line: 3,
|
322
|
+
function: 'pineapple'
|
314
323
|
}
|
315
|
-
|
316
|
-
|
324
|
+
]
|
325
|
+
end
|
326
|
+
|
327
|
+
it "attaches code to those frames files of which match root_directory" do
|
328
|
+
ex = RuntimeError.new
|
329
|
+
backtrace = [
|
330
|
+
project_root_path('code.rb') + ":94:in `to_json'",
|
331
|
+
fixture_path('notroot.txt' + ":3:in `pineapple'")
|
332
|
+
]
|
333
|
+
ex.set_backtrace(backtrace)
|
334
|
+
expect(described_class.parse(config, ex)).to eq(parsed_backtrace)
|
335
|
+
end
|
317
336
|
end
|
318
337
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
338
|
+
context "and when root_directory isn't configured" do
|
339
|
+
before do
|
340
|
+
config.root_directory = nil
|
341
|
+
stub_const('Airbrake::Backtrace::CODE_FRAME_LIMIT', 2)
|
342
|
+
end
|
343
|
+
|
344
|
+
let(:parsed_backtrace) do
|
345
|
+
[
|
346
|
+
{
|
347
|
+
file: project_root_path('code.rb'),
|
348
|
+
line: 94,
|
349
|
+
function: 'to_json',
|
350
|
+
code: {
|
351
|
+
92 => ' loop do',
|
352
|
+
93 => ' begin',
|
353
|
+
94 => ' json = @payload.to_json',
|
354
|
+
95 => ' rescue *JSON_EXCEPTIONS => ex',
|
355
|
+
# rubocop:disable Metrics/LineLength,Lint/InterpolationCheck
|
356
|
+
96 => ' @config.logger.debug("#{LOG_LABEL} `notice.to_json` failed: #{ex.class}: #{ex}")',
|
357
|
+
# rubocop:enable Metrics/LineLength,Lint/InterpolationCheck
|
358
|
+
}
|
359
|
+
},
|
360
|
+
{
|
361
|
+
file: project_root_path('code.rb'),
|
362
|
+
line: 95,
|
363
|
+
function: 'to_json',
|
364
|
+
code: {
|
365
|
+
93 => ' begin',
|
366
|
+
94 => ' json = @payload.to_json',
|
367
|
+
95 => ' rescue *JSON_EXCEPTIONS => ex',
|
368
|
+
# rubocop:disable Metrics/LineLength,Lint/InterpolationCheck
|
369
|
+
96 => ' @config.logger.debug("#{LOG_LABEL} `notice.to_json` failed: #{ex.class}: #{ex}")',
|
370
|
+
# rubocop:enable Metrics/LineLength,Lint/InterpolationCheck
|
371
|
+
97 => ' else'
|
372
|
+
}
|
373
|
+
},
|
374
|
+
{
|
375
|
+
file: project_root_path('code.rb'),
|
376
|
+
line: 96,
|
377
|
+
function: 'to_json'
|
378
|
+
}
|
379
|
+
]
|
380
|
+
end
|
381
|
+
|
382
|
+
it "attaches code to first N frames" do
|
383
|
+
ex = RuntimeError.new
|
384
|
+
backtrace = [
|
385
|
+
project_root_path('code.rb') + ":94:in `to_json'",
|
386
|
+
project_root_path('code.rb') + ":95:in `to_json'",
|
387
|
+
project_root_path('code.rb') + ":96:in `to_json'"
|
388
|
+
]
|
389
|
+
ex.set_backtrace(backtrace)
|
390
|
+
expect(described_class.parse(config, ex)).to eq(parsed_backtrace)
|
391
|
+
end
|
323
392
|
end
|
324
393
|
end
|
325
394
|
end
|
data/spec/code_hunk_spec.rb
CHANGED
@@ -5,33 +5,33 @@ RSpec.describe Airbrake::CodeHunk do
|
|
5
5
|
|
6
6
|
after do
|
7
7
|
%w[empty_file.rb code.rb banana.rb short_file.rb long_line.txt].each do |f|
|
8
|
-
Airbrake::FileCache[
|
8
|
+
Airbrake::FileCache[project_root_path(f)] = nil
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
describe "#to_h" do
|
13
13
|
context "when file is empty" do
|
14
14
|
subject do
|
15
|
-
described_class.new(config).get(
|
15
|
+
described_class.new(config).get(project_root_path('empty_file.rb'), 1)
|
16
16
|
end
|
17
17
|
|
18
18
|
it { is_expected.to eq(1 => '') }
|
19
19
|
end
|
20
20
|
|
21
21
|
context "when line is nil" do
|
22
|
-
subject { described_class.new(config).get(
|
22
|
+
subject { described_class.new(config).get(project_root_path('code.rb'), nil) }
|
23
23
|
|
24
24
|
it { is_expected.to be_nil }
|
25
25
|
end
|
26
26
|
|
27
27
|
context "when a file doesn't exist" do
|
28
|
-
subject { described_class.new(config).get(
|
28
|
+
subject { described_class.new(config).get(project_root_path('banana.rb'), 1) }
|
29
29
|
|
30
30
|
it { is_expected.to be_nil }
|
31
31
|
end
|
32
32
|
|
33
33
|
context "when a file has less than NLINES lines before start line" do
|
34
|
-
subject { described_class.new(config).get(
|
34
|
+
subject { described_class.new(config).get(project_root_path('code.rb'), 1) }
|
35
35
|
|
36
36
|
it do
|
37
37
|
is_expected.to(
|
@@ -47,7 +47,7 @@ RSpec.describe Airbrake::CodeHunk do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
context "when a file has less than NLINES lines after end line" do
|
50
|
-
subject { described_class.new(config).get(
|
50
|
+
subject { described_class.new(config).get(project_root_path('code.rb'), 222) }
|
51
51
|
|
52
52
|
it do
|
53
53
|
is_expected.to(
|
@@ -61,7 +61,7 @@ RSpec.describe Airbrake::CodeHunk do
|
|
61
61
|
|
62
62
|
context "when a file has less than NLINES lines before and after" do
|
63
63
|
subject do
|
64
|
-
described_class.new(config).get(
|
64
|
+
described_class.new(config).get(project_root_path('short_file.rb'), 2)
|
65
65
|
end
|
66
66
|
|
67
67
|
it do
|
@@ -76,7 +76,7 @@ RSpec.describe Airbrake::CodeHunk do
|
|
76
76
|
end
|
77
77
|
|
78
78
|
context "when a file has enough lines before and after" do
|
79
|
-
subject { described_class.new(config).get(
|
79
|
+
subject { described_class.new(config).get(project_root_path('code.rb'), 100) }
|
80
80
|
|
81
81
|
it do
|
82
82
|
is_expected.to(
|
@@ -93,7 +93,7 @@ RSpec.describe Airbrake::CodeHunk do
|
|
93
93
|
|
94
94
|
context "when a line exceeds the length limit" do
|
95
95
|
subject do
|
96
|
-
described_class.new(config).get(
|
96
|
+
described_class.new(config).get(project_root_path('long_line.txt'), 1)
|
97
97
|
end
|
98
98
|
|
99
99
|
it "strips the line" do
|
@@ -110,7 +110,7 @@ RSpec.describe Airbrake::CodeHunk do
|
|
110
110
|
out = StringIO.new
|
111
111
|
config = Airbrake::Config.new
|
112
112
|
config.logger = Logger.new(out)
|
113
|
-
expect(described_class.new(config).get(
|
113
|
+
expect(described_class.new(config).get(project_root_path('code.rb'), 1)).to(
|
114
114
|
eq(1 => '')
|
115
115
|
)
|
116
116
|
expect(out.string).to match(/can't read code hunk.+Permission denied/)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/spec/helpers.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: airbrake-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.5.0.rc.
|
4
|
+
version: 2.5.0.rc.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Airbrake Technologies, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -80,20 +80,6 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '2'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rubocop
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0.50'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0.50'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: public_suffix
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -166,10 +152,11 @@ files:
|
|
166
152
|
- spec/filters/root_directory_filter_spec.rb
|
167
153
|
- spec/filters/system_exit_filter_spec.rb
|
168
154
|
- spec/filters/thread_filter_spec.rb
|
169
|
-
- spec/fixtures/
|
170
|
-
- spec/fixtures/
|
171
|
-
- spec/fixtures/
|
172
|
-
- spec/fixtures/
|
155
|
+
- spec/fixtures/notroot.txt
|
156
|
+
- spec/fixtures/project_root/code.rb
|
157
|
+
- spec/fixtures/project_root/empty_file.rb
|
158
|
+
- spec/fixtures/project_root/long_line.txt
|
159
|
+
- spec/fixtures/project_root/short_file.rb
|
173
160
|
- spec/helpers.rb
|
174
161
|
- spec/nested_exception_spec.rb
|
175
162
|
- spec/notice_spec.rb
|
@@ -218,10 +205,11 @@ test_files:
|
|
218
205
|
- spec/filters/root_directory_filter_spec.rb
|
219
206
|
- spec/filters/system_exit_filter_spec.rb
|
220
207
|
- spec/filters/thread_filter_spec.rb
|
221
|
-
- spec/fixtures/
|
222
|
-
- spec/fixtures/
|
223
|
-
- spec/fixtures/
|
224
|
-
- spec/fixtures/
|
208
|
+
- spec/fixtures/notroot.txt
|
209
|
+
- spec/fixtures/project_root/code.rb
|
210
|
+
- spec/fixtures/project_root/empty_file.rb
|
211
|
+
- spec/fixtures/project_root/long_line.txt
|
212
|
+
- spec/fixtures/project_root/short_file.rb
|
225
213
|
- spec/helpers.rb
|
226
214
|
- spec/nested_exception_spec.rb
|
227
215
|
- spec/notice_spec.rb
|