-
Notifications
You must be signed in to change notification settings - Fork 119
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
Filter backtrace before formatting in #handle_exception #916
Conversation
@@ -1222,6 +1222,8 @@ def handle_exception(exc) | |||
irb_bug = true | |||
else | |||
irb_bug = false | |||
backtrace = exc.backtrace.map { |l| @context.workspace.filter_backtrace(l) }.compact | |||
exc.set_backtrace(backtrace) |
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 think IRB should not modify the original exception's backtrace.
How about exc = exc.dup
before set_backtrace?
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.
That's a great point, I'll push up that change
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.
Hmm, this results in some test failures, whether added directly above exc.set_backtrace(backtrace)
or at the very top of the method (before the conditional). I wonder if its because exc.dup
creates a shallow copy?
I will investigate those failures more to see if exc.dup
can work, but if not, should I look for some other way to avoid modifying the original exception's backtrace?
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.
should I look for some other way to avoid modifying the original exception's backtrace?
Yes, please.
One way could be
lines = lines.map { |l| @context.workspace.filter_backtrace(l[/REGEXP_TO_EXTACT_BACKTRACE_PART/]) }.compact
Another way is to modify the backtrace and restore it in ensure statement, but I'd like to avoid doing this if possible.
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.
Sounds good. I appreciate the feedback, I'll explore the options when I have some time.
Should I close this PR and open a new one when I have a solution that doesn't modify the original exception's backtrace? Or should I just push that solution here when it is ready?
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.
Actually, I tried using exc.clone
rather than exc.dup
and that appears to resolve whatever part of the state wasn't getting copied using dup
.
509aff6
to
2c490c1
Compare
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 think it's worth having this small fix to immediately improve Rails users' dev experience.
backtrace = exc.backtrace.map { |l| @context.workspace.filter_backtrace(l) }.compact | ||
exc = exc.clone | ||
exc.set_backtrace(backtrace) |
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 think we can add some comments to make the intention and context clearer:
backtrace = exc.backtrace.map { |l| @context.workspace.filter_backtrace(l) }.compact | |
exc = exc.clone | |
exc.set_backtrace(backtrace) | |
# This is mostly to make IRB work nicely with Rails console's backtrace filtering, which patches WorkSpace#filter_backtrace | |
# In such use case, we want to filter the exception's backtrace before its displayed through Exception#full_message | |
# And we clone the exception object in order to avoid mutating the original exception | |
# TODO: introduce better API to expose exception backtrace externally | |
backtrace = exc.backtrace.map { |l| @context.workspace.filter_backtrace(l) }.compact | |
exc = exc.clone | |
exc.set_backtrace(backtrace) |
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.
Thanks Stan!
What will release for this look like? Will it be patched onto older versions of irb or available on the next release? I have no idea how these things work. I'm wondering when we can mark the rails issue as fixed
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 will be included in the next IRB release (1.13 or 1.12.1). If Rails apps bump their IRB version, they'll be running Rails console with this patch.
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.
Awesome, thanks!
handle_exception now applies the filter_backtrace to exception backtraces prior to formatting the lines with Exception#full_message This fixes a bug in upstream projects, notably Rails, where the backtrace filtering logic expects the lines to be formatted as Exception#backtrace. Co-authored-by: Hartley McGuire <[email protected]>
2c490c1
to
187939f
Compare
Thank you! looks good 👍 |
(ruby/irb#916) handle_exception now applies the filter_backtrace to exception backtraces prior to formatting the lines with Exception#full_message This fixes a bug in upstream projects, notably Rails, where the backtrace filtering logic expects the lines to be formatted as Exception#backtrace. ruby/irb@805ee008f9 Co-authored-by: Hartley McGuire <[email protected]>
(ruby/irb#916) handle_exception now applies the filter_backtrace to exception backtraces prior to formatting the lines with Exception#full_message This fixes a bug in upstream projects, notably Rails, where the backtrace filtering logic expects the lines to be formatted as Exception#backtrace. ruby/irb@805ee008f9 Co-authored-by: Hartley McGuire <[email protected]>
Why is this change needed?
The current implementation of
handle_exception
formats the exception backtrace usingException#full_message
prior to applyingfilter_backtrace
on split lines of thefull_message
. Other projects that use irb intuitively expect that backtrace filtering will act on objects that conform to theException#backtrace
API, and this discrepancy has introduced a bug in Rails where backtraces in the Rails console are entirely silenced (rails/rails#49259)Closes #913
Why this solution?
We considered working around this in Rails, but the backtrace_cleaner class in Rails is not only used for the console; it still needs to work in other contexts where backtrace cleaning is actually being applied to
Exception#backtrace
.This proposed change is the least amount of change to fix the behaviour - the filter now acts on
Exception#backtrace
, but the rest of the logic for formatting and order remains unchanged and relies onException#full_message
. This seems to be a reasonable use case forException#full_message
and avoids needing to rewrite the formatting and ordering logic that is already working.The filtering previously did not apply to irb bugs (it was within
unless irb_bug
), so it was added to the else branch of theirb_bug
conditional to preserve that behaviour.Testing
This branch passes the tests run with
bundle exec rake
. It looks likehandle_exception
is tested by the testseval_input
withintest_context.rb
, which I briefly looked over and the test coverage seems good to me. This is my first contribution to irb, please let me know if there are other testing requirements.With respect to fixing the bug in Rails, here is a screenshot showing the correct/expected backtrace in the Rails console in a fresh Rails test app pointing to the version of irb proposed in this PR.