Improve default backtraces -------------------------- Key: JRUBY-5504 URL: http://jira.codehaus.org/browse/JRUBY-5504 Project: JRuby Issue Type: Improvement Reporter: Charles Oliver Nutter Assignee: Thomas E Enebo Fix For: JRuby 1.7
I'm interested in improving the default JRuby backtrace. The current backtrace is identical to MRI's, and newer traces like Rubinius's have shown there are nicer ways to render the backtrace. This bug will track ideas on how to improve the backtrace to be more useful and readable for users. To start, here's the backtrace as of JRuby 1.6.0.RC2: {noformat} ~/projects/jruby ➔ jruby -e "1.times { catch(:x) { File.open('build.xml') {|f| 1 / 0} } }" org/jruby/RubyFixnum.java:490:in `op_div': divided by 0 (ZeroDivisionError) from -e:1:in `__file__' from org/jruby/RubyIO.java:1078:in `open' from -e:1:in `__file__' from org/jruby/RubyKernel.java:1191:in `rbCatch' from -e:1:in `__file__' from org/jruby/RubyFixnum.java:252:in `times' from -e:1:in `(root)' {noformat} A few items of note: # The full .java filename plus line number are present for known entry points from Ruby into Java-based core classes. # For core classes, the Java method name is used instead of the bound Ruby name (rbCatch, op_div) # The interesting bits - the file and line number - are scattered back and forth over each line, and especially different for core class calls. Here's the Rubinius trace (and a screenshot to show the color highlighting it does when outputting to a TTY: http://i.min.us/ijfo16.png): {noformat} ~/projects/jruby ➔ rbx -e "1.times { catch(:x) { File.open('build.xml') {|f| 1 / 0} } }" An exception occurred evaluating command line code divided by 0 (ZeroDivisionError) Backtrace: Object#__script__ {} at -e:1 IO.open at kernel/common/io.rb:260 Object#__script__ {} at -e:1 Kernel(Object)#catch {} at kernel/common/throw_catch.rb:34 Rubinius::ThrownValue.register at kernel/common/throw_catch.rb:13 Kernel(Object)#catch at kernel/common/throw_catch.rb:33 Object#__script__ {} at -e:1 Integer(Fixnum)#times at kernel/common/integer.rb:138 Object#__script__ {} at -e:1 Kernel(Rubinius::Loader)#eval at kernel/common/eval.rb:112 Rubinius::Loader#evals at kernel/loader.rb:420 Rubinius::Loader#main at kernel/loader.rb:525 Rubinius::Loader.main at kernel/loader.rb:552 Object#__script__ at kernel/loader.rb:564 {noformat} The key details here: * Top line to indicate an exception occurred and where it happened (unsure what other values there are besides "command line code" * Exception message and type on the second line * Blank line to offset backtrace, followed by "Backtrace:" header Then the backtrace lines themselves: * Color highlighted to emphasize user code but show internal code lines (Note that C++ source lines are *not* shown...only .rb lines) * Module or class the method came from (with included class for modules in parens) starts the line * Script body is shown as "__script__" (similar to JRuby's __file__), with {} showing if it occurred in a block * Centered after the class and method name * file:line comes after centered "at" The centering is obviously the most noticeable characteristic, though the color is immediately apparent on terminals that support it. I believe they check termcap to see if color is possible, which would be difficult for us to do (would require native calls). There are a few down sides: * Very nonstandard...pretty, but everything's in a different place. * More internal code shown than in a standard trace, which adds a visual noise. * Color helps, but color sometimes looks bad on certain terminals (like the really hard-to-read blue on OS X). * Showing module *and* the class into which it was included is convenient * (not shown) Method aliases are shown with alias name and original name The same trace in JRuby, similar but omitting some difficult bits (there's also color, slightly different configuration, not shown): {noformat} ~/projects/jruby ➔ jruby -Xbacktrace.style=rubinius -e "1.times { catch(:x) { File.open('build.xml') {|f| 1 / 0} } }" An exception has occurred: divided by 0 Backtrace: org.jruby.RubyFixnum#op_div at org/jruby/RubyFixnum.java:490 ruby.__dash_e__#__file__ at -e:1 org.jruby.RubyIO#open at org/jruby/RubyIO.java:1078 ruby.__dash_e__#__file__ at -e:1 org.jruby.RubyKernel#rbCatch at org/jruby/RubyKernel.java:1191 ruby.__dash_e__#__file__ at -e:1 org.jruby.RubyFixnum#times at org/jruby/RubyFixnum.java:252 ruby.__dash_e__#(root) at -e:1 {noformat} Note differences: * The class in which a method was defined is not always available, since in compiled code we build the backtrace based on compile-time information (see the ruby.__dash_e__#__file__ lines, indicating the -e script compiled at command line). When interpreted, this information is available, but it's very difficult to show it at compiled code where we no longer track it (for perf reasons). * Core class .java files are shown, but the output is less cumbersome due to the centering * Block-sourced lines are not shown, but could be (the information is available in both interpreted and compiled native backtraces) Here are a couple potential improvements that are acceptable for JRuby 1.6 final. First, with the Ruby names in place of the core class Java names: {noformat} ~/projects/jruby ➔ jruby -e "1.times { catch(:x) { File.open('build.xml') {|f| 1 / 0} } }" org/jruby/RubyFixnum.java:490:in `/': divided by 0 (ZeroDivisionError) from -e:1:in `__file__' from org/jruby/RubyIO.java:1078:in `open' from -e:1:in `__file__' from org/jruby/RubyKernel.java:1191:in `catch' from -e:1:in `__file__' from org/jruby/RubyFixnum.java:252:in `times' from -e:1:in `(root)' {noformat} Since the line numbers are given, the fact that we've lost the real Java method name isn't a big deal. Note that this also only affects core class methods written in Java. A second version, providing both the Ruby name and the Java name in parens after it: {noformat} ~/projects/jruby ➔ jruby -e "1.times { catch(:x) { File.open('build.xml') {|f| 1 / 0} } }" org/jruby/RubyFixnum.java:490:in `/ (op_div)': divided by 0 (ZeroDivisionError) from -e:1:in `__file__' from org/jruby/RubyIO.java:1078:in `open' from -e:1:in `__file__' from org/jruby/RubyKernel.java:1191:in `catch (rbCatch)' from -e:1:in `__file__' from org/jruby/RubyFixnum.java:252:in `times' from -e:1:in `(root)' {noformat} The down side here is how much longer the core class lines are. I'm going to do one of the above two modifications for 1.6 final. Other possible improvements... Most of the Rubinius improvements are possible, with the exception of showing the module(class) (because it can't be known at load/compile time) and alias names (we always show (and only track) real name, not aliased). The color and centering improvements are possible, though color requires a bit more terminal introspection than we have available through normal means. * Remove the Java class entirely and use the Ruby class name for core classes (this also shows Ruby method names): {noformat} ~/projects/jruby ➔ jruby -e "1.times { catch(:x) { File.open('build.xml') {|f| 1 / 0} } }" Fixnum:490:in `/': divided by 0 (ZeroDivisionError) from -e:1:in `__file__' from IO:1078:in `open' from -e:1:in `__file__' from Kernel:1191:in `catch' from -e:1:in `__file__' from Fixnum:252:in `times' from -e:1:in `(root)' {noformat} Advantages: * No .java showing up in trace * Shorter core class backtrace lines Disadvantages: * Uninitiated will not know "IO" means RubyIO.java, "Kernel" means "RubyKernel.java", and so on * Center the trace with method name followed by file:line: {noformat} divided by 0 (ZeroDivisionError) `/' at org/jruby/RubyFixnum.java:490 `__file__' at -e:1 `open' at org/jruby/RubyIO.java:1078 `__file__' at -e:1 `catch' at org/jruby/RubyKernel.java:1191 `__file__' at -e:1 `times' at org/jruby/RubyFixnum.java:252 `(root)' at -e:1 {noformat} Advantages: * Centering * Method name is first Disadvantages: * Line number aligns randomly A variation: Centered with file:line first and method after (which is more important to you?) {noformat} divided by 0 (ZeroDivisionError) org/jruby/RubyFixnum.java:490 in `/' -e:1 in `__file__' org/jruby/RubyIO.java:1078 in `open' -e:1 in `__file__' org/jruby/RubyKernel.java:1191 in `catch' -e:1 in `__file__' org/jruby/RubyFixnum.java:252 in `times' -e:1 in `(root)' {noformat} Another variation with centering also applied to the file:line: {noformat} divided by 0 (ZeroDivisionError) org/jruby/RubyFixnum.java:490 in `/' -e:1 in `__file__' org/jruby/RubyIO.java:1078 in `open' -e:1 in `__file__' org/jruby/RubyKernel.java:1191 in `catch' -e:1 in `__file__' org/jruby/RubyFixnum.java:252 in `times' -e:1 in `(root)' {noformat} Advantages: * Centering x2 (but is it too much?) * Line number easier to find Other ideas? -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.codehaus.org/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email