aboutsummaryrefslogtreecommitdiffstats
path: root/lib/observer
diff options
context:
space:
mode:
authorSiri Hansen <[email protected]>2016-04-21 17:28:20 +0200
committerSiri Hansen <[email protected]>2016-05-19 15:21:51 +0200
commitb41327bb7f006c1379301336b9b9d6c1e077f34e (patch)
tree0b71c1324ec6aea540a84cf7e1e618eed598b7e0 /lib/observer
parent96175f1ebfd109f1268898d68a735ec5a16e9933 (diff)
downloadotp-b41327bb7f006c1379301336b9b9d6c1e077f34e.tar.gz
otp-b41327bb7f006c1379301336b9b9d6c1e077f34e.tar.bz2
otp-b41327bb7f006c1379301336b9b9d6c1e077f34e.zip
[observer] Add functionality in GUI for trace pattern on messages
Diffstat (limited to 'lib/observer')
-rw-r--r--lib/observer/doc/src/observer_ug.xml8
-rw-r--r--lib/observer/src/observer_trace_wx.erl53
-rw-r--r--lib/observer/src/observer_traceoptions_wx.erl48
3 files changed, 85 insertions, 24 deletions
diff --git a/lib/observer/doc/src/observer_ug.xml b/lib/observer/doc/src/observer_ug.xml
index ca354df864..be5d249f37 100644
--- a/lib/observer/doc/src/observer_ug.xml
+++ b/lib/observer/doc/src/observer_ug.xml
@@ -254,7 +254,13 @@
<p>
If function calls are traced, trace patterns must be added by clicking button
<em>Add Trace Pattern</em>. Select a module, function(s), and a match specification.
- If no functions are selected, all functions in the module are traced.
+ If no functions are selected, all functions in the module are traced.</p>
+ <p>
+ Trace patterns can also be added for traced messages. This is
+ done in the same way as for traced function calls. Separate
+ trace patterns must be set for sent and received messages.
+ </p>
+ <p>
A few basic match specifications are provided in the tool, and
you can provide your own match specifications. The syntax of match
specifications is described in the <seealso
diff --git a/lib/observer/src/observer_trace_wx.erl b/lib/observer/src/observer_trace_wx.erl
index 9c0243e4a7..08710ca9a6 100644
--- a/lib/observer/src/observer_trace_wx.erl
+++ b/lib/observer/src/observer_trace_wx.erl
@@ -112,12 +112,24 @@ create_window(Notebook, ParentPid) ->
match_specs=default_matchspecs()}}.
default_matchspecs() ->
- Ms = [{"Return Trace", [{'_', [], [{return_trace}]}], "fun(_) -> return_trace() end"},
- {"Exception Trace", [{'_', [], [{exception_trace}]}], "fun(_) -> exception_trace() end"},
- {"Message Caller", [{'_', [], [{message,{caller}}]}], "fun(_) -> message(caller()) end"},
- {"Message Dump", [{'_', [], [{message,{process_dump}}]}], "fun(_) -> message(process_dump()) end"}],
+ [{Key,default_matchspecs(Key)} || Key <- [funcs,send,'receive']].
+default_matchspecs(Key) ->
+ Ms = get_default_matchspecs(Key),
[make_ms(Name,Term,FunStr) || {Name,Term,FunStr} <- Ms].
+get_default_matchspecs(funcs) ->
+ [{"Skeleton", [{'$1', [], [true]}], "fun(Args) -> true end"},
+ {"Return Trace", [{'_', [], [{return_trace}]}],
+ "fun(_) -> return_trace() end"},
+ {"Exception Trace", [{'_', [], [{exception_trace}]}], "fun(_) -> exception_trace() end"},
+ {"Message Caller", [{'_', [], [{message,{caller}}]}], "fun(_) -> message(caller()) end"},
+ {"Message Dump", [{'_', [], [{message,{process_dump}}]}], "fun(_) -> message(process_dump()) end"}];
+get_default_matchspecs(send) ->
+ [{"Skeleton", [{['$1','$2'], [], [true]}], "fun([Pid,Msg]) -> true end"}];
+get_default_matchspecs('receive') ->
+ [{"Skeleton", [{['$1','$2','$3'], [], [true]}], "fun([Node,Pid,Msg]) -> true end"}].
+
+
create_process_view(Parent) ->
Panel = wxPanel:new(Parent),
MainSz = wxBoxSizer:new(?wxHORIZONTAL),
@@ -192,7 +204,7 @@ create_menues(Parent) ->
#create_menu{id = ?SAVE_TRACEOPTS, text = "Save settings"}]},
{"Options",
[#create_menu{id = ?TRACE_OUTPUT, text = "Output"},
- #create_menu{id = ?TRACE_DEFMS, text = "Match Specifications"},
+ #create_menu{id = ?TRACE_DEFMS, text = "Default Match Specifications for Functions"},
#create_menu{id = ?TRACE_DEFPS, text = "Default Process Options"}]}
],
observer_wx:create_menus(Parent, Menus).
@@ -378,7 +390,7 @@ handle_event(#wx{id=?TRACE_DEFPS}, #state{panel=Panel, def_trace_opts=PO} = Stat
handle_event(#wx{id=?TRACE_DEFMS}, #state{panel=Panel, match_specs=Ms} = State) ->
try %% Return selected MS and sends new MS's to us
- observer_traceoptions_wx:select_matchspec(self(), Panel, Ms)
+ observer_traceoptions_wx:select_matchspec(self(), Panel, Ms, funcs)
catch _:_ ->
cancel
end,
@@ -391,10 +403,22 @@ handle_event(#wx{id=?EDIT_FUNCS_MS}, #state{panel=Panel, tpatterns=TPs,
try
[Module] = get_selected_items(Mview, lists:sort(dict:fetch_keys(TPs))),
Selected = get_selected_items(LCtrl, dict:fetch(Module, TPs)),
- Ms = observer_traceoptions_wx:select_matchspec(self(), Panel, Mss),
+ Key = case Module of
+ 'Events' ->
+ SelectedEvents = [Event || #tpattern{fa=Event} <- Selected],
+ E1 = hd(SelectedEvents),
+ case lists:all(fun(E) when E==E1 -> true; (_) -> false end,
+ SelectedEvents) of
+ true -> E1;
+ false -> throw({error,"Can not set match specs for multiple event types"})
+ end;
+ _ -> funcs
+ end,
+ Ms = observer_traceoptions_wx:select_matchspec(self(), Panel, Mss, Key),
Changed = [TP#tpattern{ms=Ms} || TP <- Selected],
{noreply, do_add_patterns({Module, Changed}, State)}
- catch _:_ ->
+ catch {error, Msg} ->
+ observer_wx:create_txt_dialog(Panel, Msg, "Error", ?wxICON_ERROR),
{noreply, State}
end;
@@ -564,10 +588,17 @@ update_modules_view(Mods, Module, LCtrl) ->
update_functions_view(Funcs, LCtrl) ->
wxListCtrl:deleteAllItems(LCtrl),
- wx:foldl(fun(#tpattern{fa=FA, ms=#match_spec{str=Ms}}, Row) ->
+ wx:foldl(fun(#tpattern{m=M, fa=FA, ms=#match_spec{str=Ms}}, Row) ->
_Item = wxListCtrl:insertItem(LCtrl, Row, ""),
?EVEN(Row) andalso wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN),
- wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({func,FA})),
+ FuncStr =
+ case M of
+ 'Events' ->
+ observer_lib:to_str(FA);
+ _ ->
+ observer_lib:to_str({func,FA})
+ end,
+ wxListCtrl:setItem(LCtrl, Row, 0, FuncStr),
wxListCtrl:setItem(LCtrl, Row, 1, Ms),
Row+1
end, 0, Funcs).
@@ -695,6 +726,8 @@ setup_tps([First|Rest], Prev) ->
setup_tps([], Prev) ->
[setup_tp(TP) || TP <- lists:reverse(Prev)].
+setup_tp(#tpattern{m='Events',fa=Event, ms=#match_spec{term=Ms}}) ->
+ ttb:tpe(Event,Ms);
setup_tp(#tpattern{m=M,fa={F,A}, ms=#match_spec{term=Ms}}) ->
ttb:tpl(M,F,A,Ms).
diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl
index 9ba9b72b6f..f9b4929ec4 100644
--- a/lib/observer/src/observer_traceoptions_wx.erl
+++ b/lib/observer/src/observer_traceoptions_wx.erl
@@ -23,7 +23,7 @@
-include("observer_defs.hrl").
-export([process_trace/2, trace_pattern/4, select_nodes/2,
- output/2, select_matchspec/3]).
+ output/2, select_matchspec/4]).
process_trace(Parent, Default) ->
Dialog = wxDialog:new(Parent, ?wxID_ANY, "Process Options",
@@ -100,10 +100,17 @@ process_trace(Parent, Default) ->
trace_pattern(ParentPid, Parent, Node, MatchSpecs) ->
try
- Module = module_selector(Parent, Node),
- MFAs = function_selector(Parent, Node, Module),
- MatchSpec = select_matchspec(ParentPid, Parent, MatchSpecs),
- {Module, [#tpattern{m=M,fa={F,A},ms=MatchSpec} || {M,F,A} <- MFAs]}
+ {Module,MFAs,MatchSpec} =
+ case module_selector(Parent, Node) of
+ {'$trace_event',Event} ->
+ MS = select_matchspec(ParentPid, Parent, MatchSpecs, Event),
+ {'Events',[{'Events',Event}],MS};
+ Mod ->
+ MFAs0 = function_selector(Parent, Node, Mod),
+ MS = select_matchspec(ParentPid, Parent, MatchSpecs, funcs),
+ {Mod,MFAs0,MS}
+ end,
+ {Module, [#tpattern{m=M,fa=FA,ms=MatchSpec} || {M,FA} <- MFAs]}
catch cancel -> cancel
end.
@@ -112,7 +119,7 @@ select_nodes(Parent, Nodes) ->
check_selector(Parent, Choices).
module_selector(Parent, Node) ->
- Dialog = wxDialog:new(Parent, ?wxID_ANY, "Select Module",
+ Dialog = wxDialog:new(Parent, ?wxID_ANY, "Select Module or Event",
[{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
{size, {400, 400}}]),
Panel = wxPanel:new(Dialog),
@@ -136,7 +143,9 @@ module_selector(Parent, Node) ->
wxWindow:setFocus(TxtCtrl),
%% init data
Modules = get_modules(Node),
- AllModules = [{atom_to_list(X), X} || X <- Modules],
+ Events = [{"Messages sent",{'$trace_event',send}},
+ {"Messages received",{'$trace_event','receive'}}],
+ AllModules = Events ++ [{atom_to_list(X), X} || X <- Modules],
filter_listbox_data("", AllModules, ListBox),
wxTextCtrl:connect(TxtCtrl, command_text_updated,
[{callback, fun(#wx{event=#wxCommand{cmdString=Input}}, _) ->
@@ -174,9 +183,9 @@ function_selector(Parent, Node, Module) ->
not(erl_internal:guard_bif(Name, Arity))]),
ParsedChoices = parse_function_names(Choices),
case check_selector(Parent, ParsedChoices) of
- [] -> [{Module, '_', '_'}];
+ [] -> [{Module, {'_', '_'}}];
FAs ->
- [{Module, F, A} || {F,A} <- FAs]
+ [{Module, {F, A}} || {F,A} <- FAs]
end.
check_selector(Parent, ParsedChoices) ->
@@ -268,7 +277,12 @@ get_checked(ListBox, Acc) ->
lists:reverse(Acc)
end.
-select_matchspec(Pid, Parent, MatchSpecs) ->
+select_matchspec(Pid, Parent, AllMatchSpecs, Key) ->
+ {MatchSpecs,RestMS} =
+ case lists:keytake(Key,1,AllMatchSpecs) of
+ {value,{Key,MSs0},Rest} -> {MSs0,Rest};
+ false -> {[],AllMatchSpecs}
+ end,
Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Match Specifications",
[{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
{size, {400, 400}}]),
@@ -314,7 +328,11 @@ select_matchspec(Pid, Parent, MatchSpecs) ->
Add = fun(_,_) ->
case edit_ms(TextCtrl, new, Parent) of
- Ms = #match_spec{} -> add_and_select(-1, Ms, ListBox);
+ Ms = #match_spec{} ->
+ add_and_select(-1, Ms, ListBox),
+ wxWindow:enable(OkButt),
+ wxWindow:enable(EditMsBtn),
+ wxWindow:enable(DelMsBtn);
Else -> Else
end
end,
@@ -324,7 +342,11 @@ select_matchspec(Pid, Parent, MatchSpecs) ->
true ->
#match_spec{name=Name} = wxListBox:getClientData(ListBox,SelId),
case edit_ms(TextCtrl, Name, Parent) of
- Ms = #match_spec{} -> add_and_select(SelId, Ms, ListBox);
+ Ms = #match_spec{} ->
+ add_and_select(SelId, Ms, ListBox),
+ wxWindow:enable(OkButt),
+ wxWindow:enable(EditMsBtn),
+ wxWindow:enable(DelMsBtn);
Else -> Else
end;
false ->
@@ -367,7 +389,7 @@ select_matchspec(Pid, Parent, MatchSpecs) ->
Count = wxListBox:getCount(ListBox),
MSs = [wxListBox:getClientData(ListBox, Id) ||
Id <- lists:seq(0, Count-1)],
- Pid ! {update_ms, MSs},
+ Pid ! {update_ms, [{Key,MSs}|RestMS]},
MS = lists:nth(SelId+1, MSs),
wxDialog:destroy(Dialog),
MS;