diff options
-rw-r--r-- | lib/observer/doc/src/observer_ug.xml | 8 | ||||
-rw-r--r-- | lib/observer/src/observer_trace_wx.erl | 53 | ||||
-rw-r--r-- | lib/observer/src/observer_traceoptions_wx.erl | 48 |
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; |