Skip to content

Commit 7b3a3fe

Browse files
committed
Add functionality to get roots of tracebacks
There are two options: 1) TBs = tr:tracebacks(..., #{format => tree}), tr:roots(TBs) % alternatively: tb:root(TB) on a single traceback 2) tr:tracebacks(..., #{format => root})
1 parent 32b6031 commit 7b3a3fe

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

src/tr.erl

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
filter/1, filter/2,
2323
traceback/1, traceback/2,
2424
tracebacks/1, tracebacks/2,
25+
roots/1, root/1,
2526
range/1, range/2,
2627
ranges/1, ranges/2,
2728
call_tree_stat/0, call_tree_stat/1,
@@ -162,14 +163,18 @@
162163
-type tb_output() :: shortest | longest | all.
163164
%% Which tracebacks to return if they overlap. Default: `shortest'.
164165

165-
-type tb_format() :: tree | list.
166-
%% Merge tracebacks into a `tree' or return a `list' (default) of them.
166+
-type tb_format() :: list | tree | root.
167+
%% Format in which tracebacks are returned.
168+
%%
169+
%% `list' (default) returns a list of tracebacks.
170+
%% `tree' merges them into a list of trees.
171+
%% `root' returns only the root of each tree.
167172

168173
-type tb_order() :: top_down | bottom_up.
169174
%% Order of calls in each returned traceback. Default: `top_down'.
170175

171-
-type tb_tree() :: [tr() | {tr(), tb_tree()}].
172-
%% Multiple tracebacks merged into a tree structure.
176+
-type tb_tree() :: tr() | {tr(), [tb_tree()]}.
177+
%% Multiple tracebacks with a common root merged into a tree structure.
173178

174179
-type tb_acc_tree() :: [{tr(), tb_acc_tree()}].
175180
-type tb_acc_list() :: [[tr()]].
@@ -379,12 +384,12 @@ traceback(PredF, Options) when is_function(PredF, 1) ->
379384
%% @doc Returns tracebacks of all matching traces from `tab()'.
380385
%%
381386
%% @see tracebacks/2
382-
-spec tracebacks(pred()) -> [[tr()]] | tb_tree().
387+
-spec tracebacks(pred()) -> [[tr()]] | [tb_tree()].
383388
tracebacks(PredF) ->
384389
tracebacks(PredF, #{}).
385390

386391
%% @doc Returns tracebacks of all matching traces from `t:tr_source()'.
387-
-spec tracebacks(pred(), tb_options()) -> [[tr()]] | tb_tree().
392+
-spec tracebacks(pred(), tb_options()) -> [[tr()]] | [tb_tree()].
388393
tracebacks(PredF, Options) when is_map(Options) ->
389394
Tab = maps:get(tab, Options, tab()),
390395
Output = maps:get(output, Options, shortest),
@@ -397,6 +402,16 @@ tracebacks(PredF, Options) when is_map(Options) ->
397402
foldl(fun(T, State) -> tb_step(PredF, T, State) end, InitialState, Tab),
398403
finalize_tracebacks(TBs, Output, Format, Options).
399404

405+
%% @doc Returns the root call of each `t:tb_tree()` from the provided list.
406+
-spec roots([tb_tree()]) -> [tr()].
407+
roots(Trees) ->
408+
lists:map(fun root/1, Trees).
409+
410+
%% @doc Returns the root call of the provided `t:tb_tree()`.
411+
-spec root(tb_tree()) -> tr().
412+
root(#tr{} = T) -> T;
413+
root({#tr{} = T, _}) -> T.
414+
400415
%% @doc Returns a list of traces from `tab()' between the first matched call and the corresponding return.
401416
%%
402417
%% Matching can be done with a predicate function, an index value or a `t:tr()' record.
@@ -827,6 +842,8 @@ finalize_tracebacks(TBs, all, list, Options) ->
827842
reorder_tb(lists:reverse(TBs), maps:get(order, Options, top_down));
828843
finalize_tracebacks(TBs, _, list, Options) ->
829844
reorder_tb(tree_to_list(TBs), maps:get(order, Options, top_down));
845+
finalize_tracebacks(TBs, _, root, _Options) ->
846+
lists:map(fun({T, _}) -> T end, lists:reverse(TBs));
830847
finalize_tracebacks(TBs, _, tree, _Options) ->
831848
finalize_tree(TBs).
832849

@@ -837,7 +854,8 @@ reorder_tb(TBs, bottom_up) -> TBs.
837854
-spec tree_to_list(tb_acc_tree()) -> [[tr()]].
838855
tree_to_list(Tree) ->
839856
lists:foldl(fun({K, []}, Res) -> [[K] | Res];
840-
({K, V}, Res) -> [[K | Rest] || Rest <- tree_to_list(V)] ++ Res end, [], Tree).
857+
({K, V}, Res) -> [[K | Rest] || Rest <- tree_to_list(V)] ++ Res
858+
end, [], Tree).
841859

842860
%% Reverse order and simplify leaf nodes
843861
-spec finalize_tree(tb_acc_tree()) -> tb_tree().

test/tr_SUITE.erl

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ groups() ->
5656
tb_all,
5757
tb_all_limit,
5858
tb_tree,
59-
tb_tree_longest]},
59+
tb_tree_longest,
60+
tb_roots]},
6061
{util, [do]},
6162
{call_stat, [simple_total,
6263
tree_total,
@@ -429,6 +430,24 @@ tb_tree_longest(_Config) ->
429430
{#tr{data = [2]}, [#tr{data = [1]},
430431
#tr{data = [0]}]}]}], TBs).
431432

433+
tb_roots(_Config) ->
434+
tr:trace([{?MODULE, fib, 1}]),
435+
?MODULE:fib(4),
436+
wait_for_traces(18),
437+
tr:stop_tracing(),
438+
439+
%% Option 1: call root/1 or root/2 on a tree
440+
TBs = tr:tracebacks(fun(#tr{event = return, data = N}) when N < 2 -> true end,
441+
#{format => tree}),
442+
Roots = tr:roots(TBs),
443+
ct:pal("Roots: ~p~n", [Roots]),
444+
?assertMatch([#tr{data = [4]}], Roots),
445+
?assertEqual(hd(Roots), tr:root(hd(TBs))),
446+
447+
%% Option 2: directly use the root format
448+
?assertEqual(Roots, tr:tracebacks(fun(#tr{event = return, data = N}) when N < 2 -> true end,
449+
#{format => root})).
450+
432451
simple_total(_Config) ->
433452
tr:trace([{?MODULE, factorial, 1}]),
434453
?MODULE:factorial(2),

0 commit comments

Comments
 (0)