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 3 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 3 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 3 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>'