Details

    • Patch Submitted:
      Yes
    • Number of attachments :
      1

      Description

      When you use RubyException.printBacktrace to print out an exception, the first line of the backtrace is omitted. See attached patch. I wondered whether this was deliberate, but I struggle to see why one wouldn't want to see the first line.

        Activity

        Hide
        Hiro Asari added a comment -

        It appears to me that the only case where this makes a difference is when we raise an non-NativeException exception while backtrace style is 'mri'.

        As you can see below, the first element of the backtrace is a rather ugly duplicate. So it seems OK for me to skip it. Why this is the case, I have not investigated.

        The short of it, though, is that this appears to be a WONTFIX.

        Here is the comparison for the backtrace:

        1. Reference (MRI 2.0 - trunk 35540)
          $ ruby2.0 -ve 'raise "error"'
          ruby 2.0.0dev (2012-05-05 trunk 35540) [x86_64-darwin11.3.0]
          -e:1:in `<main>': error (RuntimeError)
          
        2. JRuby, indexing starting at 1
          $ jruby -v -e 'raise "error"'
          jruby 1.7.0.dev (ruby-1.9.3-p139) (2012-05-04 b0c4eaa) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java]
          RuntimeError: error
            (root) at -e:1
          
        3. JRuby, indexing starting at 1, using the "mri" backtrace style
          $ jruby -Xbacktrace.style=mri -v -e 'raise "error"'
          jruby 1.7.0.dev (ruby-1.9.3-p139) (2012-05-04 b0c4eaa) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java]
          -e:1:in `(root)': error (RuntimeError)
          
        4. JRuby, indexing starting at 0
          $ jruby -v -e 'raise "error"'                      
          jruby 1.7.0.dev (ruby-1.9.3-p139) (2012-05-04 b0c4eaa) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java]
          RuntimeError: error
            (root) at -e:1
          
        5. JRuby, indexing starting at 0, using the "mri" backtrace style
          $ jruby -Xbacktrace.style=mri -v -e 'raise "error"'
          jruby 1.7.0.dev (ruby-1.9.3-p139) (2012-05-04 b0c4eaa) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java]
          -e:1:in `(root)': error (RuntimeError)
          	from -e:1:in `(root)'
          

        I tracked this down to this commit: https://github.com/jruby/jruby/commit/53278235b77a3297d5e7d9cc2642d45edf7a6821

        Show
        Hiro Asari added a comment - It appears to me that the only case where this makes a difference is when we raise an non-NativeException exception while backtrace style is 'mri'. As you can see below, the first element of the backtrace is a rather ugly duplicate. So it seems OK for me to skip it. Why this is the case, I have not investigated. The short of it, though, is that this appears to be a WONTFIX. Here is the comparison for the backtrace: Reference (MRI 2.0 - trunk 35540) $ ruby2.0 -ve 'raise "error"' ruby 2.0.0dev (2012-05-05 trunk 35540) [x86_64-darwin11.3.0] -e:1:in `<main>': error (RuntimeError) JRuby, indexing starting at 1 $ jruby -v -e 'raise "error"' jruby 1.7.0.dev (ruby-1.9.3-p139) (2012-05-04 b0c4eaa) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java] RuntimeError: error (root) at -e:1 JRuby, indexing starting at 1, using the "mri" backtrace style $ jruby -Xbacktrace.style=mri -v -e 'raise "error"' jruby 1.7.0.dev (ruby-1.9.3-p139) (2012-05-04 b0c4eaa) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java] -e:1:in `(root)': error (RuntimeError) JRuby, indexing starting at 0 $ jruby -v -e 'raise "error"' jruby 1.7.0.dev (ruby-1.9.3-p139) (2012-05-04 b0c4eaa) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java] RuntimeError: error (root) at -e:1 JRuby, indexing starting at 0, using the "mri" backtrace style $ jruby -Xbacktrace.style=mri -v -e 'raise "error"' jruby 1.7.0.dev (ruby-1.9.3-p139) (2012-05-04 b0c4eaa) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java] -e:1:in `(root)': error (RuntimeError) from -e:1:in `(root)' I tracked this down to this commit: https://github.com/jruby/jruby/commit/53278235b77a3297d5e7d9cc2642d45edf7a6821
        Hide
        Martin Kleppmann added a comment -

        Ok, thanks Hiro. I was using RubyException.printBacktrace directly (from some Java code that calls into JRuby), and in that situation it was surprising that one line was missing. However, if the method isn't intended to be used that way (i.e. everyone who calls it already adds the first line anyway), then I guess these semantics are ok.

        Show
        Martin Kleppmann added a comment - Ok, thanks Hiro. I was using RubyException.printBacktrace directly (from some Java code that calls into JRuby), and in that situation it was surprising that one line was missing. However, if the method isn't intended to be used that way (i.e. everyone who calls it already adds the first line anyway), then I guess these semantics are ok.
        Hide
        Hiro Asari added a comment -

        Martin,

        Do you have a case where the lost first item causes a problem for you?

        Show
        Hiro Asari added a comment - Martin, Do you have a case where the lost first item causes a problem for you?
        Hide
        Martin Kleppmann added a comment -

        My use case: I have a Ruby class that implements a Java interface. The interface specifies that methods should throw a particular Java exception, but the underlying Ruby code throws a Ruby exception, and I want to preserve the Ruby backtrace information for easier debugging. So I have a wrapper that translates from Ruby exceptions to Java exceptions, like this:

        public interface MyInterface {
            void foo() throws MyException;
        }
        
        class MyException extends Exception {
            private String backtrace;
        
            public MyException(RubyException cause) {
                this.backtrace = ???; // how do I format cause's exception nicely as a string?
            }
        
            public String getBacktrace() {
                return backtrace;
            }
        }
        
        
        # In Ruby:
        
        class MyImplementation
          include Java::MyInterface
        
          def foo
            # do stuff
          rescue => e
            raise Java::MyException.new(e)
          end
        end
        

        I was originally using RubyException.printBacktrace (with a PrintStream based on ByteArrayOutputStream) to generate the string representation of the Ruby backtrace (the ??? place above).

        However, with the first line missing, the backtrace wasn't very useful. So instead I'm now iterating over the backtrace lines returned by RubyException.getBacktrace(), and constructing the string myself. That's actually quite reasonable.

        Show
        Martin Kleppmann added a comment - My use case: I have a Ruby class that implements a Java interface. The interface specifies that methods should throw a particular Java exception, but the underlying Ruby code throws a Ruby exception, and I want to preserve the Ruby backtrace information for easier debugging. So I have a wrapper that translates from Ruby exceptions to Java exceptions, like this: public interface MyInterface { void foo() throws MyException; } class MyException extends Exception { private String backtrace; public MyException(RubyException cause) { this.backtrace = ???; // how do I format cause's exception nicely as a string? } public String getBacktrace() { return backtrace; } } # In Ruby: class MyImplementation include Java::MyInterface def foo # do stuff rescue => e raise Java::MyException.new(e) end end I was originally using RubyException.printBacktrace (with a PrintStream based on ByteArrayOutputStream) to generate the string representation of the Ruby backtrace (the ??? place above). However, with the first line missing, the backtrace wasn't very useful. So instead I'm now iterating over the backtrace lines returned by RubyException.getBacktrace(), and constructing the string myself. That's actually quite reasonable.
        Hide
        Charles Oliver Nutter added a comment -

        Yah, I agree that printBacktrace should print the first line too...it's stupid that it doesn't.

        Hiro's right about the MRI trace behaving a bit differently, but I think fixing printBacktrace would be sufficient for this bug. Looking into it.

        Show
        Charles Oliver Nutter added a comment - Yah, I agree that printBacktrace should print the first line too...it's stupid that it doesn't. Hiro's right about the MRI trace behaving a bit differently, but I think fixing printBacktrace would be sufficient for this bug. Looking into it.
        Hide
        Charles Oliver Nutter added a comment -

        Actually, I think I got my wires crossed a bit.

        The Java exception printStackTrace (from RaiseException) should print all lines, and I believe it does.

        printBacktrace on RubyException is, as Hiro mentions, used for printing the exception in multiple formats where the first line is treated specially. I will add javadoc to that effect and add an alternative method for printing the same thing RaiseException.printStackTrace does.

        Show
        Charles Oliver Nutter added a comment - Actually, I think I got my wires crossed a bit. The Java exception printStackTrace (from RaiseException) should print all lines, and I believe it does. printBacktrace on RubyException is, as Hiro mentions, used for printing the exception in multiple formats where the first line is treated specially. I will add javadoc to that effect and add an alternative method for printing the same thing RaiseException.printStackTrace does.
        Hide
        Charles Oliver Nutter added a comment -
        commit dc6d51663acfa045c6b53f8a56f635357fba287f
        Author: Charles Oliver Nutter <headius@headius.com>
        Date:   Mon May 14 17:00:26 2012 -0500
        
            Fix JRUBY-6642.
            
            RubyException.printBacktrace will now print all lines by default,
            and has a separate form for skipping some number of lines. All
            internal uses that expected the first line to be skipped use the
            second form.
        
        Show
        Charles Oliver Nutter added a comment - commit dc6d51663acfa045c6b53f8a56f635357fba287f Author: Charles Oliver Nutter <headius@headius.com> Date: Mon May 14 17:00:26 2012 -0500 Fix JRUBY-6642. RubyException.printBacktrace will now print all lines by default, and has a separate form for skipping some number of lines. All internal uses that expected the first line to be skipped use the second form.
        Hide
        Martin Kleppmann added a comment -

        Excellent, thank you!

        Show
        Martin Kleppmann added a comment - Excellent, thank you!

          People

          • Assignee:
            Charles Oliver Nutter
            Reporter:
            Martin Kleppmann
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: