Does raise with Plug.Exception still generate stack traces?

In a newly generated phoenix project every resource is fetched with a “bang”

def show(conn, %{"id" => resource_id}) do
  resource = Resource.get!(resource_id)
  render(conn, "show.html", resource: resource)

where the Ecto.NoResultsError exception is then dealt with by Plug.Exception or something like that.

What I want to know is whether any other relatively expensive operation gets executed (like getting the stack trace) in the “not found” scenario.

And whether (if it does generate the stack trace) this controller would be any faster when lots of requests to non-existent resources are being made

def show(conn, %{"id" => resource_id}) do
  case Resource.get(resource_id) do
    nil -> render(conn, MyApp.ErrorView, "404.html")
    resource -> render(conn, "show.html", resource: resource)

I guess I can just test it …

It seems like every controller is being called inside a try block? And then __catch__ seems to be calling System.stacktrace?

Is that correct? Does phoenix also use this error handler module? Or only during dev?

Phoenix seems to be using

which does almost the same thing. So the stack trace is still being generated, even though not used (in the case of ecto errors)?

Finally, I wonder if an authorization library based on exceptions would be much slower than something like, because I want to do this

# in controller
def create(conn, %{"resource" => resource_params}, current_user) do
  case Resource.create(resource_params, user: current_user) do
    {:ok, resource} -> redirect(conn, to: resource_path(conn, :show, resource))
    {:error, changeset} -> render(conn, "new.html", changeset: changeset)

# in resource context
def create(params, user: user) do
  # raises an exception that has a Plug.Exception implementation
  authorize!(:create, user) 
  |> Resource.changeset(params)
  |> Repo.insert()

and move auth logic into the context like it’s done in