|
|
@ -27,15 +27,14 @@ trace(Input, TracerMod, TracerOpts) -> |
|
|
|
|
|
|
|
-spec trace(userInput(), module(), tracerOpts(), traceOpts()) -> ok. |
|
|
|
trace(Input, TracerMod, TracerOpts, TraceOpts) when is_list(Input) -> |
|
|
|
do_trace(Input, TracerMod, TracerOpts, TraceOpts); |
|
|
|
trace(Input, TracerMod, TracerOpts, TraceOpts) -> |
|
|
|
trace([Input], TracerMod, TracerOpts, TraceOpts). |
|
|
|
InputList = case is_list(Input) of true -> Input; _ -> [Input] end, |
|
|
|
do_trace(InputList, TracerMod, TracerOpts, TraceOpts). |
|
|
|
|
|
|
|
do_trace(Input0, TracerMod, TracerOpts, TraceOpts) -> |
|
|
|
do_trace(InputList, TracerMod, TracerOpts, TraceOpts) -> |
|
|
|
_ = application:ensure_all_started(eTpf), |
|
|
|
|
|
|
|
%% Start the pool of tracer processes. |
|
|
|
PoolID = maps:get(poolId, TraceOpts, default), |
|
|
|
PoolID = maps:get(poolId, TraceOpts, ?defPoolId), |
|
|
|
PoolSize = maps:get(poolSize, TraceOpts, erlang:system_info(schedulers)), |
|
|
|
true = PoolSize > 0, |
|
|
|
{ok, PoolPid} = supervisor:start_child(eTpf_sup, #{ |
|
|
@ -47,39 +46,39 @@ do_trace(Input0, TracerMod, TracerOpts, TraceOpts) -> |
|
|
|
Tracers = tpTracerPool:tracers(PoolPid), |
|
|
|
TracersMap = maps:from_list(lists:zip(lists:seq(0, length(Tracers) - 1), Tracers)), |
|
|
|
Mode = maps:get(mode, TraceOpts, trace), |
|
|
|
Input1 = flatten(Input0, []), |
|
|
|
Input2 = ensure_pattern(Input1), |
|
|
|
Input = ensure_scope(Input2), |
|
|
|
trace_input(Input, #{mode => Mode, tracers => TracersMap}, TraceOpts), |
|
|
|
Tem0InputList = flattenInput(InputList, []), |
|
|
|
Tem1InputList = ensurePattern(Tem0InputList), |
|
|
|
LastInputList = ensureScope(Tem1InputList), |
|
|
|
traceInput(LastInputList, #{mode => Mode, tracers => TracersMap}, TraceOpts), |
|
|
|
ok. |
|
|
|
|
|
|
|
flatten([], Acc) -> |
|
|
|
flattenInput([], Acc) -> |
|
|
|
lists:flatten(Acc); |
|
|
|
flatten([{callback, Mod, Fun} | Tail], Acc) when is_atom(Mod), is_atom(Fun) -> |
|
|
|
Input = flatten(Mod:Fun(), []), |
|
|
|
flatten(Tail, [Input | Acc]); |
|
|
|
flatten([{app, App} | Tail], Acc) when is_atom(App) -> |
|
|
|
flattenInput([{callback, Mod, Fun} | Tail], Acc) when is_atom(Mod), is_atom(Fun) -> |
|
|
|
Input = flattenInput(Mod:Fun(), []), |
|
|
|
flattenInput(Tail, [Input | Acc]); |
|
|
|
flattenInput([{app, App} | Tail], Acc) when is_atom(App) -> |
|
|
|
_ = application:load(App), |
|
|
|
{ok, Mods} = application:get_key(App, modules), |
|
|
|
flatten(Tail, [Mods | Acc]); |
|
|
|
flatten([Input | Tail], Acc) -> |
|
|
|
flatten(Tail, [Input | Acc]). |
|
|
|
flattenInput(Tail, [Mods | Acc]); |
|
|
|
flattenInput([Input | Tail], Acc) -> |
|
|
|
flattenInput(Tail, [Input | Acc]). |
|
|
|
|
|
|
|
ensure_pattern(Input) -> |
|
|
|
ensurePattern(Input) -> |
|
|
|
case [S || S = {scope, _} <- Input] of |
|
|
|
Input -> ['_' | Input]; |
|
|
|
_ -> Input |
|
|
|
end. |
|
|
|
|
|
|
|
ensure_scope(Input) -> |
|
|
|
ensureScope(Input) -> |
|
|
|
case [S || S = {scope, _} <- Input] of |
|
|
|
[] -> [{scope, [processes]} | Input]; |
|
|
|
_ -> Input |
|
|
|
end. |
|
|
|
|
|
|
|
trace_input([], _, _) -> |
|
|
|
traceInput([], _, _) -> |
|
|
|
ok; |
|
|
|
trace_input([{scope, Scope} | Tail], TracerState, Opts) -> |
|
|
|
traceInput([{scope, Scope} | Tail], TracerState, Opts) -> |
|
|
|
%% We currently enable the following trace flags: |
|
|
|
%% - call: function calls |
|
|
|
%% - procs: process exit events; plus others we ignore |
|
|
@ -96,8 +95,8 @@ trace_input([{scope, Scope} | Tail], TracerState, Opts) -> |
|
|
|
erlang:trace(PidPortSpec, true, [call, procs, timestamp, arity, return_to, set_on_spawn, {tracer, tpTracerNif, TracerState} | ExtraFlags]) |
|
|
|
|| PidPortSpec <- Scope |
|
|
|
], |
|
|
|
trace_input(Tail, TracerState, Opts); |
|
|
|
trace_input([Mod | Tail], TracerState, Opts) when is_atom(Mod) -> |
|
|
|
traceInput(Tail, TracerState, Opts); |
|
|
|
traceInput([Mod | Tail], TracerState, Opts) when is_atom(Mod) -> |
|
|
|
MatchSpec = |
|
|
|
case Opts of |
|
|
|
#{process_dump := true} -> |
|
|
@ -108,10 +107,10 @@ trace_input([Mod | Tail], TracerState, Opts) when is_atom(Mod) -> |
|
|
|
%% The module must be loaded before we attempt to trace it. |
|
|
|
_ = code:ensure_loaded(Mod), |
|
|
|
_ = erlang:trace_pattern({Mod, '_', '_'}, MatchSpec, [local]), |
|
|
|
trace_input(Tail, TracerState, Opts). |
|
|
|
traceInput(Tail, TracerState, Opts). |
|
|
|
|
|
|
|
stop() -> |
|
|
|
stop(default). |
|
|
|
stop(?defPoolId). |
|
|
|
|
|
|
|
%% @todo Confirm that we don't need to stop tracing, |
|
|
|
%% that just terminating the tracers is enough. The |
|
|
|