James Leskovar
2009-Dec-26 11:12 UTC
[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, James -- Posted via http://www.ruby-forum.com/.
Jimmy Schementi
2009-Dec-29 02:27 UTC
[Ironruby-core] Handling runtime errors in embedded applications
James,
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?
~Jimmy
________________________________________
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,
James
--
Posted via http://www.ruby-forum.com/.
_______________________________________________
Ironruby-core mailing list
Ironruby-core at rubyforge.org
http://rubyforge.org/mailman/listinfo/ironruby-core
Tomas Matousek
2009-Dec-29 08:46 UTC
[Ironruby-core] Handling runtime errors in embedded applications
ScriptingRuntimeHelpers.GetDynamicStackFrames does not work for IronRuby frames
though, only Python is using this technique of stack tracing.
Tomas
-----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
James,
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?
~Jimmy
________________________________________
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,
James
--
Posted via http://www.ruby-forum.com/.
_______________________________________________
Ironruby-core mailing list
Ironruby-core at rubyforge.org
http://rubyforge.org/mailman/listinfo/ironruby-core
_______________________________________________
Ironruby-core mailing list
Ironruby-core at rubyforge.org
http://rubyforge.org/mailman/listinfo/ironruby-core
Jimmy Schementi
2009-Dec-29 15:50 UTC
[Ironruby-core] Handling runtime errors in embedded applications
Oh really? Is there any way to get a to the dynamic stack trace info without parsing it yourself? ~Jimmy On Dec 29, 2009, at 12:51 AM, "Tomas Matousek" <Tomas.Matousek at microsoft.com > wrote:> ScriptingRuntimeHelpers.GetDynamicStackFrames does not work for > IronRuby frames though, only Python is using this technique of stack > tracing. > > Tomas > > -----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 > > James, > > 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? > > ~Jimmy > ________________________________________ > 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, > James > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Ironruby-core mailing list > Ironruby-core at rubyforge.org > http://rubyforge.org/mailman/listinfo/ironruby-core > > _______________________________________________ > Ironruby-core mailing list > Ironruby-core at rubyforge.org > http://rubyforge.org/mailman/listinfo/ironruby-core > > _______________________________________________ > Ironruby-core mailing list > Ironruby-core at rubyforge.org > http://rubyforge.org/mailman/listinfo/ironruby-core >
James Leskovar
2009-Dec-30 00:26 UTC
[Ironruby-core] Handling runtime errors in embedded applications
Unfortunantly, the problem with setting the unhandled exception event is
that there''s no way to ''recover'' from the exception;
the application
terminates immediately after the event. Additionally, this method
doesn''t seem to work for exceptions within threads:
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(MyExceptionHandler);
Console.WriteLine("Creating engine");
var engine = Ruby.CreateEngine();
engine.Execute("Thread.start { puts ''raising
exception...''; raise
Exception, ''my exception''; puts ''not
reached''; }");
Console.WriteLine("Done");
Console.ReadKey(true);
}
static void MyExceptionHandler(object sender,
UnhandledExceptionEventArgs e)
{
Console.WriteLine("Caught " +
((Exception)e.ExceptionObject).Message);
}
}
On my box (IronRuby 0.9.2, .NET 3.5sp1), the output is
Creating engine
Done
raising exception...
and then blocks on the call to ReadKey, without ever calling
MyExceptionHandler. Again, the current workaround is to use a
begin-rescue inside the thread proc, which isn''t too terrible. One
possible solution would probably be to reopen Thread.start so that it
wraps the given block with begin-rescue, and then pass the exception
object onto my host object for invoking onerror events.
Jimmy Schementi wrote:> To solve this, you can hook the
> CLR''s ApplicationUnhandedException event to catch all exceptions
from
> code executing in an AppDomain:
--
Posted via http://www.ruby-forum.com/.
Jimmy Schementi
2009-Dec-30 02:46 UTC
[Ironruby-core] Handling runtime errors in embedded applications
UnhandledException *does* have the feature to not terminate the process; you
need to do "e.Handled = true;" in your exception handler to tell the
CLR that the exception has been properly handled. If you don''t set it,
the CLR doesn''t see the exception as handled and continues propagating
the exception, which will eventually terminate the process.
I was pretty sure it worked for Threads as well, since all threads are still
bound to the current AppDomain, but let me know if your fixed exception handler
still doesn''t solve this. However, your work-around will work in the
meantime.
~js
________________________________________
From: ironruby-core-bounces at rubyforge.org [ironruby-core-bounces at
rubyforge.org] on behalf of James Leskovar [lists at ruby-forum.com]
Sent: Tuesday, December 29, 2009 4:26 PM
To: ironruby-core at rubyforge.org
Subject: Re: [Ironruby-core] Handling runtime errors in embedded applications
Unfortunantly, the problem with setting the unhandled exception event is
that there''s no way to ''recover'' from the exception;
the application
terminates immediately after the event. Additionally, this method
doesn''t seem to work for exceptions within threads:
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(MyExceptionHandler);
Console.WriteLine("Creating engine");
var engine = Ruby.CreateEngine();
engine.Execute("Thread.start { puts ''raising
exception...''; raise
Exception, ''my exception''; puts ''not
reached''; }");
Console.WriteLine("Done");
Console.ReadKey(true);
}
static void MyExceptionHandler(object sender,
UnhandledExceptionEventArgs e)
{
Console.WriteLine("Caught " +
((Exception)e.ExceptionObject).Message);
}
}
On my box (IronRuby 0.9.2, .NET 3.5sp1), the output is
Creating engine
Done
raising exception...
and then blocks on the call to ReadKey, without ever calling
MyExceptionHandler. Again, the current workaround is to use a
begin-rescue inside the thread proc, which isn''t too terrible. One
possible solution would probably be to reopen Thread.start so that it
wraps the given block with begin-rescue, and then pass the exception
object onto my host object for invoking onerror events.
Jimmy Schementi wrote:> To solve this, you can hook the
> CLR''s ApplicationUnhandedException event to catch all exceptions
from
> code executing in an AppDomain:
--
Posted via http://www.ruby-forum.com/.
_______________________________________________
Ironruby-core mailing list
Ironruby-core at rubyforge.org
http://rubyforge.org/mailman/listinfo/ironruby-core
James Leskovar
2010-Jan-01 21:52 UTC
[Ironruby-core] Handling runtime errors in embedded applications
Hmm, UnhandledExceptionEventArgs seems to only have two properties, ExceptionObject and IsTerminating, both of which are read-only. After a bit of investigation, there is another type of unhandled-exception handler, set with Application.ThreadException, which can prevent application termination. However, it only catches exceptions in Windows Forms threads, so it''s not applicable for DLR exceptions (indeed, the event is not fired when an IR exception occurs.) James Jimmy Schementi wrote:> UnhandledException *does* have the feature to not terminate the process; > you need to do "e.Handled = true;" in your exception handler to tell the > CLR that the exception has been properly handled. If you don''t set it, > the CLR doesn''t see the exception as handled and continues propagating > the exception, which will eventually terminate the process. > > I was pretty sure it worked for Threads as well, since all threads are > still bound to the current AppDomain, but let me know if your fixed > exception handler still doesn''t solve this. However, your work-around > will work in the meantime. > > ~js-- Posted via http://www.ruby-forum.com/.
Jim Deville
2010-Jan-02 06:02 UTC
[Ironruby-core] Handling runtime errors in embedded applications
Odd.... I''ve used the e.Handled argument before too... JD -----Original Message----- From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of James Leskovar Sent: Friday, January 01, 2010 1:52 PM To: ironruby-core at rubyforge.org Subject: Re: [Ironruby-core] Handling runtime errors in embedded applications Hmm, UnhandledExceptionEventArgs seems to only have two properties, ExceptionObject and IsTerminating, both of which are read-only. After a bit of investigation, there is another type of unhandled-exception handler, set with Application.ThreadException, which can prevent application termination. However, it only catches exceptions in Windows Forms threads, so it''s not applicable for DLR exceptions (indeed, the event is not fired when an IR exception occurs.) James Jimmy Schementi wrote:> UnhandledException *does* have the feature to not terminate the process; > you need to do "e.Handled = true;" in your exception handler to tell the > CLR that the exception has been properly handled. If you don''t set it, > the CLR doesn''t see the exception as handled and continues propagating > the exception, which will eventually terminate the process. > > I was pretty sure it worked for Threads as well, since all threads are > still bound to the current AppDomain, but let me know if your fixed > exception handler still doesn''t solve this. However, your work-around > will work in the meantime. > > ~js-- Posted via http://www.ruby-forum.com/. _______________________________________________ Ironruby-core mailing list Ironruby-core at rubyforge.org http://rubyforge.org/mailman/listinfo/ironruby-core