What is the proper way to evaluate a string and get a stack trace that honors the provided file: script.exs environment across all the code defined in that script regardless of whether it is executed in the current process or deferred to an async task?
The first two samples refer to the provided file: script.exs on the stack trace and the last one loses it.
Sample 1 keeps the reference to script.exs in its stacktrace
iex(1)> Code.eval_string("""
try do
raise "RAISE"
rescue
e -> {e, __STACKTRACE__}
end
""", [], file: "script.exs")
{{%RuntimeError{message: "RAISE"},
[
{:elixir_eval, :__FILE__, 1, [file: ~c"script.exs", line: 2]},
{:elixir, :eval_external_handler, 3,
[file: ~c"src/elixir.erl", line: 386, error_info: %{module: Exception}]},
...
]}, []}
Sample 2 keeps the reference to script.exs in its stacktrace
iex(2)> Code.eval_string("""
fun = fn -> raise "RAISE" end
try do
fun.()
rescue
e -> {e, __STACKTRACE__}
end
""", [], file: "script.exs")
{{%RuntimeError{message: "RAISE"},
[
{:elixir_eval, :__FILE__, 1, [file: ~c"script.exs", line: 1]},
{:elixir, :eval_external_handler, 3,
[file: ~c"src/elixir.erl", line: 386, error_info: %{module: Exception}]},
...
]}, [fun: #Function<43.81571850/0 in :erl_eval.expr/6>]}
Sample 3 loses the reference to script.exs in its stacktrace
iex(3)> Code.eval_string("""
fun = fn -> raise "RAISE" end
Task.async(fn ->
try do
fun.()
rescue
e -> {e, __STACKTRACE__}
end
end) |> Task.await(:infinity)
""", [], file: "script.exs")
{{%RuntimeError{message: "RAISE"},
[
{:elixir, :eval_external_handler, 3,
[file: ~c"src/elixir.erl", line: 386, error_info: %{module: Exception}]},
{:erl_eval, :do_apply, 7, [file: ~c"erl_eval.erl", line: 919]},
{:erl_eval, :try_clauses, 10, [file: ~c"erl_eval.erl", line: 1233]},
{Task.Supervised, :invoke_mfa, 2,
[file: ~c"lib/task/supervised.ex", line: 101]}
]}, [fun: #Function<43.81571850/0 in :erl_eval.expr/6>]}
Need this to implement scripting with accurate tracing of unhandled exceptions in async code.
Things looking into at the moment:
- Process.info(self(), :current_stacktrace)
- Last call optimisation