[Ironruby-core] Handling runtime errors in embedded applications

Tomas Matousek Tomas.Matousek at microsoft.com
Tue Dec 29 03:46:01 EST 2009

ScriptingRuntimeHelpers.GetDynamicStackFrames does not work for IronRuby frames though, only Python is using this technique of stack tracing.


-----Original Message-----
From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of Jimmy Schementi
Sent: Tuesday, December 29, 2009 3:27 AM
To: ironruby-core at rubyforge.org
Subject: Re: [Ironruby-core] Handling runtime errors in embedded applications


To be up-front, your requirements are all possible with IronRuby.

For syntax errors, you're doing the right thing by using ScriptSource.Compile(ErrorListener).

For runtime errors, this gets trickier since all IronRuby runtime errors are also actual CLR exceptions, so you need to depend on the CLR's exception catching mechanisms to detect runtime errors and have your application react accordingly. While using try/catch is one way to simply capture exceptions, as you say, it doesn't cover all cases like catching exceptions from other threads. To solve this, you can hook the CLR's ApplicationUnhandedException event to catch all exceptions from code executing in an AppDomain:
   public static void Main() {
      AppDomain currentDomain = AppDomain.CurrentDomain;
      currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
      try {
         throw new Exception("1");
      } catch (Exception e) {
         Console.WriteLine("Catch clause caught : " + e.Message);
      throw new Exception("2");
      // Output:
      //   Catch clause caught : 1
      //   MyHandler caught : 2
   static void MyHandler(object sender, UnhandledExceptionEventArgs args) {
      Exception e = (Exception) args.ExceptionObject;
      Console.WriteLine("MyHandler caught : " + e.Message);

AppDomain.UnhandedException documentation: http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx.

Now that you have a reliable way of capturing the actual exception object, you need to do something useful with it. Rather than using RubyExceptionData, it's preferred to use the DLR hosting API: "ScriptEngine.GetService<ExceptionOperations>()". This gives you a ExceptionOperations type, which you can use to format an exception as the language defines. 

However, it sounds like you'd rather get a list of stack frames to iterate through, and get information about the frame, rather than just a stacktrace string. You can get the actual dynamic stack frames with ScriptingRuntimeHelpers.GetDynamicStackFrames(exception), which will give you a DynamicStackFrame[] to iterate through, and pull out filenames, line numbers, and method names, without resorting to a regex.

Does that answer all your questions?

From: ironruby-core-bounces at rubyforge.org [ironruby-core-bounces at rubyforge.org] on behalf of James Leskovar [lists at ruby-forum.com]
Sent: Saturday, December 26, 2009 3:12 AM
To: ironruby-core at rubyforge.org
Subject: [Ironruby-core] Handling runtime errors in embedded applications

Hi there,

So my application is basically a lightweight IDE for IronRuby, built in C#, with the idea that users should be able to quickly edit and prototype ruby scripts. Part of the application's requirements is to have the ability to handle compilation/syntax errors and runtime exceptions, as well as the ability to 'jump to' the source of errors.

At the moment, I'm wrapping CreateScriptSourceFromFile, Compile and Execute within a try/catch. Syntax errors are easily handled with a custom ErrorListener passed into ScriptSource.Compile. Handling runtime errors though are a little bit more tricky; the easiest way I've found so far involves RubyExceptionData.GetInstance and a linq expression to parse the backtrace with regexes. Not the most elegant solution, but it works.

However, one area where this method falls flat is when the error occurs in a thread created within the script itself; execution is now outside the try/catch, so I'm not able to catch the Exception object.
Futhermore, nothing seems to happen when the error does occur; nothing gets written to the errorstream, nor is there any indication of any error. It seems like the only way to handle these thread errors is to do it within the script using a begin-rescue block.

My question is, is there an easier way to get runtime error information other than RubyExceptionData? Additionally, what is the best way to handle errors when they occur in a thread other than the one which calls Execute()? It would be handy to be able to set some sort of global 'ErrorListener', or perhaps have the ability to pass in such an object to the call to Execute.

Kind regards,
Posted via http://www.ruby-forum.com/.
Ironruby-core mailing list
Ironruby-core at rubyforge.org

Ironruby-core mailing list
Ironruby-core at rubyforge.org

More information about the Ironruby-core mailing list