Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create new version of Eval/VoidEval that handles errors #10

Open
SurajGupta opened this issue Apr 11, 2013 · 3 comments
Open

Create new version of Eval/VoidEval that handles errors #10

SurajGupta opened this issue Apr 11, 2013 · 3 comments

Comments

@SurajGupta
Copy link
Collaborator

Would be really nice to get the actual error that R throws instead of "R threw and error". To do that, we have to wrap all of the calls in a try(eval()) call.

see: http://www.rforge.net/Rserve/faq.html#errors

@kent37
Copy link
Contributor

kent37 commented Jul 8, 2014

I have had good results with the alternate form of error handling - catch the RserveException and try to call geterrmessage() and traceback() for more details. geterrmessage() has been very reliable; traceback() not so much but occasionally I do get something. Here is an implementation as extension methods on RConnection - change the logging to suit:

   /// Extension methods for Rserve components
   public static class RserveExtensions
   {
      /// Eval method that catches errors and returns the actual R error.
      /// See http://www.rforge.net/Rserve/faq.html#errors
      ///  According to the Rserve
      /// docs the try() method is more reliable; however this method
      /// sometimes gives us a stack trace which is very helpful.
      public static Sexp TryEval(this RConnection conn, String expr)
      {
         try
         {
            return conn.Eval(expr);
         }
         catch (RserveException ex)
         {
            GetAndThrowRealError(conn, ex);
            return null;   // We won't get here but the compiler doesn't know that.
         }
      }

      /// VoidEval method with error reporting.
      public static void TryVoidEval(this RConnection conn, String expr)
      {
         try
         {
            conn.VoidEval(expr);
         }
         catch (RserveException ex)
         {
            GetAndThrowRealError(conn, ex);
         }
      }

      /// Try to get a real error message and stack trace; if that fails rethrow the original exception.
      private static void GetAndThrowRealError(RConnection conn, RserveException ex)
      {
         // Try to get the error message
         String msg;
         try
         {
            msg = conn.Eval("geterrmessage()").AsString;
         }
         catch
         {
            throw ex;
         }

         if (String.IsNullOrWhiteSpace(msg))
            throw ex;

         // Try to get the stack trace
         // It's possible that geterrmessage() succeeds and traceback() fails.
         // If so just use the error message
         try
         {
            var tracebacks = conn.Eval("traceback()").AsStrings;
            var traceback = String.Join("\r\n", tracebacks);
            Log.TraceError("Rserve error: {0}Traceback: {1}", msg, traceback);
#if DEBUG
            msg = msg + traceback;
#endif
         }
         catch 
         {
            // Log msg only
            Log.TraceError("Rserve error: {0}", msg);
         }

         // Throw with a helpful message
         throw new RserveException(msg);
      }
   }

@SurajGupta
Copy link
Collaborator Author

Rserve recommends the try(eval()) approach which I like because you don't have to go to the server to get the error, it comes back as part of the evaluation. Also, I think RserveException can be thrown for issues unrelated to the user computation (like network issues). So we wouldn't want to go back to the server in those cases. Let me think about this some more. It seems like you have something that works, so we should implement it. Will be in touch...

@kent37
Copy link
Contributor

kent37 commented Jul 9, 2014

Yes, I will try two more round trips to the server; one for geterrmessage()
and one for traceback(). My server is running on the same machine as the
client so the round trips are fast and the error is generally going to end
up displaying in a dialog box so speed is not critical.

One thing I like about my approach is I don't have to modify the client
command.

I am finding that I rarely get tracebacks, not sure why that is.

Kent

On Wed, Jul 9, 2014 at 4:33 PM, Suraj Gupta [email protected]
wrote:

Rserve recommends the try(eval()) approach which I like because you don't
have to go to the server to get the error, it comes back as part of the
evaluation. Also, I think RserveException can be thrown for issues
unrelated to the user computation (like network issues). So we wouldn't
want to go back to the server in those cases. Let me think about this some
more. It seems like you have something that works, so we should implement
it. Will be in touch...


Reply to this email directly or view it on GitHub
#10 (comment)
.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants