3333 call_stat /1 , call_stat /2 ]).
3434
3535% % API - utilities
36- -export ([contains_data /2 ,
36+ -export ([match_data / 2 , contains_data / 2 , contains_val / 2 , match_val /2 ,
3737 do /1 ,
3838 lookup /1 ,
3939 next /1 , seq_next /1 , next /2 , prev /1 , seq_prev /1 , prev /2 ,
7878% % <li>`info' - For `send' events it is a `t:recipient()' tuple; otherwise `no_info'.</li>
7979% % </ul>
8080
81- -type pred () :: fun ((tr () ) -> boolean ()).
82- % % Predicate returning `true' for matching traces .
81+ -type pred (T ) :: fun ((T ) -> boolean ()).
82+ % % Predicate returning `true' for matching terms of type `T' .
8383% %
84- % % For other traces it can return a different value or fail.
84+ % % For other terms, it can return a different value or fail.
8585
8686-type selector (Data ) :: fun ((tr ()) -> Data ).
8787% % Trace selector function.
229229% % Function call tree with its accumulated time and number of repetitions.
230230
231231-type prev_next_options () :: #{tab => table (),
232- pred => pred ()}.
232+ pred => pred (tr () )}.
233233% % Options for obtaining previous and next traces.
234234% %
235235% % `tab' is the ETS table with traces (default: `trace').
@@ -356,12 +356,12 @@ select(F, DataVal) ->
356356 select (MS , DataVal , [], SelectRes ).
357357
358358% % @doc Returns matching traces from `tab()'.
359- -spec filter (pred ()) -> [tr ()].
359+ -spec filter (pred (tr () )) -> [tr ()].
360360filter (F ) ->
361361 filter (F , tab ()).
362362
363363% % @doc Returns matching traces from `t:tr_source()'.
364- -spec filter (pred (), tr_source ()) -> [tr ()].
364+ -spec filter (pred (tr () ), tr_source ()) -> [tr ()].
365365filter (F , Tab ) ->
366366 Traces = foldl (fun (Tr , State ) -> filter_trace (F , Tr , State ) end , [], Tab ),
367367 lists :reverse (Traces ).
@@ -372,15 +372,15 @@ filter(F, Tab) ->
372372% % Fails if no trace is matched.
373373% %
374374% % @see traceback/2
375- -spec traceback (pred () | index () | tr ()) -> [tr ()].
375+ -spec traceback (pred (tr () ) | index () | tr ()) -> [tr ()].
376376traceback (Pred ) ->
377377 traceback (Pred , #{}).
378378
379379% % @doc Returns traceback of the first matching trace from `t:tr_source()'.
380380% %
381381% % Fails if no trace is matched.
382382% % The options `limit' and `format' do not apply.
383- -spec traceback (pred () | index () | tr (), tb_options ()) -> [tr ()].
383+ -spec traceback (pred (tr () ) | index () | tr (), tb_options ()) -> [tr ()].
384384traceback (Index , Options ) when is_integer (Index ) ->
385385 traceback (fun (# tr {index = I }) -> Index =:= I end , Options );
386386traceback (T = # tr {}, Options ) ->
@@ -392,12 +392,12 @@ traceback(PredF, Options) when is_function(PredF, 1) ->
392392% % @doc Returns tracebacks of all matching traces from `tab()'.
393393% %
394394% % @see tracebacks/2
395- -spec tracebacks (pred ()) -> [[tr ()]] | [tb_tree ()].
395+ -spec tracebacks (pred (tr () )) -> [[tr ()]] | [tb_tree ()].
396396tracebacks (PredF ) ->
397397 tracebacks (PredF , #{}).
398398
399399% % @doc Returns tracebacks of all matching traces from `t:tr_source()'.
400- -spec tracebacks (pred (), tb_options ()) -> [[tr ()]] | [tb_tree ()].
400+ -spec tracebacks (pred (tr () ), tb_options ()) -> [[tr ()]] | [tb_tree ()].
401401tracebacks (PredF , Options ) when is_map (Options ) ->
402402 Tab = maps :get (tab , Options , tab ()),
403403 Output = maps :get (output , Options , shortest ),
@@ -426,14 +426,14 @@ root({#tr{} = T, _}) -> T.
426426% % Fails if no trace is matched.
427427% %
428428% % @see range/2
429- -spec range (pred () | index () | tr ()) -> [tr ()].
429+ -spec range (pred (tr () ) | index () | tr ()) -> [tr ()].
430430range (PredF ) ->
431431 range (PredF , #{}).
432432
433433% % @doc Returns a list of traces from `t:tr_source()' between the first matched call and the corresponding return.
434434% %
435435% % Fails if no call is matched.
436- -spec range (pred () | index () | tr (), range_options ()) -> [tr ()].
436+ -spec range (pred (tr () ) | index () | tr (), range_options ()) -> [tr ()].
437437range (Index , Options ) when is_integer (Index ) ->
438438 range (fun (# tr {index = I }) -> Index =:= I end , Options );
439439range (T = # tr {}, Options ) ->
@@ -444,12 +444,12 @@ range(PredF, Options) when is_function(PredF, 1) ->
444444% % @doc Returns lists of traces from `tab()' between matched calls and corresponding returns.
445445% %
446446% % @see ranges/2
447- -spec ranges (pred ()) -> [[tr ()]].
447+ -spec ranges (pred (tr () )) -> [[tr ()]].
448448ranges (PredF ) ->
449449 ranges (PredF , #{}).
450450
451451% % @doc Returns lists of traces from `t:tr_source()' between matched calls and corresponding returns.
452- -spec ranges (pred (), range_options ()) -> [[tr ()]].
452+ -spec ranges (pred (tr () ), range_options ()) -> [[tr ()]].
453453ranges (PredF , Options ) when is_map (Options ) ->
454454 Tab = maps :get (tab , Options , tab ()),
455455 Output = maps :get (output , Options , all ),
@@ -501,13 +501,49 @@ call_stat(KeyF, Tab) ->
501501
502502% % API - utilities
503503
504- % % @doc Looks for `DataVal' in `#tr.data'.
504+ % % @doc Returns traces with `#tr.data' containing any values matching the provided predicate.
505+ % %
506+ % % The matching values can occur in (possibly nested) tuples, maps or lists.
507+ -spec match_data (pred (term ()), tr ()) -> boolean ().
508+ match_data (Pred , # tr {data = Data }) when is_function (Pred , 1 ) ->
509+ match_val (Pred , Data ).
510+
511+ % % @doc Returns traces containing `DataVal' in `#tr.data'.
505512% %
506513% % `DataVal' can occur in (possibly nested) tuples, maps or lists.
507514-spec contains_data (term (), tr ()) -> boolean ().
508515contains_data (DataVal , # tr {data = Data }) ->
509516 contains_val (DataVal , Data ).
510517
518+ % % @doc Checks if `Val' contains any values matching the predicate `Pred'.
519+ % %
520+ % % The matching values can occur in (possibly nested) tuples, maps or lists.
521+ -spec match_val (pred (T ), T ) -> boolean ().
522+ match_val (Pred , Val ) ->
523+ case catch Pred (Val ) of
524+ true ->
525+ true ;
526+ _ ->
527+ case Val of
528+ [_ |_ ] ->
529+ lists :any (fun (El ) -> match_val (Pred , El ) end , Val );
530+ _ when is_tuple (Val ) ->
531+ match_val (Pred , tuple_to_list (Val ));
532+ #{} when map_size (Val ) > 0 ->
533+ match_val (Pred , maps :to_list (Val ));
534+ _ ->
535+ false
536+ end
537+ end .
538+
539+ % % @doc Checks if the given value `DataVal' is present within `Data'.
540+ % %
541+ % % Returns `true' if `DataVal' is found, otherwise returns `false'.
542+ % % `DataVal' can occur in (possibly nested) tuples, maps or lists.
543+ -spec contains_val (T , T ) -> boolean ().
544+ contains_val (DataVal , Data ) ->
545+ match_val (fun (Val ) -> Val =:= DataVal end , Data ).
546+
511547% % @doc Executes the function call for the provided `t:tr()' record or index.
512548-spec do (tr ()) -> term ().
513549do (Index ) when is_integer (Index ) ->
@@ -545,7 +581,7 @@ next(Index, Options) when is_integer(Index) ->
545581next (# tr {index = Index }, Options ) ->
546582 next (Index , Options ).
547583
548- -spec next (index (), pred (), table ()) -> tr ().
584+ -spec next (index (), pred (tr () ), table ()) -> tr ().
549585next (Index , Pred , Tab ) ->
550586 case ets :next_lookup (Tab , Index ) of
551587 {NextIndex , [NextT ]} ->
@@ -581,7 +617,7 @@ prev(Index, Options) when is_integer(Index) ->
581617prev (# tr {index = Index }, Options ) ->
582618 prev (Index , Options ).
583619
584- -spec prev (index (), pred (), table ()) -> tr ().
620+ -spec prev (index (), pred (tr () ), table ()) -> tr ().
585621prev (Index , Pred , Tab ) ->
586622 case ets :prev_lookup (Tab , Index ) of
587623 {PrevIndex , [PrevT ]} ->
@@ -701,9 +737,7 @@ create_tab(Tab) ->
701737select (_MS , _DataVal , DataAcc , '$end_of_table' ) ->
702738 lists :append (lists :reverse (DataAcc ));
703739select (MS , DataVal , DataAcc , {Matched , Cont }) ->
704- Filtered = lists :filter (fun (# tr {data = Data }) -> contains_val (DataVal , Data );
705- (T ) -> contains_val (DataVal , T )
706- end , Matched ),
740+ Filtered = lists :filter (fun (T ) -> contains_data (DataVal , T ) end , Matched ),
707741 SelectRes = ets :select (Cont ),
708742 select (MS , DataVal , [Filtered | DataAcc ], SelectRes ).
709743
@@ -713,12 +747,6 @@ filter_trace(F, T, State) ->
713747 _ -> State
714748 end .
715749
716- contains_val (DataVal , DataVal ) -> true ;
717- contains_val (DataVal , L ) when is_list (L ) -> lists :any (fun (El ) -> contains_val (DataVal , El ) end , L );
718- contains_val (DataVal , T ) when is_tuple (T ) -> contains_val (DataVal , tuple_to_list (T ));
719- contains_val (DataVal , M ) when is_map (M ) -> contains_val (DataVal , maps :to_list (M ));
720- contains_val (_ , _ ) -> false .
721-
722750index (Tab ) ->
723751 case ets :last (Tab ) of
724752 I when is_integer (I ) -> I + 1 ;
@@ -874,7 +902,7 @@ stop_skipping_messages(Pid, PidsTab) ->
874902
875903% % Filter tracebacks
876904
877- -spec tb_step (pred (), tr (), map ()) -> map ().
905+ -spec tb_step (pred (tr () ), tr (), map ()) -> map ().
878906tb_step (PredF , T = # tr {pid = Pid , event = Event },
879907 State = #{tbs := TBs , call_stacks := CallStacks , output := Output , format := Format ,
880908 count := Count , limit := Limit }) ->
0 commit comments