This may be relatively safe in production:
On application startup, call :erlang.trace_pattern({:_, :_, :_}, true, [:call_count]). If code loading is dynamic (i.e. you’re not running as part of a release), also call :erlang.trace_pattern(:on_load, true, [:call_count]).
Then whenever you want to gather call stats for all public functions that have been called at least once:
for {m, _} <- :code.all_loaded(),
{f, a} <- m.module_info(:functions),
{:call_count, c} = :erlang.trace_info({m, f, a}, :call_count),
c > 0,
do: {{m, f, a}, c} # or if you prefer: {"#{inspect(m)}.#{f}/#{a}", c}
If you want to include functions that were never called, just drop the c > 0, line.
Or, for your use-case of finding unused functions in a given application:
app = :my_app
for m <- Application.spec(app)[:modules],
{f, a} <- m.module_info(:functions),
{:call_count, c} = :erlang.trace_info({m, f, a}, :call_count),
c == 0,
do: {{m, f, a}, c} # or if you prefer: {"#{inspect(m)}.#{f}/#{a}", c}
In that case you can also selectively enable call count tracing for only the modules of your application, instead of for all modules in the system.
You can reset the counters with :erlang.trace_pattern({:_, :_, :_}, :restart, [:call_count]) or stop tracing with :erlang.trace_pattern({:_, :_, :_}, false, [:call_count]).






















