Debugging

printing

op()
|> IO.inspect(label: "op", limit: :infinity)
op()
|> dbg()

tracing

:dbg.tracer()
:dbg.p(:all, :c) # :c for call trace
:dbg.tpl(App1Web.PageController, :home, 2, []) # tpl for trace process local
:dbg.stop_clear()

breaking point

IEx.pry starts an interactive IEx session at a specific point during code execution.

  • You can insert IEx.pry() into your code.
  • When execution reaches IEx.pry(), it pauses and drops you into an IEx shell.
  • Inside the pry session, you can inspect local variables, evaluate expressions, and resume execution.

IEx.break!

The iex --dbg pry command line option configures IEx to automatically enter a pry session when a breakpoint is hit or certain errors occur.

iex --dbg pry -S mix

IEx.break! will leads to a pry session when the breakpoint is hit.

IEx.break!(App1Web.PageController, :home, 2)

recon

REmote CONtrol, it can be used in prod env.

defmodule M, do: (def incr(n), do: n + 1)

:recon_trace.calls({M, :incr, :_}, 3)

M.incr(0)

The maching pattern here is {mod, fn, arity}, and it limited to 3 times.

:recon_trace.calls/2 returns 0 if instruction is not successful, this happens when the module is not loaded or the function spec is incorrect.

maching parameters

Only tracing calls where paramters are [1]:

:recon_trace.calls({M, :incr, [{[1], [], []}]}, 3)
M.incr(0)
M.incr(1)

tracing result

:recon_trace.calls({M, :incr, [{[:_], [], [{:return_trace}]}]}, 3)
# or simply:
:recon_trace.calls({M, :incr, :return_trace}, 3)
M.incr(0)
12:24:58.761345 <0.658.0> 'Elixir.M':incr(0)
1
Recon tracer rate limit tripped.

tracing all calls to modules matching a prefix

prefix = "Elixir.App1Web."

:code.all_loaded()
  |> Enum.map(fn {mod, _file} -> mod end)
  |> Enum.filter(&String.starts_with?(Atom.to_string(&1), prefix))
  |> Enum.each(&:recon_trace.calls({&1, :_, :return_trace}, 100))