Elixir: Correct way of printing __STACKTRACE__ - exception

I know we can get the full stacktrace using __STACKTRACE__ in a catch/rescue block in elixir, but what's the correct way of printing it? In my case, I rescue from an error but I still want to log it to console. This is what I'm doing right now:
def unreliable_method(item) do
# Do something with `item`
:ok
rescue
_err ->
Logger.error("Failed for item: #{inspect(item)}")
Logger.error(inspect(__STACKTRACE__))
{:error, :processing_failed}
end

Just the Stacktrace
This was answered by Michał Muskała on the official elixir github issue:
The canonical way would be to use Exception.format_stacktrace/1
From the docs, it's clear that we don't need to explicitly pass __STACKTRACE__ as an argument to the method when still inside the rescue block. It's automatically retrieved using Process.info:
Logger.error(Exception.format_stacktrace())
Full Error and Stacktrace
Michal's comment helped me find Exception.format/3, that formats the error itself and its complete stacktrace, and that seemed more appropriate for my usecase:
def unreliable_method do
# do something
:ok
rescue
err ->
Logger.error(Exception.format(:error, err, __STACKTRACE__))
{:error, :processing_failed}
end

Related

Phoenix/Elixir/Ejabberd - Response already sent error

I was following this guide for embedding Ejabberd into a Phoenix application (https://blog.process-one.net/embedding-ejabberd-into-an-elixir-phoenix-web-application/) and I'm having an error now that it' running.
Basically, everything appears to work fine until I navigate to "http://localhost:4000/ejabberd" at which point I get the following error:
[error] #PID<0.721.0> running EjbrdTest.Endpoint terminated Server:
localhost:4000 (http) Request: GET /ejabberd
** (exit) an exception was raised:
** (Plug.Conn.AlreadySentError) the response was already sent
(plug) lib/plug/conn.ex:428: Plug.Conn.resp/3
(plug) lib/plug/conn.ex:415: Plug.Conn.send_resp/3
(ejbrdTest) web/controllers/ejabberd_controller.ex:1: EjbrdTest.EjabberdController.phoenix_controller_pipeline/2
(ejbrdTest) lib/phoenix/router.ex:265: EjbrdTest.Router.dispatch/2
(ejbrdTest) web/router.ex:1: EjbrdTest.Router.do_call/2
(ejbrdTest) lib/ejbrdTest/endpoint.ex:1: EjbrdTest.Endpoint.phoenix_pipeline/1
(ejbrdTest) lib/plug/debugger.ex:90: EjbrdTest.Endpoint."call (overridable 3)"/2
(ejbrdTest) lib/phoenix/endpoint/render_errors.ex:34: EjbrdTest.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
And rather than a list of users, I see this in the jumbotron:
Online users: < %= for user <- #users do %> < %= user %>
< % end %>
I've not been able to find anything on this, any ideas?
Thanks. Let me know if you need any more info.
Removing plug :action will fix the issue. Looks like it is called by default now, so that line causes a duplicate error:
https://github.com/phoenixframework/phoenix/issues/888
The blog post had a rendering issue (now fixed). There is no space between < and %.
You can download the actual source code from Gist: https://gist.github.com/mremond/383666d563025e86adfe#file-index-html-eex
In my case, I was piping through an authentication function in my router. That auth function was returning a response but wasn't halting. Once I added a |> halt() to the end of the conn chain, I was good to go.
Just wanted to leave this hear in case I or someone else needs a quick reminder.

Avoiding double render error when rendering a 500 screen from original render exception

In my Application controller, I have this to catch all otherwise uncaught exceptions...
if Rails.env != "test"
rescue_from Exception, :with => :render_500
end
It nicely catches exceptions and calls my "render_500" action, which logs the exception to the database and then renders a custom 500 page that includes a reference GUID for the exception (so I can look up details later).
The problem I'm running into is that if the exception caught occurred while rendering a page (e.g., bad code in a view, undefined variable referenced in a view), I end up triggering a second exception because of a double render error.
Thoughts on how to avoid this double render error on rendering the 500 page?
The way to avoid a double render error by rendering a second time seems to be to check if there already exists a response body...
render unless response_body
Since, if I understand correctly you want the second render to replace the first you might try replacing the existing response_body with your own. Since response_body is an array of strings you could probably use render_to_string then replace the response body like:
def render_500
...stuff...
response = render_to_string "myController/view"
status = 500
unless response_body
render :inline=> response
else
response_body = [response]
end
end
Plus whatever other headers you needed to adjust. This isn't tested and feels a bit unpleasant but I think it should work. I'd be happy to hear if there's a cleaner way.

Python - pythoncom.com_error handling in Python 3.2.2

I am using Python 3.2.2, and building a Tkinter interface to do some Active Directory updating. I am having trouble trying to handle pythoncom.com_error exceptions.
I grabbed some code from here:
http://code.activestate.com/recipes/303345-create-an-account-in-ms-active-directory/
However, I use the following (straight from the above site) handle the exceptions raised:
except pythoncom.com_error,(hr,msg,exc,arg):
This code is consistent with many of the sites I have seen that handle these exceptions, however with Python 3.2.2, I get a syntax error if I include the comma after "pythoncom.com_error". If I remove the comma, the program starts, but then when the exception is raised, I get other exceptions because "hr", "msg" etc are not defined as global variables.
If I remove the comma and all of the bits in the brackets, then it all works well, except I can't see exactly what happens in the exception, which I want so I can pass through the actual error message from AD.
Does anyone know how to handle these pythoncom exceptions properly in Python 3.2.2?
Thanks in advance!
You simply need to use the modern except-as syntax, I think:
import pythoncom
import win32com
import win32com.client
location = 'fred'
try:
ad_obj=win32com.client.GetObject(location)
except pythoncom.com_error as error:
print (error)
print (vars(error))
print (error.args)
hr,msg,exc,arg = error.args
which produces
(-2147221020, 'Invalid syntax', None, None)
{'excepinfo': None, 'hresult': -2147221020, 'strerror': 'Invalid syntax', 'argerror': None}
(-2147221020, 'Invalid syntax', None, None)
for me [although I'm never sure whether the args order is really what it looks like, so I'd probably refer to the keys explicitly; someone else may know for sure.]
I use this structure (Python 3.5) --
try:
...
except Exception as e:
print ("error in level argument", e)
...
else:
...

Erlang error handling philosophy - case vs throw

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.

How to execute something if any exception happens

A python newbie question: I need to do the following
try:
do-something()
except error1:
...
except error2:
...
except:
...
#Here I need to do something if any exception of the above exception was thrown.
I can set a flag and do this. But is there a cleaner way of doing this?
Actually I don't like flags and consider them as the last resort solution. In this case I'd consider something like this:
def f():
try:
do_something()
except E1:
handle_E1()
except E2:
handle_E2()
else:
return
do_stuff_to_be_done_in_case_any_exception_occurred()
Of course, this is only an option if you can return in the else: case.
Another option might be to rethrow the exception and recatch it for a more general handling of errors. This might even be the cleanest approach:
def f():
try: # general error handling
try: # specific error handling
do_something()
except E1:
handle_E1()
raise
except E2:
handle_E2()
raise
except (E1, E2):
do_stuff_to_be_done_in_case_any_exception_occurred()
I just tried a couple different idea's out and it looks like a flag is your best bet.
else suite is only called if there is no exception
finally will always be called
You can do this with a nested try. The except block of the outer try should catch all exceptions. Its body is another try that immediately re-raises the exception. The except blocks of the inner try actually handle the individual exceptions. You can use the finally block in the inner try to do what you want: run something after any exception, but only after an exception.
Here is a little interactive example (modeled on Applesoft BASIC for nostalgia purposes).
try:
input("]") # for Python 3: eval(input("]"))
except:
try:
#Here do something if any exception was thrown.
raise
except SyntaxError:
print "?SYNTAX",
except ValueError:
print "?ILLEGAL QUANTITY",
# additional handlers here
except:
print "?UNKNOWN",
finally:
print "ERROR"
This is the best way I can think of. Looks like a code smell though
try:
exception_flag = True
do-something()
exception_flag = False
except error1:
...
except error2:
...
except:
...
finally:
if exception_flag:
...
You wouldn't need the finally if you are not reraising exceptions in the handler
From the docs: http://docs.python.org/reference/compound_stmts.html#finally
If finally is present, it specifies a ‘cleanup’ handler. The try clause is executed, including any except and else clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception, it is re-raised at the end of the finally clause. If the finally clause raises another exception or executes a return or break statement, the saved exception is lost. The exception information is not available to the program during execution of the finally clause.
It's not clear if you need to handle differently error1, error2 etc. If not, then the following code will do the trick:
try:
do_something()
except (error1, error2, error3), exception_variable:
handle_any_of_these_exceptions()
if you do need to handle different errors differently as well as having the common code, then in the except block, you can have code of the following type:
if isinstance(exception_variable, error1):
do_things_specific_to_error1()
I think this is a more neat solution by using return in the try clause.
If everything works, we will return the value we got in bar(). If we get an exception, we will run the next code, in this case raising another exception.
Demonstrated with a randint.
import random
def foo():
try:
return bar()
except IndexError:
print('Error.')
raise KeyError('Error msg')
def bar():
res = random.randint(0, 2)
if res == 0:
raise IndexError
return res
res = foo()
print(res)