Error reports in Erlang - erlang

I've taken the cowboy example code and brooken it.
The code for the default request handler looked like this:
-module(default_handler).
-behaviour(cowboy_http_handler).
-export([init/3, handle/2, terminate/2]).
init({_Any, http}, Req, []) ->
{ok, Req, undefined}.
handle(Req, State) ->
{ok, Req2} = cowboy_http_req:reply(200, [], <<"Hello world!">>, Req),
{ok, Req2, State}.
terminate(_Req, _State) ->
ok.
its straight forward, but I wanted to make return files so I changed it to:
-module(default_handler).
-behaviour(cowboy_http_handler).
-export([init/3, handle/2, terminate/2]).
init({_Any, http}, Req, []) ->
{ok, Req, undefined}.
handle(Req, State) ->
try
{Path, Req1} = cowboy_http_req:path(Req),
{ok, File} = file:read_file(Path),
cowboy_http_req:reply(200, [], File, Req1)
of
{ok, Req2} ->
{ok, Req2, State}
catch
_ ->
{ok, Req3} = cowboy_http_req:reply(200, [], <<"Hello world!">>, Req),
{ok, Req3, State}
end.
terminate(_Req, _State) ->
ok.
The try-catch thing should handle the fact that there might not be a file, but it does not. Why is that?
When I try to fetch a file that is not there I get a large error report in the console, can anyone tell me why?
=ERROR REPORT==== 15-Jun-2012::14:24:54 ===
** Handler default_handler terminating in handle/2
for the reason error:{badmatch,{error,badarg}}
** Options were []
** Handler state was undefined
** Request was [{socket,#Port<0.1515>},
{transport,cowboy_tcp_transport},
{connection,keepalive},
{pid,<0.1175.0>},
{method,'GET'},
{version,{1,1}},
{peer,undefined},
{host,[<<"localhost">>]},
{host_info,undefined},
{raw_host,<<"localhost">>},
{port,8080},
{path,[<<"favicon.ico">>]},
{path_info,undefined},
{raw_path,<<"/favicon.ico">>},
{qs_vals,undefined},
{raw_qs,<<>>},
{bindings,[]},
{headers,
[{'Accept-Charset',<<"ISO-8859-1,utf-8;q=0.7,*;q=0.3">>},
{'Accept-Language',<<"en-US,en;q=0.8">>},
{'Accept-Encoding',<<"gzip,deflate,sdch">>},
{'User-Agent',
<<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/10.10 Chromium/18.0.1025.151 Chrome/18.0.1025.151 Safari/535.19">>},
{'Accept',<<"*/*">>},
{'Connection',<<"keep-alive">>},
{'Host',<<"localhost">>}]},
{p_headers,[{'Connection',[<<"keep-alive">>]}]},
{cookies,undefined},
{meta,[]},
{body_state,waiting},
{buffer,<<>>},
{resp_state,waiting},
{resp_headers,[]},
{resp_body,<<>>},
{onresponse,undefined},
{urldecode,{#Fun<cowboy_http.urldecode.2>,crash}}]
** Stacktrace: [{default_handler,handle,2,
[{file,"src/default_handler.erl"},{line,13}]},
{cowboy_http_protocol,handler_handle,3,
[{file,"src/cowboy_http_protocol.erl"},
{line,298}]}]

probably because of how it evaluates the catch clause, see http://www.erlang.org/doc/reference_manual/expressions.html#try
If an exception occurs during evaluation of Exprs but there is no matching ExceptionPattern of the right Class with a true guard sequence, the exception is passed on as if Exprs had not been enclosed in a try expression.
You need to specify an error class (error, throw or exit) if not looking for the default, which is throw.
try Exprs of
Pattern1 [when GuardSeq1] ->
Body1;
...;
PatternN [when GuardSeqN] ->
BodyN
catch
[Class1:]ExceptionPattern1 [when ExceptionGuardSeq1] ->
ExceptionBody1;
...;
[ClassN:]ExceptionPatternN [when ExceptionGuardSeqN] ->
ExceptionBodyN
a catch-all-errors would be written as
catch
_:_ ->
notice how you specify both class and ExpressionPattern as "don't care".
Hope this helps because I only 'dabbled' in erlang until now. :)

This line:
{Path, Req1} = cowboy_http_req:path(Req),
Actually returns a list of binaries, like [<<"path">>,<<"path2">>] instead of something like "/path/path2" which should be what you're actually looking for.
So, to form the filesystem path:
{Path, Req1} = cowboy_http_req:path(Req),
FsPath = lists:foldl(
fun(PathComponent, Acc) ->
string:join([Acc, erlang:binary_to_list(PathComponent)], "/")
end,
"",
Path
),
{ok, File} = file:read_file(FsPath),
(The badarg error you're getting is because the argument to file:read_file/1 is not a string (a list) but a list of binaries, which is not the expected argument.
And the catch needs a _:_ clause, just like Harald answer states.
Cheers.

Related

Erlang error: no function clause matching io:request

I'm an experienced programmer new to Erlang and I'm stuck on the following:
myread() ->
{_, MyData } = file:read_file( "hands.txt" ),
io:format( "hands-out.txt", "~w", MyData ).
yields, when myread() is invoked from the shell:
** exception error: no function clause matching io:request("hands-out.txt",
{format,"~w", <<"3h 5h 7h 8h 3h 5h 7h 8h q"...>>})
(io.erl, line 556) in function io:o_request/3 (io.erl, line 63)
Any help would be appreciated.
Two things:
"hands-out.txt", "~w" needs to be one string: "hands-out.txt: ~w"
and the data that's replacing the ~w needs to be a list. So:
io:format( "hands-out.txt: ~w", [MyData] ).
See http://erlang.org/doc/man/io.html#format-2
Also, you should pattern match on the status value in the return from file:read_file/1. In your version, an error, which would be returned as {error, Reason} would match here, since you're using _, and you'd print the error reason rather than the file, which might be confusing.
So either make it {ok, MyData } = file:read_file( "hands.txt" ) if you want to crash on read error, or something like the following if you want to handle that case:
myread() ->
case file:read_file( "hands.txt" ) of
{ok, MyData } ->
io:format( "hands-out.txt: ~w", [MyData] );
{error, Error} ->
io:format("Error: ~w~n", [Error])
end.

Is there a way to tell whether a function has a matching clause without calling it in Erlang?

E.g. suppose I have a module named caller, and one of the functions defined therein contains this expression:
Callee:some_function(foo, Bar)
caller could try to catch function_clause, but how would caller know that it comes directly from Callee:some_function as opposed to some other function call (e.g. a call that Callee:some_function itself makes)?
You could catch function_clause errors with try-catch, and check if the stacktrace matches:
-module(foo).
-compile(export_all).
maybe_apply(Mod, Fun, Args) ->
try apply(Mod, Fun, Args)
catch
error:function_clause ->
case erlang:get_stacktrace() of
[{Mod, Fun, Args} | _] ->
{error, function_clause};
[{Mod, Fun, Args, _LineNumber} | _] ->
{error, function_clause};
Stacktrace ->
{error, other_function_clause, Stacktrace}
end
end.
Here is an example that shows how it distinguishes between a function clause error in lists:filter itself, and a function clause in a function called by lists:filter:
> foo:maybe_apply(lists, filter, [x, [1,2,3]]).
{error,function_clause}
> foo:maybe_apply(lists, filter, [fun(x) -> true end, [1,2,3]]).
{error,other_function_clause,
[{erl_eval,'-inside-an-interpreted-fun-',[1],[]},
{erl_eval,expr,3,[]}]}
You can use catch (callee:some_function(foo, Bar)) and analyse the error message if any:
1> catch (lists:filter(5,[1,2,3])).
{'EXIT',{function_clause,[{lists,filter,
[5,[1,2,3]],
[{file,"lists.erl"},{line,1283}]},
{erl_eval,do_apply,6,
[{file,"erl_eval.erl"},{line,661}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
{shell,exprs,7,[{file,"shell.erl"},{line,684}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
{shell,eval_loop,3,
[{file,"shell.erl"},{line,624}]}]}}
2> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4}])).
[3,7]
3> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4,5}])).
{'EXIT',{function_clause,[{erl_eval,'-inside-an-interpreted-fun-',
[{3,4,5}],
[]},
{erl_eval,expr,3,[]}]}}
4>
4> catch(lists:map(fun ({X,Y}) -> X / Y end, [{1,2},{3,0}])).
{'EXIT',{badarith,[{erlang,'/',[3,0],[]},
{lists,map,2,[{file,"lists.erl"},{line,1237}]},
{lists,map,2,[{file,"lists.erl"},{line,1237}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,661}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
{shell,exprs,7,[{file,"shell.erl"},{line,684}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,624}]}]}}
5>
you can recognize the case that you are looking for because it has the form:
{'EXIT',{function_clause,[{callee,some_function,
[foo, Bar],
[{file,"callee.erl"},{line,LineNumber}]}|Stack]}}

Erlang: supervisor:start_child/2 error has me baffled

I'm making slight modifications to Logan/Merritt/Carlson's simple cache, Chapter 6, pp 149-169, Erlang and OTP in Action. So far, no code changes, just renaming the modules.
I start the application:
application:start(gridz).
ok
I insert an item:
gridz_maker:insert(blip, blop).
I get this error:
** exception error: no match of right hand side value
{error,
{function_clause,
[{gridz_edit,init,
[{blop,86400}],
[{file,"src/gridz_edit.erl"},{line,51}]},
{gen_server,init_it,6,
[{file,"gen_server.erl"},{line,304}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]}}
in function gridz_maker:insert/2 (src/gridz_maker.erl, line 15)
Here's the code:
insert(Key, Value) ->
case gridz_store:lookup(Key) of
{ok, Pid} -> gridz_edit:replace(Pid, Value);
{error, _} -> {ok, Pid} = gridz_edit:create(Value), %% line 15
gridz_store:insert(Key, Pid)
end.
I look at line 15:
{error, _} -> {ok, Pid} = gridz_edit:create(Value),
I expect the error because this is a new item. gridz:edit is a gen_server (sc_element in Logan et/al.) Here's the code for create/1:
create(Value) ->
create(Value, ?DEFAULT_LEASE_TIME).
create(Value, LeaseTime) ->
gridz_sup:start_child(Value, LeaseTime).
And here's the code for gridz_sup:start_child/2:
start_child(Value, LeaseTime) ->
supervisor:start_child(?SERVER, [Value, LeaseTime]).
init([]) ->
Grid = {gridz_edit, {gridz_edit, start_link, []},
temporary, brutal_kill, worker, [gridz_edit]},
Children = [Grid],
RestartStrategy = {simple_one_for_one, 0, 1},
{ok, {RestartStrategy, Children}}.
If I execute supervisor:start_child/2 directly, here's what I get:
{error,{function_clause,[{gridz_edit,init,
[{blop,50400}],
[{file,"src/gridz_edit.erl"},{line,51}]},
{gen_server,init_it,6,
[{file,"gen_server.erl"},{line,304}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]}}
Line 51 in gridz_edit is an init function:
init([Value, LeaseTime]) ->
Now = calendar:local_time(),
StartTime = calendar:datetime_to_gregorian_seconds(Now),
{ok,
#state{value = Value,
lease_time = LeaseTime,
start_time = StartTime},
time_left(StartTime, LeaseTime)}.
If I execute it directly, it works:
120> gridz_edit:init([blop, (60 * 60 * 24)]).
{ok,{state,blop,86400,63537666408},86400000}
So now I'm baffled. What am I missing? Why does supervisor:start_child/2 throw an error?
Thanks,
LRP
The error says you are passing in a tuple with 2 members, {blop,86400}, when you seem to be expecting a list of 2 members: [Value, LeaseTime]. In your direct execution, you are also using a list, so it works. You should figure out where the tuple is being created, and create a list instead.

Erl file not compiling due to syntax errors

I am trying to figure out what is wrong with this code, cause it is giving me errors preventing it from compiling properly into a beam file. I do not see what is wrong with the syntax. Is there an IDE which could help me out?
These are the errors:
parallels#parallels-Parallels-Virtual-Platform:/var/backend/ejabberd_modules# erlc -I /var/tmp/ejabberd/src/ mod_stanza_ack.erl
./mod_stanza_ack.erl:97: syntax error before: '.'
./mod_stanza_ack.erl:98: syntax error before: Body
./mod_stanza_ack.erl:16: function route/3 undefined
./mod_stanza_ack.erl:3: Warning: behaviour gen_mod undefined
./mod_stanza_ack.erl:111: Warning: function strip_bom/1 is unused
./mod_stanza_ack.erl:114: Warning: function send_presence/3 is unused
./mod_stanza_ack.erl:120: Warning: function echo/3 is unused
./mod_stanza_ack.erl:123: Warning: function send_message/4 is unused
This is the code:
-module(mod_stanza_ack).
-behavior(gen_server).
-behavior(gen_mod).
-export([start_link/2]).
-export([start/2,
stop/1,
init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3]).
-export([route/3]).
-include("ejabberd.hrl").
-define(PROCNAME, ejabberd_mod_stanza_ack).
-define(BOTNAME, stanza_ack).
start_link(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
start(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
ChildSpec = {Proc,
{?MODULE, start_link, [Host, Opts]},
temporary,
1000,
worker,
[?MODULE]},
supervisor:start_child(ejabberd_sup, ChildSpec).
stop(Host) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:call(Proc, stop),
supervisor:terminate_child(ejabberd_sup, Proc),
supervisor:delete_child(ejabberd_sup, Proc).
init([Host, Opts]) ->
?DEBUG("ECHO_BOT: Starting echo_bot", []),
% add a new virtual host / subdomain "echo".example.com
MyHost = gen_mod:get_opt_host(Host, Opts, "echo.#HOST#"),
ejabberd_router:register_route(MyHost, {apply, ?MODULE, route}),
{ok, Host}.
handle_call(stop, _From, Host) ->
{stop, normal, ok, Host}.
handle_cast(_Msg, Host) ->
{noreply, Host}.
handle_info(_Msg, Host) ->
{noreply, Host}.
terminate(_Reason, Host) ->
ejabberd_router:unregister_route(Host),
ok.
code_change(_OldVsn, Host, _Extra) ->
{ok, Host}.
% Checks a presence /subscription/ is a part of this.
% we may want to impliment blacklisting / some kind of
% protection here to prevent malicious users
%route(From, #jid{luser = ?BOTNAME} = To, {xmlelement, "presence", _, _} = Packet) ->
route(From, To, {xmlelement, "presence", _, _} = Packet) ->
case xml:get_tag_attr_s("type", Packet) of
"subscribe" ->
send_presence(To, From, "subscribe");
"subscribed" ->
send_presence(To, From, "subscribed"),
send_presence(To, From, "");
"unsubscribe" ->
send_presence(To, From, "unsubscribed"),
send_presence(To, From, "unsubscribe");
"unsubscribed" ->
send_presence(To, From, "unsubscribed");
"" ->
send_presence(To, From, "");
"unavailable" ->
ok;
"probe" ->
send_presence(To, From, "");
_Other ->
?INFO_MSG("Other kind of presence~n~p", [Packet])
end,
ok;
%route(From, #jid{luser = ?BOTNAME} = To, {xmlelement, "message", _, _} = Packet) ->
route(From, To, {xmlelement, "message", _, _} = Packet) ->
case xml:get_subtag_cdata(Packet, "body") of
"" ->
ok.
Body ->
case xml:get_tag_attr_s("type", Packet) of
"error" ->
?ERROR_MSG("Received error message~n~p -> ~p~n~p", [From, To, Packet]);
_ ->
echo(To, From, strip_bom(Body))
end
end,
ok.
%% HELPER FUNCTIONS
strip_bom([239,187,191|C]) -> C;
strip_bom(C) -> C.
send_presence(From, To, "") ->
ejabberd_router:route(From, To, {xmlelement, "presence", [], []});
send_presence(From, To, TypeStr) ->
ejabberd_router:route(From, To, {xmlelement, "presence", [{"type", TypeStr}], []}).
echo(From, To, Body) ->
send_message(From, To, "chat", Body).
send_message(From, To, TypeStr, BodyStr) ->
XmlBody = {xmlelement, "message",
[{"type", TypeStr},
{"from", jlib:jid_to_string(From)},
{"to", jlib:jid_to_string(To)}],
[{xmlelement, "body", [],
[{xmlcdata, BodyStr}]}]},
ejabberd_router:route(From, To, XmlBody).
./mod_stanza_ack.erl:97: syntax error before: '.' is saying the error is in line 97.
At line 97 change ok. to ok;. This will fix the issue.
Erlide plugin for eclipse is a good IDE to try out.
On line 97 in the function route/3 the first clause of the case is
"" ->
ok.
The . here ends the function which is illegal in the middle of a case, it should be a ;. This also means that the parser assumes that the variable Body on the next line starts a new function which is also illegal as a function name cannot be a variable.
Seeing the function route/3 has not been defined it cannot be exported which is the cause of the undefined function error on line 16.
Sometimes the compiler error messages are a bit cryptic but the line numbers usually help.

How to debug errors in Erlang?

I got one error when starting my gen server, i want to know how to debug it, thanks!
I run "example:add_listener(self(), "127.0.0.1", 10999)." after start_link.
The error is :
=ERROR REPORT==== 11-May-2011::13:41:57 ===
** Generic server <0.37.0> terminating
** Last message in was {'EXIT',<0.35.0>,
{{timeout,
{gen_server,call,
[<0.35.0>,
{add_listener,"127.0.0.1",10999}]}},
[{gen_server,call,2},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}}
** When Server state == {state,example,
{dict,0,16,16,8,80,48,
{[],[],[],[],[],[],[],[],[],[],[],[],[],
[],[],[]},
{{[],[],[],[],[],[],[],[],[],[],[],[],[],
[],[],[]}}},
{dict,0,16,16,8,80,48,
{[],[],[],[],[],[],[],[],[],[],[],[],[],
[],[],[]},
{{[],[],[],[],[],[],[],[],[],[],[],[],[],
[],[],[]}}},
[]}
** Reason for termination ==
** {{timeout,{gen_server,call,[<0.35.0>,{add_listener,"127.0.0.1",10999}]}},
[{gen_server,call,2},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}
** exception exit: {timeout,{gen_server,call,
[<0.35.0>,{add_listener,"127.0.0.1",10999}]}}
in function gen_server:call/2
My code is :
-module(test_ess_tcp).
-export([start_link/0,
add_listener/3,
remove_listener/3]).
-export([init/2, handle_call/3, handle_cast/2, handle_info/2]).
-export([terminate/2, sock_opts/0, new_connection/4]).
-behavior(ess_tcp).
start_link() ->
ess_tcp:start_link(?MODULE, []).
add_listener(Pid, IpAddr, Port) ->
gen_server:call(Pid, {add_listener, IpAddr, Port}).
remove_listener(Pid, IpAddr, Port) ->
gen_server:call(Pid, {remove_listener, IpAddr, Port}).
init([], State) ->
%% Example storing callback module specific state
%% This modifies the server state
{ok, ess_tcp:store_cb_state([], State)}.
handle_call({add_listener, IpAddr, Port}, _From, State) ->
%% Example of getting callback module state
io:format("Not used here, but just an example"),
[] = ess_tcp:get_cb_state(State),
case ess_tcp:add_listen_socket({IpAddr, Port}, State) of
{ok, State1} ->
{reply, ok, State1};
Error ->
{reply, Error, State}
end;
handle_call({remove_listener, IpAddr, Port}, _From, State) ->
case ess_tcp:remove_listen_socket({IpAddr, Port}, State) of
{ok, State1} ->
{reply, ok, State1};
Error ->
{reply, Error, State}
end;
handle_call(_Msg, _From, State) ->
{reply, ignored, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info({tcp, Sock, Data}, State) ->
Me = self(),
P = spawn(fun() -> worker(Me, Sock, Data) end),
gen_tcp:controlling_process(Sock, P),
{noreply, State};
handle_info(_Msg, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
sock_opts() ->
[binary, {active, once}, {packet, 0}].
new_connection(_IpAddr, _Port, Sock, State) ->
Me = self(),
P = spawn(fun() -> worker(Me, Sock) end),
gen_tcp:controlling_process(Sock, P),
{ok, State}.
worker(Owner, Sock) ->
gen_tcp:send(Sock, "Hello\n"),
inet:setopts(Sock, [{active, once}]),
gen_tcp:controlling_process(Sock, Owner).
worker(Owner, Sock, Data) ->
gen_tcp:send(Sock, Data),
inet:setopts(Sock, [{active, once}]),
gen_tcp:controlling_process(Sock, Owner).
Well, your gen_server:call is getting a timeout when called. That means that the gen_server is either taking longer than the default 3 second timeout for a call or it is blocked somewhere.
using tracing to debug kind of behaviour is ideal. For instance if you type this in the shell before running the test:
dbg:tracer(),dbg:p(all,c),dbg:tpl(ess_tcp, x).
you will trace on all functions within ess_tcp to see what is going on in there. For more info about dbg see http://www.erlang.org/doc/man/dbg.html
actually best tool to debug in erlang is io:format statements. Put io:formats where you have doubts and see if you get the expected values.
Regarding above question it is mainly stuck somewhere !!

Resources