I'm writing a REST service in Erlang and need to verify the received data before passing it to other internal functions for further processing; in order to do that, I'm currently using nested case expressions like this:
case all_args_defined(Args) of
true ->
ActionSuccess = action(Args),
case ActionSuccess of
{ok, _} -> ...;
{fail, reason} -> {fail, reason}
end,
_ ->
{fail, "args not defined"}
end,
...
I realize this is kind of ugly, but this way I can provide detailed error messages. Additionally, I don't think the usual make it crash philosophy is applicable here - I don't want my REST service to crash and be restarted every time somebody throws invalid arguments at it.
However, I'm considering abandoning all those cases in favor of an umbrella try/catch block catching any badmatch errors - would this work?
fun() ->
true = all_args_defined(Args),
{ok, _} = action(Args).
%% somewhere else
catch fun().
Since what you want to achieve is error reporting, you should structure the thing around the execution of actions and reporting of the result. Perhaps something like this:
execute(Action, Args) ->
try
check_args(Args),
Result = action(Action, Args),
send_result(Result)
catch
throw:{fail, Reason} ->
report_error(Reason);
ExceptionClass:Term ->
%% catch-all for all other unexpected exceptions
Trace = erlang:get_stacktrace(),
report_error({crash, ExceptionClass, Term, Trace})
end.
%% all of these throw {fail, Reason} if they detect something fishy
%% and otherwise they return some value as result (or just crash)
action(foo, [X1, X2]) -> ...;
action(foo, Args) -> throw({fail, {bad_arity, foo, 2, Args}});
action(...) -> ...
%% this handles the formatting of all possible errors
report_error({bad_arity, Action, Arity, Args}) ->
send_error(io_lib:format("wrong number of arguments for ~w: "
"expected ~w, but got ~w",
[Action, Arity, length(Args)]));
report_error(...) -> ...;
report_error({crash, Class, Term, Trace}) ->
send_error(io_lib:format("internal error: "
"~w:~w~nstacktrace:~n~p~n",
[Class, Term, Trace])).
I've had this problem while developing an application that create users.
I first come with a solution like this:
insert() ->
try
check_1(), % the check functions throw an exception on error.
check_2(),
check_3(),
do_insert()
catch
throw:Error1 ->
handle_error_1();
throw:Error2 ->
handle_error_2();
_:Error ->
internal_error()
end.
The problem with this solution is that you lose the stack trace with the try...catch block.
Instead of this, a better solution is:
insert() ->
case catch execute() of
ok -> all_ok;
{FuncName, Error} ->
handle_error(FuncName, Error);
{'EXIT', Error} ->
internal_error(Error)
end.
execute() ->
check_1(), % the check functions throw an exception on error.
check_2(),
check_3(),
do_insert().
This way you have the full error stack on Error.
I have faced exactly the same question when writing my own REST services.
Let's start with the philosophy:
I like to think of my applications like a box. On the inside of the box are all of the parts I built and have direct control over. If something breaks here, it's my fault, it should crash, and I should read about it in an error log. On the edge of the box are all of the connection points to the outside world - these are not to be trusted. I avoid exception handling in the inside parts and use it as needed for the outer edge.
On similar projects I have worked on:
I usually have about a dozen checks on the user input. If something looks bad, I log it and return an error to the user. Having a stack trace isn't particularly meaningful to me - if the user forgot a parameter there is nothing in my code to hunt down and fix. I'd rather see a text log that says something like: “at 17:35, user X accessed path Y but was missing parameter Z”.
I organize my checks into functions that return ok or {error, string()}. The main function just iterates over the checks and returns ok if they all pass, otherwise it returns the first error, which is then logged. Inside of my check functions I use exception handling as needed because I can't possibly consider all of the ways users can screw up.
As suggested by my colleagues, you can alternatively have each check throw an exception instead of using a tuple.
As for your implementation, I think your idea of using a single exception handler is a good one if you only have the single check. If you end up needing more checks you may want to implement something like I described so that you can have more specific logging.
Related
I am currently developing geotiff reading and writing functions for octave using .oct files. I went through the octave documentation but could not find much on throwing exceptions. Does that mean I can throw exception the way I do it in C++ by just simply writing throw "error message"?
There are two ways, admittedly they are documented in two utterly separate places, not cross-linked/cross-referenced, which makes no sense, and if you didn't know the function/keyword you wouldn't find them:
error() raises an error, which stops the program. See 12.1 Raising Errors.
error("[%s] Here be wyrms", pkgname)
assert() both tests the condition then raises the error() with a customizable message (so don't do if (cond) ... error(...) ... endif).
See B.1 Test Functions.
% 1. Produce an error if the specified condition is zero (not met).
assert (cond)
assert (cond, errmsg)
assert (cond, errmsg, …)
assert (cond, msg_id, errmsg, …)
% 2a. Produce an error if observed (expression) is not the same as expected (expression); Note that observed and expected can be scalars, vectors, matrices, strings, cell arrays, or structures.
assert (observed, expected)
% 2b. a version that includes a (typically floating-point) tolerance
assert (observed, expected, tol)
See also the command fail()
Yes, you could just use something like
error ("mynewlib: Hello %s world!", "foo");
to signal errors which are catched and viewed.
(Personally I think such questions should really go to the GNU Octave mailing list where you'll find the core developers and octave-forge package maintainers).
I guess you want to build a wrapper around libgeotiff? Have a look at the octave-image package! Where do you host your code?
./examples/code/unwinddemo.cc might also be interesting for you. It shows how to use unwind_protect and define user error handlers.
http://hg.savannah.gnu.org/hgweb/octave/file/3b0a9a832360/examples/code/unwinddemo.cc
Perhaps your function should then be merged into the octave-forge mapping package: "http://sourceforge.net/p/octave/mapping/ci/default/tree/"
I can't get my database access work with lwt. Should I include it in a thread? How? Or make a new thread which returns a 'a lwt value? If so, what to do with that value?
The same goes for Printf.eprintf, which also seems to be blocked by lwt. So I use Lwt_io instead. But why would lwt block regular io?
What I have is a simple db request like Db.update session. It is within an Lwt_main.run main function. All this is within a CGI script (should not matter, database access works fine until I start with the lwt commands).
I can give you more code if needed.
Regards
Olle
Edit
let main sock env =
(* code omitted *)
Gamesession.update_game_session env#db game_session_connected;
(* code omitted *)
Lwt_main.run (main sock_listen env)
Edit 2
This was the solution:
Lwt_preemptive.detach (fun () -> Db.call) ()
Printf.eprintf is not "blocked", it's just that the buffering parameters are changed and often messages do not display before the end of the program. You should try eprintf "something\n%!" (%! means "flush"), but yes it's better to use Lwt_io.
For the database, I don't know, you did not say which library you're using (at least the one called ocaml-mysql is not Lwt-friendly, so it may require using Lwt_preemptive).
Edit
Your:
Lwt_preemptive.detach (fun () -> Db.call) ()
This call creates a thread that, once executed, returns immediately the function Db.call. So, basically in that case Lwt_preemptive.detach does nothing :)
I don't know ocaml-mysql but if:
Db.call: connection_params -> connection_handle
you would have
let lwt_db_call connection_params =
Lwt_preemptive.detach Db.call connection_params
How can I avoid getting an error when passing as argument to the function do-http-request an invalid host.
Is there any way that I can catch the error like the Java's exception-handling mechanism ?
Sure, CL has a very nice condition system. One easy option would be wrapping the call to do-http-request in ignore-errors, which returns nil (and the condition as a second value) if an error condition was signalled in the wrapped code. You could then check for nil afterwards.
If you want something more like exception handling in Java, just use handler-case and add an appropriate error clause (I don't have AllegroServe installed, but I suppose you get a socket-error for providing a wrong URL – just change that part if I misread):
(handler-case
(do-http-request …)
(socket-error ()
…))
If you need finally-like functionality, use unwind-protect:
(unwind-protect
(handler-case
(do-http-request …)
(socket-error (condition) ; bind the signalled condition
…) ; code to run when a socket-error was signalled
(:no-error (value) ; bind the returned value
…)) ; code to run when no condition was signalled
…) ; cleanup code (finally)
You can even get more fancy, and e.g. use handler-bind to handle the condition stack upwards by invoking a restart somewhere down the stack, without unwinding it. For example, if do-http-request provided a restart to try again with another URL, you could handle your error condition by invoking that restart with a new URL to retry. I just mention this for the sake of completeness – it would be overkill for your use case, but being able to resume (possibly expensive) computations easily can be a rather convenient feature.
Please see #7755661 first. I am using ECL and basically want to execute some code, trap any kind of condition that may occur and then continue execution, without prompting or entering the debugger. This is easy to achieve with the following handler-case macro:
(handler-case
(load "code.lisp") ; this may raise a condition
(error (condition)
(print condition))) ; this prints sth like #<a UNBOUND-VARIABLE>
My only problem is that I cannot find a generic way to print a more meaningful error for the user. Indeed my application is an HTTP server and the output goes to a web page. code.lisp is written by the user and it can raise any kind of condition, I do now want to list them all in my code. I would just like to print the same error message I see on the REPL when I do not use handler-case, but in the HTML page, e.g. for an "unbound variable" error, a string like "The variable VAR is unbound".
By inspecting a condition object of type UNBOUND-VARIABLE I see it has two slots: SI:REPORT-FUNCTION, which is a compiled function and SI:NAME, set to the name of the variable in this case. I guess SI:REPORT-FUNCTION could be what I need to invoke but how can I call it? If I try:
(handler-case foo (error (condition) (SI::REPORT-FUNCTION condition)))
it tells me that SI:REPORT-FUNCTION is undefined. SI or SYS in ECL is a package for functions and variables internal to the implementation, but I don't worry if my code is not portable, as long as it works.
BTW in other kinds of condition objects there are also other apparently useful slots for my purpose, named SI:FORMAT-CONTROL and SI:FORMAT-ARGUMENT, but I cannot access any of them from my code too.
I was looking for somethink alike to the getMessage() method of Java exception objects in Lisp, but none of my sources ever mentions something like that.
Moreover, is there any hope to be able to get the line number in code.lisp where the error occurred too? Without that it would be difficult for the user to locate the problem in his code.lisp source file. I would really want to provide this information and stopping at the first error is acceptable for me.
In Common Lisp when print escaping is disabled, the error message is printed.
CL-USER > (handler-case
a
(error (condition)
(write condition :escape nil)))
The variable A is unbound.
#<UNBOUND-VARIABLE 4020059743>
Note that PRINT binds *print-escape* to T.
Using PRINC works - it binds *print-escape* to NIL.
CL-USER > (handler-case
a
(error (condition)
(princ condition)))
The variable A is unbound.
#<UNBOUND-VARIABLE 4020175C0B>
This is described in CLHS 9.1.3 Printing Conditions.
Also note, when you have an object, which has a slot and the value of this slot is a function, then you need to get the slot value using the function SLOT-VALUE and then use FUNCALL or APPLY and call the function with the correct arguments.
If you have a condition of type simple-condition then it has a format-control and a format-argument information. This is described with an example how to use it for FORMAT in CLHS Function SIMPLE-CONDITION-FORMAT-CONTROL, SIMPLE-CONDITION-FORMAT-ARGUMENTS
My answer below is based on one I already gave at the ECL mailing list. Actually I would claim that this is not an embedding problem, but a Lisp one. You want to get some information at the file position of the form which caused the error. This is not attached to a condition because conditions happen independently of whether the form evaluated was interpreted, compiled or part of a function that is already installed in the Lisp image. In other words, it is up to you to know the position of the file which is being read and do some wrapping that adds the information.
The following is nonstandard and prone to change: ECL helps you by defining a variable ext::source-location when LOAD is used on a source file. This variable contains a CONS that should NEVER be changed or stored by the user, but you can get the file as (CAR EXT:*SOURCE-LOCATION*) and the file position as (CDR EXT:*SOURCE-LOCATION*). The plan is then to embed your LOAD form inside a HANDLER-BIND
(defparameter *error-message* nil)
(defparameter *error-tag* (cons))
(defun capture-error (condition)
(setf *error*
(format nil "At character ~S in file ~S an error was found:~%~A"
(cdr ext:*source-location*)
(car ext:*source-location*)
condition)))
(throw *error-tag* *error-message*))
(defun safely-load (file)
(handler-bind ((serious-condition #'capture-error))
(catch *error-tag*
(load file)
nil)))
(SAFELY-LOAD "myfile.lisp") will return either NIL or the formatted error.
In any case I strongly believe that relying on LOAD for this is doomed to fail. You should create your own version of LOAD, starting from this
(defun my-load (userfile)
(with-open-file (stream userfile :direction :input :external-format ....whateverformat...)
(loop for form = (read stream nil nil nil)
while form
do (eval-form-with-error-catching form))))
where EVAL-FORM-.... implements something like the code above. This function can be made more sophisticated and you may keep track of file positions, line numbers, etc. Your code will also be more portable this way.
So please, read the ANSI Spec and learn the language. The fact that you did not know how to print readably a condition and instead tried to play with ECL internals shows that you might face further problems in the future, trying to go with non-portable solutions (hidden slot names, report functions, etc) instead of first trying the standard way.
This is the Exception message thrown by Gen_server when its not started.
(ankit#127.0.0.1)32> R11 = system_warning:self_test("SysWarn").
** exception exit: {noproc,
{gen_server,call,
[system_warning_sup,
{start_child,
{system_warning_SysWarn,
{system_warning,start_link,[{system_warning_SysWarn}]},
permanent,10,worker,
[system_warning]}},
infinity]}}
in function gen_server:call/3
in call from system_warning_sup:'-start_child/1-lc$^0/1-0-'/1
in call from system_warning:self_test/1
(ankit#127.0.0.1)33> R11.
* 1: variable 'R11' is unbound
Now, What I want to do is to catch this exception message & put into variable R11 (showed above as unbound). I want to do so because if gen_sever is not started then I want to start after getting this message. I also tried using handle_info but not able to trap the exception or may be not able to implement it correctly. Can any body please help me with this problem providing some code for example.
Both the answers from #W55tKQbuRu28Q4xv and #Zed are correct but a little terse. :-)
There are two ways to locally catch an error: catchand try. Both will also catch non-local returns generated by throw.
catch is the older and simpler of the two and has the syntax catch Expr. If an error occurs in the expression being evaluated then catch returns {'EXIT',ErrorValue}, otherwise it just returns the value of the expression. One problem with it is that there is no way to see how the error return value has been generated so it can easily be faked in the expression. In the same way you can't see if the return value comes from a throw. N.B. this is not a bug but a feature. Also it is a prefix operator with a low priority so you would normally use it like:
R11 = (catch system_warning:self_test (....))
to avoid confusion. This was a mistake, it should have been catch ... end.
throw is more complex and allows you much greater control over over what to catch and how to handle both the normal returns and error/non-local returns. See the manual for a full description. #Zed's example shows the simplest case which catches everything.
> try
> R11 = system_warning:self_test("SysWarn")
> catch
> Ex:Type -> {Ex,Type,erlang:get_stacktrace()}
> end.
Try to use 'catch':
R11 = catch system_warning:self_test (....)