Issue #6647 has been updated by Charles Nutter.


Here's an implementation in JRuby: https://github.com/jruby/jruby/pull/3937

From the primary commit:

Implement Thread{.,#}report_on_exception[=].

This impl works as follows:

* Default global value is nil.
* nil = report when thread is GC if nobody has captured the
  exception (i.e. called #join or #value or abort_on_exception
  logic has fired).
* true = report when the thread terminates, regardless of capture.
* false = never report.
* New threads inherit the current global setting.
* If a thread name has been set from Ruby, it will be combined
  with JRuby's internal name for the report. If it has not been
  set, we will just report the internal thread name.

There are some open questions for this feature:

* If join/value are interrupted, should they still set the capture
  bit? My impl does not; they must complete.
* Is the VERBOSE-like nil/true/false clear enough or should we use
  symbols like :off, :gc, :on?

----------------------------------------
Feature #6647: Exceptions raised in threads should be logged
https://bugs.ruby-lang.org/issues/6647#change-58876

* Author: Charles Nutter
* Status: Assigned
* Priority: Normal
* Assignee: Yukihiro Matsumoto
----------------------------------------
Many applications and users I have dealt with have run into bugs due to Ruby's behavior of quietly swallowing exceptions raised in threads. I believe this is a bug, and threads should always at least log exceptions that bubble all the way out and terminate them.

The implementation should be simple, but I'm not yet familiar enough with the MRI codebase to provide a patch. The exception logging should be logged in the same way top-level exceptions get logged, but perhaps with information about the thread that was terminated because of the exception.

Here is a monkey patch that simulates what I'm hoping to achieve with this bug:

```ruby
class << Thread
  alias old_new new

  def new(*args, &block)
    old_new(*args) do |*bargs|
      begin
        block.call(*bargs)
      rescue Exception => e
        raise if Thread.abort_on_exception || Thread.current.abort_on_exception
        puts "Thread for block #{block.inspect} terminated with exception: #{e.message}"
        puts e.backtrace.map {|line| "  #{line}"}
      end
    end
  end
end

Thread.new { 1 / 0 }.join
puts "After thread"   
```

Output:

```
system ~/projects/jruby $ ruby thread_error.rb 
Thread for block #<Proc:0x000000010d008a80 / thread_error.rb:17> terminated with exception: divided by 0
  thread_error.rb:17:in `/'
  thread_error.rb:17
  thread_error.rb:7:in `call'
  thread_error.rb:7:in `new'
  thread_error.rb:5:in `initialize'
  thread_error.rb:5:in `old_new'
  thread_error.rb:5:in `new'
  thread_error.rb:17
After thread
```



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>