-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement code hunks support #258
Conversation
spec/fixtures/long_line.rb
Outdated
@@ -0,0 +1 @@ | |||
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Metrics/LineLength: Line is too long. [204/90] (https://github.com/bbatsov/ruby-style-guide#80-character-limits)
8384f4a
to
2b25010
Compare
93 => ' begin', | ||
94 => ' json = @payload.to_json', | ||
95 => ' rescue *JSON_EXCEPTIONS => ex', | ||
# rubocop:disable Metrics/LineLength,Lint/InterpolationCheck |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lint/UnneededDisable: Unnecessary disabling of Lint/InterpolationCheck (did you mean Lint/LiteralInCondition?).
2b25010
to
13cbb0a
Compare
spec/backtrace_spec.rb
Outdated
# rubocop:enable Metrics/LineLength,Lint/InterpolationCheck | ||
97 => ' else' | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unexpected token tRCURLY
93 => ' begin', | ||
94 => ' json = @payload.to_json', | ||
95 => ' rescue *JSON_EXCEPTIONS => ex', | ||
# rubocop:disable Metrics/LineLength,Lint/InterpolationCheck |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lint/UnneededDisable: Unnecessary disabling of Lint/InterpolationCheck (did you mean Lint/LiteralInCondition?), Metrics/LineLength.
13cbb0a
to
b6eff5c
Compare
This feature is experimental. I am not documenting it in the README because users shouldn't be using it yet.
b6eff5c
to
1eab0dd
Compare
lib/airbrake-ruby/backtrace.rb
Outdated
return unless code_hunk | ||
|
||
unless code_hunk.key?(0) | ||
frame[:code_hunk] = code_hunk |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rename to just code
for brevity? Anyway in JSON it should be codeHunk
, not code_hunk
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
lib/airbrake-ruby/backtrace.rb
Outdated
code_hunk = Airbrake::CodeHunk.new(frame[:file], frame[:line]).to_h | ||
return unless code_hunk | ||
|
||
unless code_hunk.key?(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see 2 unless
that check for code_hunk
. I also don't understand what code_hunk.key?(0)
does so it would be nice if you refactor this code or make it more obvious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#to_h
returns a hash of int => string
. A file can never have a zero line. I thought the existence of it would mean there's an error.
First unless
is when a file is empty. Second unless
is when there's an error that we need to log.
Does that make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense, but why not to throw an exception like any other Ruby code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be unfortunate to miss a notice just because we couldn't read a line of code. I think simply ignoring that error and moving on would be the best solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't suggest you throw that exception to users. You can catch and log it as usually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
lib/airbrake-ruby/backtrace.rb
Outdated
|
||
logger.error( | ||
"#{LOG_LABEL} error while reading code hunk `#{file}:#{line}'. " \ | ||
"Reason: #{code_hunk[0]}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I don't understand why code_hunk[0]
contains the reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Files can never have line 0.
lib/airbrake-ruby/code_hunk.rb
Outdated
|
||
## | ||
# @return [Integer] how many lines should be read around the base line | ||
INTERVAL = 3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NLINES
would be a better name. Also I suggest to lower this to 2
so we have 2 lines before and 2 lines after.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
spec/code_hunk_spec.rb
Outdated
subject { described_class.new(fixture_path('empty_file.rb'), 1).to_h } | ||
|
||
it { is_expected.to eql({}) } | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For empty file I expect to see {1: ""}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
spec/code_hunk_spec.rb
Outdated
subject { described_class.new(fixture_path('banana.rb'), 1).to_h } | ||
|
||
it { is_expected.to be_nil } | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not to throw an exception (return error)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would it buy us?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK that is how errors are returned in Ruby.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you have examples, I'd look at them. I don't think that's how it works. Either way, it's not a big deal because in real world backtraces would unlikely point to non existing files.
spec/code_hunk_spec.rb
Outdated
end | ||
end | ||
|
||
context "when a file has less lines than a code hunk requests" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice if you follow previous context and say something like less than INTERVAL lines before and after
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
spec/code_hunk_spec.rb
Outdated
end | ||
end | ||
|
||
context "when a line location is in the middle of a file" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this should has enough lines before and after
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
lib/airbrake-ruby/code_hunk.rb
Outdated
@start_line = [line - interval, 1].max | ||
@end_line = line + interval | ||
|
||
@code_hash = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code_hash -> lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
spec/code_hunk_spec.rb
Outdated
99 => ' end', | ||
100 => '', | ||
101 => ' break if truncate == 0', | ||
102 => ' end', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style/TrailingCommaInArguments: Avoid comma after the last parameter of a method call. (https://github.com/bbatsov/ruby-style-guide#no-trailing-params-comma)
Pending discussion in #258 (comment) and #258 (comment) but the rest is fixed. PTAL |
b19be87
to
ed7f03f
Compare
PTAL |
lib/airbrake-ruby/backtrace.rb
Outdated
@@ -188,6 +193,13 @@ def match_frame(regexp, stackframe) | |||
|
|||
Patterns::GENERIC.match(stackframe) | |||
end | |||
|
|||
def read_code_hunk(config, frame) | |||
code_hunk = Airbrake::CodeHunk.new(config, frame[:file], frame[:line]).to_h |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a good reason this method is called to_h
? I see none.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
read
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect CodeHunk
to be shared and code look like this:
def constructor
@code_hunk = Airbrake::CodeHunk.new(config)
def populate_code(frame)
@code = @code_hunk.get(file, line)
if @code
frame[:code] = @code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks ok to me, but the problem is that Backtrace doesn't have a constructor. We use Backtrace.parse
, not Backtrace.new.parse
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No big deal, I can init at the same place.
lib/airbrake-ruby/backtrace.rb
Outdated
function: match[:function] | ||
} | ||
|
||
read_code_hunk(config, frame) if config.code_hunks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is supposed to read something, but it returns nil.
lib/airbrake-ruby/code_hunk.rb
Outdated
|
||
private | ||
|
||
def fetch_code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This actually reads somethings, but it is called fetch and returns nil too.
lib/airbrake-ruby/code_hunk.rb
Outdated
return unless File.exist?(@file) | ||
|
||
begin | ||
fetch_code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I see is that you check lines
, then for some reason call fetch_code
and then check lines
again. It would be much more obvious if code was:
check @lines
set @lines
check @lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, checking lines on line 29 is not needed. It's just prevention of reading the same file twice (for the same results). I removed it for now.
lib/airbrake-ruby/code_hunk.rb
Outdated
return | ||
end | ||
|
||
@lines = { 1 => '' } if @lines.empty? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this is here and not in fetch_code
?
lib/airbrake-ruby/code_hunk.rb
Outdated
|
||
begin | ||
fetch_code | ||
rescue StandardError => ex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an example you asked for.
With this change notifier reads every file in backtrace for every notice which is a bit wasteful. I think we need to add a fixed size cache (say last 100 entries) in separate PR to make situation better. |
ee08390
to
319dc26
Compare
319dc26
to
1ee9384
Compare
I agree. I simplified code. PTAL |
This feature is experimental. I am not documenting it in the README because
users shouldn't be using it yet.