caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Extracting exception details (Async, Cohttp, Exn)
@ 2013-11-29 14:34 Ollie Frolovs
  2013-12-02  3:45 ` Milan Stanojević
  0 siblings, 1 reply; 4+ messages in thread
From: Ollie Frolovs @ 2013-11-29 14:34 UTC (permalink / raw)
  To: caml users

Hello list!

I’m designing a function to query a web service and i am stuck trying to implement quality error handling/reporting. I have a specific question – how do i extract the “description” field from the Core’s Exn type?

I’ve been experimenting in the top-level and i got stuck. My workflow with step by step explanations is below.


First, i create a request, which i believe does not run just yet because it is “deferred”.

utop # let result = try_with (fun () -> Cohttp_async.Client.get (Uri.of_string "http://127.0.0.2"));;
val result : (Cohttp.Response.t * string Pipe.Reader.t, exn) Result.t Deferred.t = <abstr>

Then, i “Deferred.map" the result at which point the Cohttp/Async library try to connect and (as desired) fail. 
I’m using ident here because i want to see what’s inside the exception, thankfully the pretty-printer for exceptions is quite good.

utop # result >>| ident;;
- : (Cohttp.Response.t * string Pipe.Reader.t, exn) Result.t =  Core.Std.Result.Error                                                            (lib/monitor.ml.Error_                                                        
((exn ("connection attempt timeout" 127.0.0.2:80)) (backtrace (""))
(monitor
(((name try_with) (here ()) (id 553) (has_seen_error true)
 (someone_is_listening true) (kill_index 0))
((name main) (here ()) (id 1) (has_seen_error false)
 (someone_is_listening false) (kill_index 0))))))

So i could have pattern-matched Error x where x has type exn (exception). But how do i extract the exception description which is “connection timeout attempt"? I would like to be able to do something like this

utop # result >>| function Error e -> Error (Exn.description_string e) | Ok x -> Ok (do_some_magic x);;

So at this point my future function would return Result.t, string for Error and something else for Ok. 

I had a look at Core’s documentation for Exn but its to_string returns the whole sexp converted into string so i am stuck :’(

As a side question for someone familiar with Core – why does Exn.to_string return sexp in a string at all, it also has sexp_of_t, so i suppose one could evaluate Sexp.to_string @@ Exn.sexp_of_t e. I am surprised that i do not see a  function to extract the valuable description field from the exception and yet there is this apparent duplication of effort. Or am i talking non-sense?

Kind regards,

Ollie

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Caml-list] Extracting exception details (Async, Cohttp, Exn)
  2013-11-29 14:34 [Caml-list] Extracting exception details (Async, Cohttp, Exn) Ollie Frolovs
@ 2013-12-02  3:45 ` Milan Stanojević
  2013-12-02  8:55   ` Ollie Frolovs
  0 siblings, 1 reply; 4+ messages in thread
From: Milan Stanojević @ 2013-12-02  3:45 UTC (permalink / raw)
  To: Ollie Frolovs; +Cc: caml users

On Fri, Nov 29, 2013 at 9:34 AM, Ollie Frolovs
<ollie.frolovs.2012@my.bristol.ac.uk> wrote:
> Hello list!
>
> I’m designing a function to query a web service and i am stuck trying to implement quality error handling/reporting. I have a specific question – how do i extract the “description” field from the Core’s Exn type?
>

There is no "description" field in Exn type.
The confusion here is that the exception you see is actually a wrapped
async exception. When async catches an exception, it wraps it up in a
different exception with more information for easier debugging.
Its definition is (you can see it at
https://github.com/janestreet/async_core/blob/master/lib/monitor.ml#L55)

module Exn_for_monitor = struct
  type t =
    { exn : exn;
      backtrace : string sexp_list;
      backtrace_history : Backtrace.t sexp_list;
      monitor : monitor;
    }
  with fields, sexp_of
end

exception Error_ of Exn_for_monitor.t with sexp

And that is what you see in your output.
To get the original exception you can use Monitor.extract_exn but that
gives you less information (but it might be ok in your particular
case)

> I’ve been experimenting in the top-level and i got stuck. My workflow with step by step explanations is below.
>
>
> First, i create a request, which i believe does not run just yet because it is “deferred”.
>
> utop # let result = try_with (fun () -> Cohttp_async.Client.get (Uri.of_string "http://127.0.0.2"));;
> val result : (Cohttp.Response.t * string Pipe.Reader.t, exn) Result.t Deferred.t = <abstr>
>
> Then, i “Deferred.map" the result at which point the Cohttp/Async library try to connect and (as desired) fail.

utop has some special support for async but I'm not sure exactly what
it does but I doubt it delays running a function.

In general when you have a function in async that returns a deferred,
you do kick off code that will eventually fill in the deferred that
you got back. It is not the case that only when you use that deferred
something happens. Just wanted to point this out to avoid
misconceptions about async.


> I had a look at Core’s documentation for Exn but its to_string returns the whole sexp converted into string so i am stuck :’(
>
> As a side question for someone familiar with Core – why does Exn.to_string return sexp in a string at all, it also has sexp_of_t, so i suppose one could evaluate Sexp.to_string @@ Exn.sexp_of_t e. I am surprised that i do not see a  function to extract the valuable description field from the exception and yet there is this apparent duplication of effort. Or am i talking non-sense?
>

As I said before, this is an issue with async wrapping the original
exception with some more data and then raising the new exception.

Exn.to_string gives you a sexp in a string precisely to avoid
duplication of effort. Otherwise we would need to write to_string and
sexp_of_t for each exception (basically having two preprocessors, one
for to_string and one for sexp). This way you just define your
exception and add "with sexp" and you get all the data in exception
when it's raised.

Hope this helps,
   Milan

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Caml-list] Extracting exception details (Async, Cohttp, Exn)
  2013-12-02  3:45 ` Milan Stanojević
@ 2013-12-02  8:55   ` Ollie Frolovs
  2013-12-02 15:14     ` Milan Stanojević
  0 siblings, 1 reply; 4+ messages in thread
From: Ollie Frolovs @ 2013-12-02  8:55 UTC (permalink / raw)
  To: Milan Stanojević; +Cc: caml users

Thank you for your advice, I’ve written the reply below as I still cannot do what I set out to do.

On 2 Dec 2013, at 03:45, Milan Stanojević <milanst@gmail.com> wrote:

> On Fri, Nov 29, 2013 at 9:34 AM, Ollie Frolovs
> <ollie.frolovs.2012@my.bristol.ac.uk> wrote:
>> Hello list!
>> 
>> I’m designing a function to query a web service and i am stuck trying to implement quality error handling/reporting. I have a specific question – how do i extract the “description” field from the Core’s Exn type?
>> 
> 
> There is no "description" field in Exn type.
Indeed. By saying “description” I tried to communicate my intention, obviously unsuccessfully. In the given example, I would like to extract ("connection attempt timeout" 127.0.0.2:80) in some civil way, preferable as a string so that i can display the error message to the user. In RWO all examples that i have seen so far, just check for Error/None and print “Unexpected failure” to the user (DuckDuckGo example). I want to give more information but not the entire sexp with the backtrace, etc.

utop # result >>| ident;;
- : (Cohttp.Response.t * string Pipe.Reader.t, exn) Result.t =  Core.Std.Result.Error                                                            (lib/monitor.ml.Error_                                                        
((exn ("connection attempt timeout" 127.0.0.2:80)) (backtrace (""))
(monitor
(((name try_with) (here ()) (id 553) (has_seen_error true)
(someone_is_listening true) (kill_index 0))
((name main) (here ()) (id 1) (has_seen_error false)
(someone_is_listening false) (kill_index 0))))))

> The confusion here is that the exception you see is actually a wrapped
> async exception. When async catches an exception, it wraps it up in a
> different exception with more information for easier debugging.
> Its definition is (you can see it at
> https://github.com/janestreet/async_core/blob/master/lib/monitor.ml#L55)
> 
> module Exn_for_monitor = struct
>  type t =
>    { exn : exn;
>      backtrace : string sexp_list;
>      backtrace_history : Backtrace.t sexp_list;
>      monitor : monitor;
>    }
>  with fields, sexp_of
> end
> 
> exception Error_ of Exn_for_monitor.t with sexp
> 
> And that is what you see in your output.
> To get the original exception you can use Monitor.extract_exn but that
> gives you less information (but it might be ok in your particular
> case)
> 
All this makes sense, the question is how do i extract the exception information in a format i described above?

>> I’ve been experimenting in the top-level and i got stuck. My workflow with step by step explanations is below.
>> 
>> 
>> First, i create a request, which i believe does not run just yet because it is “deferred”.
>> 
>> utop # let result = try_with (fun () -> Cohttp_async.Client.get (Uri.of_string "http://127.0.0.2"));;
>> val result : (Cohttp.Response.t * string Pipe.Reader.t, exn) Result.t Deferred.t = <abstr>
>> 
>> Then, i “Deferred.map" the result at which point the Cohttp/Async library try to connect and (as desired) fail.
> 
> utop has some special support for async but I'm not sure exactly what
> it does but I doubt it delays running a function.
Again, that was bad wording on my part. The way I understand it – utop runs Async scheduler and also when necessary, waits for the deferred to become determined and shows the contents of the deferred instead. I don’t have a problem with this – I think i understand this part. 

> 
> In general when you have a function in async that returns a deferred,
> you do kick off code that will eventually fill in the deferred that
> you got back. It is not the case that only when you use that deferred
> something happens. Just wanted to point this out to avoid
> misconceptions about async.
Thanks.
> 
> 
>> I had a look at Core’s documentation for Exn but its to_string returns the whole sexp converted into string so i am stuck :’(
>> 
>> As a side question for someone familiar with Core – why does Exn.to_string return sexp in a string at all, it also has sexp_of_t, so i suppose one could evaluate Sexp.to_string @@ Exn.sexp_of_t e. I am surprised that i do not see a  function to extract the valuable description field from the exception and yet there is this apparent duplication of effort. Or am i talking non-sense?
>> 
> 
> As I said before, this is an issue with async wrapping the original
> exception with some more data and then raising the new exception.
> 
> Exn.to_string gives you a sexp in a string precisely to avoid
> duplication of effort. Otherwise we would need to write to_string and
> sexp_of_t for each exception (basically having two preprocessors, one
> for to_string and one for sexp). This way you just define your
> exception and add "with sexp" and you get all the data in exception
> when it's raised.
> 
OK, i understand this but i still do not know how to extract the information from the exception and display it to the user :’(

— Ollie

> Hope this helps,
>   Milan


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Caml-list] Extracting exception details (Async, Cohttp, Exn)
  2013-12-02  8:55   ` Ollie Frolovs
@ 2013-12-02 15:14     ` Milan Stanojević
  0 siblings, 0 replies; 4+ messages in thread
From: Milan Stanojević @ 2013-12-02 15:14 UTC (permalink / raw)
  To: Ollie Frolovs; +Cc: caml users

> Indeed. By saying “description” I tried to communicate my intention, obviously unsuccessfully. In the given example, I would like to extract ("connection attempt timeout" 127.0.0.2:80) in some civil way, preferable as a string so that i can display the error message to the user. In RWO all examples that i have seen so far, just check for Error/None and print “Unexpected failure” to the user (DuckDuckGo example). I want to give more information but not the entire sexp with the backtrace, etc.
>

As I said, you can use Monitor.extract_exn.

try_with (fun () -> Cohttp_async.Client.get (Uri.of_string "http://127.0.0.2"))
>>= function
| Error exn ->
  let orig_exn = Monitor.extract_exn exn in
  Exn.to_string orig_exn
| Ok _ -> .....

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-12-02 15:15 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-29 14:34 [Caml-list] Extracting exception details (Async, Cohttp, Exn) Ollie Frolovs
2013-12-02  3:45 ` Milan Stanojević
2013-12-02  8:55   ` Ollie Frolovs
2013-12-02 15:14     ` Milan Stanojević

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).