How to get Ruby stack trace from script run from Java

I’m running a JRuby script from Java and catching exceptions during its
execution. When I catch the exception I want to log out the Ruby (i.e.
not Java) stack trace for the user.

I have kind of got this working using the following code:

try {

… call JRuby Script

} catch (EvalFailedException je) {
Throwable cause = je.getCause();
if (cause instanceof RaiseException) {
RaiseException re = (RaiseException)cause;
RubyException rbe = re.getException();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
rbe.printBacktrace(ps);
ps.flush();
String stack = baos.toString();
logger.error("Exception in Ruby verticle: " + rbe.message +
“\n” + stack);
return;
}
}

As you can see, the code is pretty ugly, but I can’t find a way to get
the Ruby trace as a string without going through a PrintWriter.

Also the backtrace displayed doesn’t show the line number of the actual
code that threw the exception, it only shows the trace of the lines
leading up to the current line.

I’m sure there must be a simpler way of doing this. Any suggestions
greatly appreciated :slight_smile:

Suggestions below…

On Tue, Feb 14, 2012 at 2:22 PM, Tim F. [email protected] wrote:

} catch (EvalFailedException je) {
Throwable cause = je.getCause();
if (cause instanceof RaiseException) {
RaiseException re = (RaiseException)cause;
RubyException rbe = re.getException();

At this point you should be able to call rbe.backtrace(), which will
usually give you a RubyArray. From there…

IRubyObject bt = rbe.backtrace();
if (bt instanceof List) {
for (String line : (List)bt) printOrWhatever(line);
}

Also the backtrace displayed doesn’t show the line number of the actual code
that threw the exception, it only shows the trace of the lines leading up to
the current line.

Hmm…backtrace() should include everything up to the initiating
line (or as close as possible). Let me know if it does not.

  • Charlie

On 14/02/12 14:34, Charles Oliver N. wrote:

IRubyObject bt = rbe.backtrace();
if (bt instanceof List) {
for (String line : (List)bt) printOrWhatever(line);
}

Thanks, that’s definitely cleaner.

However, sometimes the backtrace reported in this way includes Java
stack stuff, for example, here is a back trace from a ruby exception I
raised from some JRuby code:

 [junit]

/home/tim/projects/vert.x/src/tests/framework/ruby/test_utils.rb:15:in
azzert' [junit] core/http/test_client.rb:163:inhttp_method’
[junit] core/http/test_client.rb:19:in test_get_ssl' [junit] org/jruby/RubyMethod.java:117:incall’
[junit]
/home/tim/projects/vert.x/src/tests/framework/ruby/test_utils.rb:39:in
register_all' [junit] org/jruby/RubyProc.java:268:incall’
[junit] org/jruby/RubyProc.java:232:in `call’

As you can see it’s interleaved with Java stack frames. For my users
they won’t care about the Java stuff. They are programing in Ruby, not
Java, and don’t care about the internal implementation details of the
Ruby runtime. Is there any way of getting a clean Ruby trace without the
Java stuff?

I’m not sure, but I seem to only get the messed up back traces if the
Ruby has been called from a callback set on a Java object.

I can create a test case if you like… (?)

Cheers!