Packages
mob_dev
0.6.16
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.37
0.3.35
0.3.34
0.3.33
0.3.28
0.3.26
0.3.23
0.3.21
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.18
0.2.17
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
Development tooling for the Mob mobile framework
Current section
Files
Jump to
Current section
Files
lib/mob_dev/otp_trace/collector.ex
defmodule MobDev.OtpTrace.Collector do
@moduledoc false
# GenServer that receives `{:trace, pid, :call, {m, f, a}}` messages
# from `:erlang.trace/3` and accumulates the unique MFAs into a MapSet.
#
# Used by `MobDev.OtpTrace.capture/2`. Excludes a configurable set of
# modules (the trace machinery itself) so we don't poison the result
# with our own bookkeeping.
use GenServer
@spec start_link(MapSet.t(module())) :: {:ok, pid()}
def start_link(exclude_modules) when is_struct(exclude_modules, MapSet) do
GenServer.start_link(__MODULE__, exclude_modules)
end
@spec snapshot(pid()) :: MapSet.t(mfa())
def snapshot(pid), do: GenServer.call(pid, :snapshot, 5_000)
@spec stop(pid()) :: :ok
def stop(pid), do: GenServer.stop(pid)
@impl true
def init(exclude) do
{:ok, %{mfas: MapSet.new(), exclude: exclude}}
end
@impl true
def handle_info({:trace, _pid, :call, {m, f, args_or_arity}}, state) do
# `:erlang.trace/3` reports the call payload as either an integer arity
# (when invoked via apply/3) or a list of actual args (the common case).
# Normalize to arity so the MapSet entry is comparable across calls.
arity = if is_list(args_or_arity), do: length(args_or_arity), else: args_or_arity
state =
if MapSet.member?(state.exclude, m) do
state
else
%{state | mfas: MapSet.put(state.mfas, {m, f, arity})}
end
{:noreply, state}
end
@impl true
def handle_info(_msg, state), do: {:noreply, state}
@impl true
def handle_call(:snapshot, _from, state) do
{:reply, state.mfas, state}
end
end