Feature #14835
closedSupport TracePoint#raised_exception on non-:raise events
Description
TracePoint supports :raise and :return events, and :return event will be invoked when an exception occurs in a method.
But its TracePoint block parameter instance doesn't have any information about raised exceptions.
That means, we can know an exception was raised in a method, but we cannot know an exception was rescued or not there.
def thrower
raise "exception"
end
def caller_without_rescue
thrower
end
tp = TracePoint.trace(:raise, :return) do |tp|
case tp.event
when :raise
p(here: "trace", event: :raise, klass: tp.defined_class, method: tp.method_id, exception: tp.raised_exception)
else
p(here: "trace", event: tp.event, klass: tp.defined_class, method: tp.method_id, value: tp.return_value)
end
end
caller_with_rescue
puts "\n----------------------\n"
begin
caller_without_rescue
rescue => e2
puts "outer rescue: #{e2}"
end
The script above shows these events, but TracePoint events are completely same in these two examples.
# caller_with_rescue
{:here=>"trace", :event=>:raise, :klass=>Object, :method=>:thrower, :exception=>#<RuntimeError: exception>}
{:here=>"trace", :event=>:return, :klass=>Object, :method=>:thrower, :value=>nil}
rescue: exception
{:here=>"trace", :event=>:return, :klass=>Object, :method=>:caller_with_rescue, :value=>nil}
----------------------
# caller_without_rescue
{:here=>"trace", :event=>:raise, :klass=>Object, :method=>:thrower, :exception=>#<RuntimeError: exception>}
{:here=>"trace", :event=>:return, :klass=>Object, :method=>:thrower, :value=>nil}
{:here=>"trace", :event=>:return, :klass=>Object, :method=>:caller_without_rescue, :value=>nil}
outer rescue: exception
My expectation is that TracePoint instance should contain exception instance in raised_exception at the time when it's not rescued.
Updated by jeremyevans0 (Jeremy Evans) over 4 years ago
- Tracker changed from Bug to Feature
- Subject changed from Impossible to know whether an exception was rescued or not using TracePoint to Support TracePoint#raised_exception on non-:raise events
- ruby -v deleted (
ruby 2.6.0preview2 (2018-05-31 trunk 63539) [x86_64-darwin17]) - Backport deleted (
2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN)
I looked into this, and with the current TracePoint design, it does not appear possible. For :raise events, the raised_exception is stored in trace_args->data. This is the same location that the return value is stored for :return, :c_return, and :b_return events. To change this, we would have to modify rb_trace_arg_struct to support additional space for storing the exception in the non-:raise case, and I'm not sure at the point of :return (or :c_return/:b_return) if we can get the exception.
TracePoint#raised_exception is documented to only work for :raise events and not other events. So the current behavior is not a bug. I agree that there may be cases where raised_exception would be useful in other events. So I'm switching to feature request, though I don't know if it is feasible to implement such a feature.
Updated by ko1 (Koichi Sasada) almost 4 years ago
- Status changed from Open to Feedback
Sorry I can't understand the request.
Could you explain more?
Updated by tagomoris (Satoshi Tagomori) almost 4 years ago
We cannot know how "return" events are triggered. It can be triggered by usual returns (return values), and also be triggered by raised exceptions (does not return values).
This also makes it impossible to know where the raised exception was rescued.
If the "return" event contains exceptions (as raised_exception) when it is triggered by raised events, we can distinguish "return" events, by usual returns, or by raised exceptions. That is my request.
Currently, calling raised_exception method on "return" event causes the exception below:
<internal:trace_point>:338:in `raised_exception': not supported by this event (RuntimeError)
from /Users/tagomoris/hoge.rb:20:in `block in <main>'
from /Users/tagomoris/hoge.rb:9:in `caller_with_rescue'
from /Users/tagomoris/hoge.rb:26:in `<main>'